emission_nox.F90 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  1. !
  2. #define TRACEBACK write (gol,'("in ",a," (",a,i6,")")') 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: EMISSION_NOX
  14. !
  15. ! !DESCRIPTION: hold data and methods for NOx emissions.
  16. ! -----------------
  17. ! AR5 emissions
  18. ! -----------------
  19. ! For each month, arrays emis_nox_2d/3d have to be filled.
  20. ! It follows the following settins:
  21. ! - take emiss_ene/dom/ind/wst/agr/awb/slv/tra/shp/
  22. ! /air/forestfire/grassfire from AR5 data sets (NO GFED!!)
  23. ! - use natural emissions from MACC data sets
  24. ! (emiss_nat/soil/bio/oc)
  25. ! - vertical distribution is done via emission_vdist_by_sector
  26. ! (emission_data.F90)
  27. ! - lightning is done online (eminox_lightning)
  28. !\\
  29. !\\
  30. ! !INTERFACE:
  31. !
  32. MODULE EMISSION_NOX
  33. !
  34. ! !USES:
  35. !
  36. use GO, only : gol, goErr, goPr, goBug
  37. use tm5_distgrid, only : dgrid, get_distgrid, scatter, gather
  38. use dims, only : nregions, idate, dy, okdebug
  39. use global_types, only : emis_data, d3_data
  40. use emission_read, only : used_providers, has_emis
  41. IMPLICIT NONE
  42. PRIVATE
  43. !
  44. ! !PUBLIC MEMBER FUNCTIONS:
  45. !
  46. public :: Emission_NOx_Init
  47. public :: Emission_NOx_Done
  48. public :: Emission_NOx_Declare
  49. public :: Emission_NOx_bb_daily_cycle
  50. #ifndef without_convection
  51. public :: lightningNOX
  52. #endif
  53. public :: nox_emis_3d, nox_emis_3d_bb_app
  54. public :: eminox_lightning
  55. !
  56. ! !DATA MEMBERS:
  57. !
  58. character(len=*), parameter :: mname = 'emission_nox'
  59. type(d3_data), dimension(nregions), target :: nox_emis_3d, nox_emis_3d_bb, nox_emis_3d_bb_app
  60. type(d3_data), dimension(nregions), target :: eminox_lightning
  61. integer :: nox_2dsec, nox_3dsec
  62. real :: fscalelig ! scaling used in lightning NOX production to get 5.98 Tg for 2006
  63. !
  64. ! !REVISION HISTORY:
  65. ! 1 Oct 2010 - Achim Strunk - overhaul for AR5
  66. ! 1 Dec 2011 - Narcisa Banda - added EDGAR 4
  67. ! 27 Jun 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  68. !
  69. ! !REMARKS:
  70. ! NOx emissions are added directly in chemistry, instead of apart from it.
  71. !
  72. !EOP
  73. !------------------------------------------------------------------------
  74. CONTAINS
  75. !--------------------------------------------------------------------------
  76. ! TM5 !
  77. !--------------------------------------------------------------------------
  78. !BOP
  79. !
  80. ! !IROUTINE: EMISSION_NOX_INIT
  81. !
  82. ! !DESCRIPTION: allocate memory
  83. !\\
  84. !\\
  85. ! !INTERFACE:
  86. !
  87. subroutine Emission_NOx_Init( status )
  88. !
  89. ! !USES:
  90. !
  91. use dims, only : lm
  92. use emission_read, only : providers_def, numb_providers, ed42_nsect_nox
  93. use emission_data, only : LAR5BMB
  94. use emission_read, only : n_ar5_ant_sec, n_ar5_shp_sec, n_ar5_air_sec, n_ar5_bmb_sec
  95. use emission_read, only : ar5_cat_ant, ar5_cat_shp, ar5_cat_air, ar5_cat_bmb
  96. #ifndef without_convection
  97. use meteodata, only : set, gph_dat, temper_dat, cp_dat
  98. use emission_data, only : use_tiedkte
  99. #endif
  100. !
  101. ! !OUTPUT PARAMETERS:
  102. !
  103. integer, intent(out) :: status
  104. !
  105. ! !REVISION HISTORY:
  106. ! 1 Oct 2010 - Achim Strunk - adapted for AR5
  107. ! 27 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  108. ! 10 Jul 2013 - Ph. Le Sager - init lightning when no inventory is selected
  109. !
  110. !EOP
  111. !------------------------------------------------------------------------
  112. !BOC
  113. character(len=*), parameter :: rname = mname//'/Emission_NOx_Init'
  114. integer :: region, i1, j1, i2, j2
  115. integer :: imr, jmr, lmr, lsec, lprov
  116. ! --- begin --------------------------------------
  117. status = 0
  118. #ifndef without_convection
  119. ! Meteo used for LightningNOx
  120. do region=1,nregions
  121. call Set( temper_dat(region), status, used=.true. )
  122. call Set( gph_dat(region), status, used=.true. )
  123. call Set( cp_dat(region), status, used=.true. )
  124. enddo
  125. !
  126. ! Scaling parameter for LiNOx
  127. !
  128. ! Set to get 5.98 Tg N with 2006 EI met fields. This is resolution
  129. ! and met fields dependent. The factor has been estimated for:
  130. ! - @3x2 and 34 levels, Tiedkte : fscalelig=13.715
  131. ! - @1x1 and 34 levels, Tiedkte : fscalelig=17.051
  132. ! - @3x2 and 34 levels, EI conv : fscalelig=13.715*0.786
  133. ! - @1x1 and 34 levels, EI conv : fscalelig=17.051*0.649
  134. !
  135. if (use_tiedkte) then ! convective fluxes computed from T/rh/wind (Tiedkte)
  136. fscalelig=13.715 ! 3x2-34L, Tiedkte scheme
  137. if (dy == 1) fscalelig=17.051 ! 1x1-34L, Tiedkte scheme
  138. else
  139. fscalelig=10.78 ! 3x2-34L, EI convective fluxes
  140. if (dy == 1) fscalelig=11.066 ! 1x1-34L, EI convective fluxes
  141. endif
  142. #endif
  143. ! allocate information arrays (2d and 3d)
  144. do region=1,nregions
  145. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  146. lmr = lm(region)
  147. allocate(eminox_lightning(region)%d3(i1:i2,j1:j2,lmr) )
  148. eminox_lightning(region)%d3=0.
  149. enddo
  150. ! Check if any inventory is used
  151. if(.not. has_emis) return
  152. ! nb of sectors
  153. nox_2dsec = 0
  154. nox_3dsec = 0
  155. do lprov = 1, numb_providers
  156. if (count(used_providers.eq.providers_def(lprov)%name)/=0) then
  157. if (trim(providers_def(lprov)%name) .eq. 'AR5') then
  158. ! nb of available sectors in AR5 depends on category
  159. nox_2dsec = nox_2dsec + n_ar5_ant_sec*count('NO'.eq.ar5_cat_ant) + &
  160. n_ar5_shp_sec*count('NO'.eq.ar5_cat_shp)
  161. if (LAR5BMB) nox_2dsec = nox_2dsec + n_ar5_bmb_sec*count('NO'.eq.ar5_cat_bmb)
  162. nox_3dsec = nox_3dsec + n_ar5_air_sec*count('NO'.eq.ar5_cat_air)
  163. ! nox_2dsec = nox_2dsec + providers_def(lprov)%nsect2d
  164. ! nox_3dsec = nox_3dsec + count('NO'.eq.ar5_cat_air)
  165. elseif (trim(providers_def(lprov)%name) .eq. 'ED42') then
  166. nox_2dsec = nox_2dsec + ed42_nsect_nox
  167. ! no 3d sectors in EDGAR 4.2
  168. else
  169. nox_2dsec = nox_2dsec + providers_def(lprov)%nsect2d
  170. nox_3dsec = nox_3dsec + providers_def(lprov)%nsect3d
  171. endif
  172. endif
  173. enddo
  174. ! allocate information arrays (2d and 3d)
  175. do region=1,nregions
  176. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  177. lmr = lm(region)
  178. allocate( nox_emis_3d (region)%d3(i1:i2,j1:j2,lmr) )
  179. allocate( nox_emis_3d_bb (region)%d3(i1:i2,j1:j2,lmr) )
  180. allocate( nox_emis_3d_bb_app(region)%d3(i1:i2,j1:j2,lmr) )
  181. enddo
  182. status = 0
  183. END SUBROUTINE EMISSION_NOX_INIT
  184. !EOC
  185. !--------------------------------------------------------------------------
  186. ! TM5 !
  187. !--------------------------------------------------------------------------
  188. !BOP
  189. !
  190. ! !IROUTINE: EMISSION_NOX_DONE
  191. !
  192. ! !DESCRIPTION: Free memory
  193. !\\
  194. !\\
  195. ! !INTERFACE:
  196. !
  197. SUBROUTINE EMISSION_NOX_DONE( status )
  198. !
  199. ! !OUTPUT PARAMETERS:
  200. !
  201. integer, intent(out) :: status
  202. !
  203. ! !REVISION HISTORY:
  204. ! 1 Oct 2010 - Achim Strunk - adapted for AR5
  205. !
  206. !EOP
  207. !------------------------------------------------------------------------
  208. !BOC
  209. character(len=*), parameter :: rname = mname//'/Emission_NOx_Done'
  210. integer :: region, lsec
  211. ! --- begin ---------------------------------
  212. status = 0
  213. if(.not. has_emis) return
  214. do region = 1, nregions
  215. deallocate( nox_emis_3d (region)%d3 )
  216. deallocate( nox_emis_3d_bb (region)%d3 )
  217. deallocate( nox_emis_3d_bb_app(region)%d3 )
  218. deallocate( eminox_lightning (region)%d3 )
  219. end do
  220. status = 0
  221. END SUBROUTINE EMISSION_NOX_DONE
  222. !EOC
  223. !--------------------------------------------------------------------------
  224. ! TM5 !
  225. !--------------------------------------------------------------------------
  226. !BOP
  227. !
  228. ! !IROUTINE: EMISSION_NOX_DECLARE
  229. !
  230. ! !DESCRIPTION: Opens, reads and evaluates input files (per month).
  231. ! Provides emissions on 2d/3d-arrays which are then added
  232. ! in the chemistry routine (no *apply !).
  233. ! Vertically distribute the 2D dataset according to sector.
  234. !\\
  235. !\\
  236. ! !INTERFACE:
  237. !
  238. SUBROUTINE EMISSION_NOX_DECLARE( status )
  239. !
  240. ! !USES:
  241. !
  242. use toolbox, only : coarsen_emission
  243. use partools, only : isRoot, par_broadcast
  244. use dims, only : im, jm, lm, nlon360, nlat180, iglbsfc
  245. use dims, only : newsrun, idate, sec_month
  246. use chem_param, only : xmn, xmno2, xmno
  247. use emission_data, only : msg_emis, emission_vdist_by_sector, LAR5BMB
  248. ! ---------------- AR5 - EDGAR 4 - ETC. --------------------
  249. use emission_data, only : emis_input_year
  250. use emission_data, only : emis_input_dir_mac, emis_input_dir_ed4
  251. use emission_data, only : emis_input_dir_retro, emis_input_dir_gfed
  252. use emission_read, only : emission_ar5_regrid_aircraft
  253. use emission_read, only : emission_ar5_ReadSector, emission_macc_ReadSector
  254. use emission_read, only : emission_ed4_ReadSector, emission_gfed_ReadSector
  255. use emission_read, only : emission_retro_ReadSector
  256. use emission_read, only : sectors_def, numb_sectors
  257. use emission_read, only : ar5_dim_3ddata
  258. use emission_read, only : ed42_nox_sectors
  259. !
  260. ! !OUTPUT PARAMETERS:
  261. !
  262. integer, intent(out) :: status
  263. !
  264. ! !REVISION HISTORY:
  265. ! 1 Oct 2010 - Achim Strunk - adapted for AR5
  266. ! 1 Dec 2011 - Narcisa Banda - added EDGAR 4
  267. ! 27 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  268. ! 25 Feb 2014 - Jason Williams - separate array for BMB so that burning daily cycle can be applied
  269. !
  270. ! !REMARKS:
  271. ! (1) Because we do not use an apply method, the vertical distribution
  272. ! is done here. However this is a bug, since this is time dependent.
  273. ! Possible solution: do vert dist in chemistry like the BMB cycle,
  274. ! or in the more general BMB cycle routine.
  275. !
  276. !
  277. !EOP
  278. !------------------------------------------------------------------------
  279. !BOC
  280. character(len=*), parameter :: rname = mname//'/emission_nox_declare'
  281. integer :: region, hasData
  282. integer,parameter :: add_field=0
  283. integer,parameter :: amonth=2
  284. integer :: imr, jmr, lmr, lsec, i1, i2, j1, j2
  285. ! AR5 temporary arrays
  286. real, dimension(:,:,:), allocatable :: field3d !, field3d2
  287. type(d3_data), dimension(nregions), target :: emis3d, work(nregions), work3d(nregions)
  288. type(emis_data), dimension(nregions), target :: emis2d, wrk2D(nregions)
  289. ! defensive
  290. integer :: seccount2d, seccount3d
  291. ! --- begin -----------------------------------------
  292. status = 0
  293. if(.not. has_emis) return
  294. write(gol,'(" EMISS-INFO ------------- read NOx emissions -------------")'); call goPr
  295. ! reset emissions, allocate work array
  296. do region = 1, nregions
  297. nox_emis_3d(region)%d3 = 0.0 ; nox_emis_3d_bb(region)%d3 = 0.0
  298. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  299. lmr = lm(region)
  300. allocate( work3d(region)%d3 (i1:i2,j1:j2, ar5_dim_3ddata) ) ; work3d(region)%d3 = 0.0
  301. allocate( emis3d(region)%d3 (i1:i2,j1:j2, lmr ) ) ; emis3d(region)%d3 = 0.0
  302. allocate( emis2d(region)%surf(i1:i2,j1:j2) ) ; emis2d(region)%surf = 0.0
  303. end do
  304. ! global arrays for coarsening
  305. do region = 1, nregions
  306. if (isRoot)then
  307. allocate(work(region)%d3(im(region),jm(region),ar5_dim_3ddata))
  308. else
  309. allocate(work(region)%d3(1,1,1))
  310. end if
  311. enddo
  312. do region = 1, nregions
  313. wrk2D(region)%surf => work(region)%d3(:,:,1)
  314. end do
  315. ! --------------------------------
  316. ! do a loop over available sectors
  317. ! --------------------------------
  318. ! count 2d and 3d sectors
  319. seccount2d = 0
  320. seccount3d = 0
  321. ! always allocate here 3d data set (for 2d sectors it will be filled in first layer only)
  322. if (isRoot) then
  323. allocate( field3d( nlon360, nlat180, ar5_dim_3ddata ) ) ; field3d = 0.0
  324. else
  325. allocate( field3d( 1, 1, 1 ) )
  326. end if
  327. sec: do lsec = 1, numb_sectors
  328. if (count(used_providers.eq.sectors_def(lsec)%prov).eq.0) cycle
  329. if ((trim(sectors_def(lsec)%prov).eq.'ED42') .and. (count(ed42_nox_sectors.eq.sectors_def(lsec)%name) .eq. 0)) cycle
  330. if (associated(sectors_def(lsec)%species)) then ! AR5 check
  331. if (count('NO'.eq.sectors_def(lsec)%species).eq.0) cycle
  332. if ((trim(sectors_def(lsec)%catname) .eq. 'biomassburning').and.(.not.LAR5BMB)) cycle
  333. endif
  334. if( sectors_def(lsec)%f3d ) then
  335. seccount3d = seccount3d + 1
  336. else
  337. seccount2d = seccount2d + 1
  338. end if
  339. field3d = 0.0
  340. #ifdef with_online_nox
  341. ! skip natural nox in case it is calculated online
  342. if( trim(sectors_def(lsec)%namecat == 'natural') ) then
  343. write (gol,'(80("-"))'); call goPr
  344. write (gol,'("INFO: skipping sector `",a,"` due to `with_online_nox` ")') trim(sectors_def(lsec)%name); call goPr
  345. cycle
  346. end if
  347. #endif
  348. root: if (isRoot) then ! READ
  349. select case( trim(sectors_def(lsec)%prov) )
  350. case( 'AR5' )
  351. ! AR5 emissions included NO and NO2 aircraft emissions, but they are duplicates. So
  352. ! only take into account one of the sets. (in TM5: NO, skip NO2).
  353. ! Screen out solvent sector for NO,
  354. ! because it is zero in the RCPs
  355. ! and not present in the historical files.
  356. if (trim(sectors_def(lsec)%name) .ne. 'emiss_slv') then
  357. call emission_ar5_ReadSector( 'NO', emis_input_year, idate(2), lsec, field3d, status )
  358. IF_NOTOK_RETURN(status=1)
  359. ! convert from (kg NO)/s to (kg N)/s
  360. field3d = field3d * xmn / xmno
  361. endif
  362. case( 'MACC' )
  363. ! screen out sectors w/o NOx (bio, oc, nat)
  364. if ( (trim(sectors_def(lsec)%name) .eq. 'emiss_soil' ) .or. &
  365. (trim(sectors_def(lsec)%name) .eq. 'emiss_anthro') .or. &
  366. (trim(sectors_def(lsec)%name) .eq. 'emiss_air' ) ) then
  367. call emission_macc_ReadSector( emis_input_dir_mac, 'NO', emis_input_year, idate(2), &
  368. '0.5x0.5_kg.nc', sectors_def(lsec)%name, 'kg NO / s', field3d, status )
  369. IF_NOTOK_RETURN(status=1)
  370. ! convert from (kg NO)/s to (kg N)/s
  371. field3d = field3d * xmn / xmno
  372. endif
  373. case( 'ED41' )
  374. select case(trim(sectors_def(lsec)%name))
  375. case ('1A3a','1A3b_c_e','1A3d_SHIP','1A3d1')
  376. ! anthropogenic sources
  377. call emission_ed4_ReadSector( emis_input_dir_ed4, 'NOx','nox', emis_input_year, idate(2), &
  378. lsec, trim(sectors_def(lsec)%prov), 'kg / s', field3d, status )
  379. IF_NOTOK_RETURN(status=1;deallocate(field3d))
  380. end select
  381. case( 'ED42' )
  382. ! biomass burning (GFED/RETRO/AR5BMB) and transport (ED41) are excluded through ED42_NOX_SECTORS definition
  383. call emission_ed4_ReadSector( emis_input_dir_ed4, 'NOx', 'nox', emis_input_year, idate(2), &
  384. lsec, trim(sectors_def(lsec)%prov), 'kg / s', field3d, status )
  385. IF_NOTOK_RETURN(status=1)
  386. case('GFEDv3')
  387. call emission_gfed_ReadSector( emis_input_dir_gfed, 'nox', emis_input_year, idate(2), &
  388. sectors_def(lsec)%name, 'kg NO2 / s', field3d(:,:,1), status )
  389. IF_NOTOK_RETURN(status=1)
  390. ! convert from (kg NO2)/s to (kg N)/s
  391. field3d = field3d * xmn / xmno2
  392. case('RETRO')
  393. call emission_retro_ReadSector( emis_input_dir_retro, 'NOX', emis_input_year, idate(2), &
  394. sectors_def(lsec)%name, 'kg / s', field3d(:,:,1), status )
  395. IF_NOTOK_RETURN(status=1)
  396. ! in the file kg(species)/m2/s - what does this mean?? by the numbers I assume kg NO2
  397. ! convert from (kg NO2)/s to (kg N)/s
  398. field3d = field3d * xmn / xmno2
  399. case('MEGAN')
  400. !
  401. ! use soil emissions from MACC
  402. !
  403. case('DUMMY')
  404. case default
  405. write(gol,*) "Error in building list of providers USED_PROVIDERS"; call goErr
  406. status=1; TRACEBACK; return
  407. end select
  408. ! verbose
  409. if(sum(field3d) < 100.*TINY(1.0) ) then
  410. if (okdebug) then
  411. write(gol,'("EMISS-INFO - no NOx emissions found for ",a," ",a," for month ",i2 )') &
  412. trim(sectors_def(lsec)%prov), sectors_def(lsec)%name, idate(2) ; call goPr
  413. endif
  414. hasData=0
  415. else
  416. if (okdebug) then
  417. write(gol,'("EMISS-INFO - found NOx emissions for ",a," ",a," for month ",i2 )') &
  418. trim(sectors_def(lsec)%prov), sectors_def(lsec)%name, idate(2) ; call goPr
  419. endif
  420. ! scale from kg/s to kg/month
  421. field3d = field3d * sec_month ! kg / month
  422. hasData=1
  423. endif
  424. end if root
  425. call Par_broadcast(hasData, status)
  426. IF_NOTOK_RETURN(status=1)
  427. if (hasData == 0) cycle sec
  428. ! reset temporary arrays
  429. do region = 1, nregions
  430. emis3d(region)%d3 = 0.0
  431. work3d(region)%d3 = 0.0
  432. emis2d(region)%surf = 0.0
  433. end do
  434. ! distinguish 2d/3d sectors
  435. if( sectors_def(lsec)%f3d ) then
  436. ! ---------------------------
  437. ! 3d data (AIRCRAFT)
  438. ! ---------------------------
  439. if (isRoot) then
  440. ! write some numbers
  441. call msg_emis( amonth, trim(sectors_def(lsec)%prov), sectors_def(lsec)%name, 'NOx', xmn, sum(field3d) )
  442. ! distribute to work arrays in regions
  443. call Coarsen_Emission( 'NOX '//trim(sectors_def(lsec)%name), nlon360, nlat180, ar5_dim_3ddata, &
  444. field3d, work, add_field, status )
  445. IF_NOTOK_RETURN(status=1)
  446. end if
  447. ! scatter, sum up on target array
  448. do region = 1, nregions
  449. call scatter(dgrid(region), work3d(region)%d3, work(region)%d3, 0, status)
  450. IF_NOTOK_RETURN( status=1 )
  451. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, J_STRT=j1)
  452. ! aircraft data: regrid vertically to model layers
  453. call emission_ar5_regrid_aircraft( region, i1, j1, work3d(region)%d3, emis3d(region)%d3, status )
  454. IF_NOTOK_RETURN( status=1 )
  455. nox_emis_3d(region)%d3 = nox_emis_3d(region)%d3 + emis3d(region)%d3
  456. end do
  457. else ! ar5_sector is 2d
  458. ! ---------------------------
  459. ! 2d data (Anthropogenic, Ships, Biomassburning, ...)
  460. ! ---------------------------
  461. if (isRoot) then ! print total & regrid
  462. call msg_emis( amonth, trim(sectors_def(lsec)%prov), sectors_def(lsec)%name, 'NOx', xmn, sum(field3d(:,:,1)) )
  463. call coarsen_emission( 'NOx '//sectors_def(lsec)%name, nlon360, nlat180, field3d(:,:,1), &
  464. wrk2D, add_field, status )
  465. IF_NOTOK_RETURN(status=1)
  466. end if
  467. ! scatter, distribute vertically according to sector, and sum up on target array
  468. do region = 1, nregions
  469. call scatter(dgrid(region), emis2d(region)%surf, work(region)%d3(:,:,1), 0, status)
  470. IF_NOTOK_RETURN(status=1)
  471. call emission_vdist_by_sector( sectors_def(lsec)%vdisttype, 'NOx', region, emis2d(region), emis3d(region), status )
  472. IF_NOTOK_RETURN(status=1)
  473. if ( trim(sectors_def(lsec)%catname) .eq. 'biomassburning') then
  474. nox_emis_3d_bb(region)%d3 = nox_emis_3d_bb(region)%d3 + emis3d(region)%d3
  475. else
  476. nox_emis_3d(region)%d3 = nox_emis_3d(region)%d3 + emis3d(region)%d3
  477. endif
  478. end do
  479. end if ! sectors_def
  480. end do sec ! sectors
  481. deallocate( field3d )
  482. do region = 1, nregions
  483. if (associated(wrk2D(region)%surf)) nullify(wrk2D(region)%surf)
  484. deallocate( emis3d(region)%d3, emis2d(region)%surf )
  485. deallocate( work(region)%d3 )
  486. deallocate( work3d(region)%d3 )
  487. end do
  488. ! check sectors found
  489. if( seccount2d /= nox_2dsec ) then
  490. write(gol,'(80("-"))') ; call goPr
  491. write(gol,'("ERROR: 2d sectors do not equal total number:",i4," /= ",i4," !")') seccount2d, nox_2dsec ; call goErr
  492. write(gol,'(80("-"))') ; call goPr
  493. status=1; return
  494. end if
  495. if( seccount3d /= nox_3dsec ) then
  496. write(gol,'(80("-"))') ; call goPr
  497. write(gol,'("ERROR: 3d sectors do not equal total number:",i4," /= ",i4," !")') seccount3d, nox_3dsec ; call goErr
  498. write(gol,'(80("-"))') ; call goPr
  499. status=1; return
  500. end if
  501. ! ok
  502. status = 0
  503. END SUBROUTINE EMISSION_NOX_DECLARE
  504. !EOC
  505. !--------------------------------------------------------------------------
  506. ! TM5 !
  507. !--------------------------------------------------------------------------
  508. !BOP
  509. !
  510. ! !IROUTINE: EMISSION_NOX_BB_DAILY_CYCLE
  511. !
  512. ! !DESCRIPTION: Impose daily burning cycle to BMB NOx emissions for current
  513. ! time step.
  514. !\\
  515. !\\
  516. ! !INTERFACE:
  517. !
  518. SUBROUTINE EMISSION_NOX_BB_DAILY_CYCLE( status )
  519. !
  520. ! !USES:
  521. !
  522. use dims, only : itaur, nsrce, tref, lm
  523. use dims, only : dx, xref, xbeg, yref, ybeg, ndyn_max
  524. use partools, only : myid
  525. use emission_data, only : emis_bb_trop_cycle, bb_cycle
  526. use datetime, only : tau2date
  527. !
  528. ! !OUTPUT PARAMETERS:
  529. !
  530. integer, intent(out) :: status
  531. !
  532. ! !REVISION HISTORY:
  533. ! 23 Jan 2014 - Jason Williams - V0
  534. !
  535. !EOP
  536. !------------------------------------------------------------------------
  537. !BOC
  538. character(len=*), parameter :: rname = mname//'/emission_nox_bb_daily_cycle'
  539. integer :: i,j,l,region, lmr, itim, ntim
  540. integer :: i1, i2, j1, j2, ipos, sec_in_day
  541. integer, dimension(6) :: idater
  542. real :: dtime, dtime2, xlon, xlat
  543. !
  544. REG: do region = 1, nregions
  545. !
  546. ! Re-initialize the bb NOx array
  547. !
  548. nox_emis_3d_bb_app(region)%d3 = 0.0
  549. call tau2date(itaur(region),idater)
  550. dtime = float(nsrce)/(2*tref(region)) ! emissions are added in two steps...XYZECCEZYX.
  551. dtime2 = float(ndyn_max)/(2*tref(region))
  552. ntim = 86400/nint(dtime2) ! number of timesteps in 24 hours.
  553. sec_in_day = idater(4)*3600 + idater(5)*60 + idater(6) ! elapsed seconds this day
  554. itim = sec_in_day/nint(dtime2)+1 ! time interval
  555. if(okdebug) then
  556. write(gol,*)'emission_nox_bb_daily_cycle in region ',region,' at date: ',idater, ' with time step:', dtime,' on ',myid
  557. call goPr
  558. end if
  559. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  560. lmr = lm(region)
  561. if( emis_bb_trop_cycle) then
  562. do l=1,lmr
  563. do j=j1,j2
  564. do i=i1,i2
  565. xlat = ybeg(region) + (j-0.5)*dy/yref(region)
  566. if (xlat .gt. -20 .and. xlat .lt. 20) then
  567. ! apply emission cycle in tropics only
  568. ! itim = 1 and lon = -180 --->position 1
  569. ! itim = ntim ant lon = -180 --->position ntim, etc.
  570. ! itim = 1 and lon = 0 ---->position ntim/2
  571. xlon = xbeg(region) + (i-0.5)*dx/xref(region)
  572. ipos = 1 + mod(int((xlon+180.)*ntim/360.) + (itim-1),ntim) !position in array depending on time and lon.
  573. nox_emis_3d_bb_app(region)%d3(i,j,l) = nox_emis_3d_bb(region)%d3(i,j,l)*bb_cycle(region)%scalef(ipos)
  574. else
  575. nox_emis_3d_bb_app(region)%d3(i,j,l) = nox_emis_3d_bb(region)%d3(i,j,l)
  576. endif
  577. enddo
  578. enddo
  579. enddo
  580. else
  581. nox_emis_3d_bb_app(region)%d3 = nox_emis_3d_bb(region)%d3
  582. endif
  583. end do REG
  584. if(okdebug) then
  585. write(gol,*) 'end of emission_nox_bb_daily_cycle'; call goPr
  586. end if
  587. status=0
  588. END SUBROUTINE EMISSION_NOX_BB_DAILY_CYCLE
  589. #ifndef without_convection
  590. !--------------------------------------------------------------------------
  591. ! TM5 !
  592. !--------------------------------------------------------------------------
  593. !BOP
  594. !
  595. ! !IROUTINE: lightningNOx
  596. !
  597. ! !DESCRIPTION: Calculates NOx emissions from lightning as input for
  598. ! photochemistry module. NOx lightning is calculated using a linear
  599. ! relationship between lightning flashes and convective precipitation
  600. !
  601. ! * total annual production is approximately 5 Tg(N)/yr
  602. ! * marine lightning is ten times less active
  603. ! * fraction of cloud-to-ground over total flashes is determined by
  604. ! 4th order polynomial fit of the cold cloud thickness (Price and
  605. ! Rind, GRL 1993).
  606. ! * NOx production per IC and CG flash is according to Price et al,
  607. ! JGR, 1997.
  608. ! * vertical NOx profile is an approximation of the 'outflow' profile
  609. ! adopted from Pickering et al., JGR 1998.
  610. !
  611. ! Calculate distribution of lightning using cloudtop heights
  612. ! of deep convection, cloud cover and convective precipitation
  613. !
  614. ! Reference: E. Meijer, KNMI.
  615. ! Physics and Chemistry of the earth, Manuscript ST6.03-4
  616. !\\
  617. !\\
  618. ! !INTERFACE:
  619. !
  620. SUBROUTINE LIGHTNINGNOX(region, I1, J1, emilig, status)
  621. !
  622. ! !USES:
  623. !
  624. USE dims, only : im,jm,lm,ybeg,yref
  625. use Dims, only : CheckShape
  626. USE Binas, only : Avog
  627. use chem_param, only : xmn
  628. use partools, only : isRoot, par_reduce
  629. USE toolbox, only : ltropo, lvlpress
  630. USE meteodata, only : m_dat, phlb_dat
  631. use meteodata, only : temper_dat, gph_dat, cp_dat
  632. USE global_data, only : region_dat, conv_dat
  633. USE emission_data, only : plandr
  634. !
  635. ! !INPUT PARAMETERS:
  636. !
  637. integer, intent(in) :: region, i1, j1
  638. !
  639. ! !OUTPUT PARAMETERS:
  640. !
  641. real, intent(out) :: emilig(i1:,j1:,:) ! lighting emissions (kg N/s)
  642. integer, intent(out) :: status
  643. !
  644. ! !REVISION HISTORY:
  645. ! ? ??? 2001 - Ernst Meijer - Set up
  646. ! ? ??? 2002 - Olivie, van Weele - Revisions
  647. ! ? Jul 2002 - Frank Dentener - adapted for TM5
  648. ! ? Jan 2003 - Maarten krol - adapted for NEW TM5
  649. ! 1 Oct 2010 - Achim Strunk - protex
  650. ! 27 Jun 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  651. ! 21 Aug 2013 - Ph. Le Sager - update fscalelig for 1x1
  652. !
  653. ! !REMARKS:
  654. !
  655. !EOP
  656. !------------------------------------------------------------------------
  657. !BOC
  658. character(len=*), parameter :: rname = mname//'/lightningNOx'
  659. real, dimension(:,:,:), pointer :: phlb ! pressure (Pa) (1:lm+1)
  660. real, dimension(:,:,:), pointer :: m ! air mass (kg)
  661. real, dimension(:,:,:), pointer :: gph ! height (incl. oro)
  662. integer,dimension(:,:), pointer :: lutop ! cloud_top
  663. integer,dimension(:,:), pointer :: lubottom ! cloud base
  664. real,dimension(:), pointer :: dxyp ! area (m)
  665. real,dimension(:,:,:), pointer :: t ! temperature (K)
  666. real,dimension(:,:,:), pointer :: cp ! convective precipitation (mm/day)
  667. real,dimension(:,:), pointer :: plandregion ! landfraction (0-1)
  668. !
  669. real,dimension(:),allocatable :: gphx,tx
  670. real :: top ! cloudtop (km)
  671. real :: cldd ! cold cloud extension (km) (0 deg - tep)
  672. integer :: ibase ! base of cloud layer
  673. integer :: itropo ! tropopuase layer
  674. integer :: itop ! top of cloud layer
  675. integer :: itmin15 ! layer with the t=-15 isotherm
  676. integer :: itmin24 ! layer with the t=-24 isotherm
  677. integer :: it0 ! layer with the t= 0 isotherm
  678. !
  679. real :: cpc ! convective precipitation => (m s^-1)
  680. !
  681. real :: fl ! flash rate (1/s)
  682. real :: cg ! cloud-to-ground flashe rate (1/s)
  683. real :: ic ! intra-cloud flash rate (1/s)
  684. real :: pnocg,pnoic ! molecules NO produced per CG, IC flash
  685. ! DIAGNOSTIC variables
  686. real :: flashglob ! global flash frequency (1/s)
  687. real :: flashtrop ! tropical flash frequency (1/s)
  688. real :: ic_flashglob ! global flash frequency (1/s)
  689. real :: ic_flashtrop ! tropical flash frequency (1/s)
  690. real :: noxltrop ! tropical NOxL (kg/s)
  691. !
  692. logical :: cld ! flag for initialisation and cloud
  693. !
  694. integer :: i,j,l,ll,nlay,i2,j2
  695. real :: dsum
  696. real :: airmass
  697. integer :: level_pblh
  698. real :: xlat, dlat, tot_emilig
  699. logical :: lightning_output = .false. ! switch for diagnostic output
  700. logical :: lightning_output_2 = .false.
  701. ! for buggy MPI (see comment in budget_global.F90 for details)
  702. real :: flashglob_all, ic_flashglob_all, flashtrop_all, ic_flashtrop_all, noxltrop_all, tot_emilig_all
  703. ! --- begin --------------------------------
  704. CALL GET_DISTGRID( dgrid(region), I_STOP=i2, J_STOP=j2 )
  705. call CheckShape( (/i2-i1+1,j2-j1+1,lm(region)/), shape(emilig), status )
  706. IF_NOTOK_RETURN(status=1)
  707. m => m_dat (region)%data
  708. phlb => phlb_dat (region)%data
  709. cp => cp_dat (region)%data
  710. plandregion => plandr (region)%surf
  711. dxyp => region_dat (region)%dxyp
  712. lubottom => conv_dat (region)%cloud_base
  713. lutop => conv_dat (region)%cloud_top
  714. t => temper_dat (region)%data
  715. gph => gph_dat (region)%data
  716. !
  717. !
  718. allocate(gphx(0:lm(region))) ! note now from 0-->lm
  719. allocate(tx(lm(region)))
  720. !
  721. ! FD region coordinates are needed for determining statistics in tropics
  722. ! (-30 N,30N) and for excluding polar lightning (75N, 75 S) the emissions
  723. ! in parent regions containing a zoom are only set to zero after budget
  724. ! calculations using zoomed
  725. !
  726. ! Initialising statistics
  727. !
  728. flashglob = 0.
  729. flashtrop = 0.
  730. ic_flashglob = 0.
  731. ic_flashtrop = 0.
  732. noxltrop = 0.
  733. !
  734. ! initialising lightning emission
  735. !
  736. emilig(:,:,:) = 0. ! (im,jm,lm)
  737. dlat = dy/yref(region)
  738. !
  739. do j=j1,j2
  740. xlat = float(ybeg(region)) + j*dlat ! southern edge of gridbox
  741. if(xlat < -75.0 .or. (xlat+dlat) > 75.0) cycle ! exclude poles....
  742. do i=i1,i2
  743. !
  744. fl = 0.
  745. cldd = 0.
  746. cg = 0.
  747. ic = 0.
  748. !
  749. ibase = 0
  750. itop = 0
  751. itmin24 = 0
  752. itmin15 = 0
  753. it0 = 0
  754. !
  755. cld = .false.
  756. !
  757. cpc = cp(i,j,1)
  758. !old data cpc = cp(i,j,1) / 1000./86400. ! mm/day => m/s
  759. !
  760. if (cpc.gt.0.) then
  761. tx(:)=t(i,j,:)
  762. gphx(0:lm(region))=gph(i,j,1:lm(region)+1) !note the bounds
  763. ibase = lubottom(i,j)
  764. itop = lutop(i,j)
  765. itropo = ltropo(region,tx,gphx,lm(region))
  766. if (ibase.ne.0.and.itop.ne.0) then
  767. do l = itop, ibase, -1
  768. if (tx(l).le.249.15) itmin24=l
  769. if (tx(l).le.258.15) itmin15=l
  770. if (tx(l).le.273.15) it0 = l
  771. enddo !l
  772. top = (gphx(itop)+gphx(itop-1))/2000. ! cloud top (km)
  773. if (itmin24.ne.0.and.top.gt.5) then
  774. cld = .true. ! IF CLOUD REGIONS, IT IS A DEEP CLOUD
  775. if (itop.gt.itropo) itop = itropo
  776. if (it0 .gt.itropo) it0 = itropo
  777. endif ! itmin24
  778. endif !ibase ne 0
  779. !
  780. if (cld) then
  781. !fd top = (gphx(itop)+gphx(itop-1))/2000. ! cloud top (km)
  782. cldd= top - (gphx(it0)+gphx(it0-1))/2000. ! cold top (km)
  783. fl = fscalelig *4.e6 * cpc * dxyp(j)*1.e-12
  784. fl = (0.9*plandregion(i,j) + 0.1) * fl
  785. if (cldd.ge.5.5) then
  786. cg = fl / (.021*cldd**4-.648*cldd**3+7.493*cldd**2-36.54*cldd+64.09)
  787. ic = fl - cg
  788. else
  789. ! changed from [0.;fl] to [fl; fl-cg] (TvN, PLS, 22-04-2013)
  790. ! this increases the LiNOx by ~8.2 TgN/yr
  791. cg = fl
  792. ic = fl-cg
  793. endif !cldd
  794. ! changed pnocg factor from 6.7e9 to 6.7e8 (TvN, PLS, 22-04-2013)
  795. ! this is from more recent estimate from observations [Ott et al., 2010]
  796. pnocg = 1e17*6.7e8*cg *xmn*1e-3/Avog
  797. pnoic = 1e17*6.7e8*ic *xmn*1e-3/Avog
  798. ! DISTRIBUTION of LNOx over the COLUMN
  799. !
  800. ! assume all IC-LNOx and 70% of CG-LNOx betweem t=-15 and cloudtop;
  801. ! assume 10% of CG-LNOx between EARTH SURFACE and t=-15
  802. ! assume 20% of CG-LNOx in BOUNDARY LAYER
  803. !
  804. ! To avoid dependency on the vertical resolution :
  805. ! - surface emission in lowest layers : boundary layer height;
  806. ! - LNOx within one of these three regions is distributed proportional to the mass of each layer.
  807. ! distributing all IC LNOx and 70% of CG LNOx BETWEEN t=-15 and CLOUDTOP
  808. dsum = 0.7*pnocg+pnoic
  809. ! determining nlay
  810. itop = min(itop,itropo-1)
  811. nlay = itop - itmin15
  812. if (nlay.le.0) then
  813. itmin15=itop-1
  814. nlay = 1
  815. if (lightning_output_2) write(6,*) 'WARNING noxlight_cvp: itmin15>=itropo: ',i,j,itropo,itmin15
  816. endif !nlay le 0
  817. ! distributing according to airmass
  818. airmass = 0.
  819. do l=itmin15+1,itop
  820. airmass = airmass + m(i,j,l)
  821. enddo
  822. do l=itmin15+1,itop
  823. emilig(i,j,l) = dsum*m(i,j,l)/airmass
  824. enddo
  825. ! distributing 10% of CG LNOx between EARTH SURFACE and t=-15
  826. dsum = 0.1 * pnocg
  827. ! distributing according to air mass
  828. airmass = 0.
  829. do l=1,itmin15
  830. airmass = airmass + m(i,j,l)
  831. enddo
  832. do l=1,itmin15
  833. emilig(i,j,l) = emilig(i,j,l) + dsum*m(i,j,l)/airmass
  834. enddo
  835. ! distributing 20% of CG LNOx between ground pressure and 0.8*ground pressure
  836. dsum = 0.2 * pnocg
  837. level_pblh = lvlpress(region,0.8*phlb(i,j,1),phlb(i,j,1))
  838. ! distributing according to airmass
  839. airmass = 0.
  840. do l=1,level_pblh
  841. airmass = airmass + m(i,j,l)
  842. enddo
  843. do l=1,level_pblh
  844. emilig(i,j,l) = emilig(i,j,l) + dsum*m(i,j,l)/airmass
  845. enddo
  846. if (lightning_output) then ! CALCULATE GLOBAL/TROPICAL flash, NOxL rates
  847. flashglob = flashglob + fl
  848. ic_flashglob = ic_flashglob + ic
  849. select case(nint(xlat)) ! xlat is the southern edge of box j....
  850. case(-30:29)
  851. flashtrop = flashtrop + fl
  852. ic_flashtrop = ic_flashtrop + ic
  853. do l = 1, lm(region)
  854. noxltrop = noxltrop + emilig(i,j,l)
  855. enddo
  856. case default
  857. end select
  858. endif ! lightning_output
  859. endif !cld = .true.
  860. endif !cpc.gt.0.
  861. enddo !i
  862. enddo !j
  863. if (lightning_output) then
  864. call par_reduce( flashglob , 'sum', flashglob_all , status )
  865. call par_reduce( ic_flashglob , 'sum', ic_flashglob_all , status )
  866. call par_reduce( flashtrop , 'sum', flashtrop_all , status )
  867. call par_reduce( ic_flashtrop , 'sum', ic_flashtrop_all , status )
  868. call par_reduce( noxltrop , 'sum', noxltrop_all , status )
  869. tot_emilig = sum(emilig)
  870. call par_reduce( tot_emilig, 'sum', tot_emilig_all, status )
  871. if (isRoot) then
  872. write(gol,*) 'EMISS-INFO - global lightning frequency = ',flashglob_all,' s-1' ; call goPr
  873. write(gol,*) 'EMISS-INFO - ic global lightning frequency = ',ic_flashglob_all,' s-1' ; call goPr
  874. write(gol,*) 'EMISS-INFO - tropical lightning frequency = ',flashtrop_all,' s-1' ; call goPr
  875. write(gol,*) 'EMISS-INFO - ic tropical lightning frequency= ',ic_flashtrop_all,' s-1' ; call goPr
  876. write(gol,*) 'EMISS-INFO - global lightning emission : ',tot_emilig_all*1.e-9*365.*86400.,' Tg[N]/a' ; call goPr
  877. write(gol,*) 'EMISS-INFO - tropical lightning emission : ',noxltrop_all*1.e-9*365.*86400.,' Tg[N]/a' ; call goPr
  878. end if
  879. endif
  880. nullify(m)
  881. nullify(phlb)
  882. nullify(gph)
  883. nullify(cp)
  884. nullify(plandregion)
  885. nullify(lubottom)
  886. nullify(lutop)
  887. nullify(dxyp)
  888. nullify(t)
  889. deallocate(gphx)
  890. deallocate(tx)
  891. status=0
  892. END SUBROUTINE LIGHTNINGNOX
  893. #endif
  894. END MODULE EMISSION_NOX