emission_isop.F90 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  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: EMISSION_ISOP
  14. !
  15. ! !DESCRIPTION: data and methods for Isoprene emissions.
  16. !\\
  17. !\\
  18. ! !INTERFACE:
  19. !
  20. MODULE EMISSION_ISOP
  21. !
  22. ! !USES:
  23. !
  24. use GO, only : gol, goPr, goErr, goBug
  25. use tm5_distgrid, only : dgrid, get_distgrid, scatter, gather
  26. use partools, only : isRoot, par_broadcast
  27. use dims, only : nregions, idate, okdebug
  28. use global_types, only : emis_data, d3_data
  29. use global_types, only : isop_data
  30. use emission_read, only : used_providers_isop, has_isop_emis
  31. IMPLICIT NONE
  32. PRIVATE
  33. !
  34. ! !PUBLIC MEMBER FUNCTIONS:
  35. !
  36. public :: Emission_isop_Init
  37. public :: Emission_isop_Done
  38. public :: emission_isop_Declare
  39. public :: Emission_isop_Apply
  40. !
  41. ! !PRIVATE DATA MEMBERS:
  42. !
  43. character(len=*), parameter :: mname = 'emission_isop'
  44. !isoprene emission distribution function
  45. type(isop_data),dimension(nregions),target :: isop_dat
  46. !flags the daily calculation of isoprene distribution func.
  47. integer,dimension(nregions) :: day_isop
  48. type( emis_data ), dimension(:,:), allocatable :: isop_emis_2d
  49. type( d3_data ), dimension(:,:), allocatable :: isop_emis_3d
  50. integer :: j_start, j_end ! indices for tropics
  51. integer :: isop_3dsec, isop_2dsec
  52. logical, allocatable :: has_data_3d(:), has_data_2d(:)
  53. !
  54. ! !REVISION HISTORY:
  55. ! 1 Oct 2010 - Achim Strunk - overhaul for AR5
  56. ! 28 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  57. !
  58. ! !REMARKS:
  59. !
  60. !EOP
  61. !------------------------------------------------------------------------
  62. contains
  63. !--------------------------------------------------------------------------
  64. ! TM5 !
  65. !--------------------------------------------------------------------------
  66. !BOP
  67. !
  68. ! !IROUTINE: EMISSION_ISOP_INIT
  69. !
  70. ! !DESCRIPTION: Allocate memory
  71. !\\
  72. !\\
  73. ! !INTERFACE:
  74. !
  75. SUBROUTINE EMISSION_ISOP_INIT( status )
  76. !
  77. ! !USES:
  78. !
  79. use dims, only : ndyn_max, tref, im, jm, lm, idate, nlon360, nlat180
  80. use dims, only : sec_month, dy, yref, ybeg
  81. use global_data, only : rcfile
  82. use emission_read, only : providers_def, numb_providers, sectors_def
  83. !
  84. ! !OUTPUT PARAMETERS:
  85. !
  86. integer, intent(out) :: status
  87. !
  88. ! !REVISION HISTORY:
  89. ! 1 Oct 2010 - Achim Strunk - adapted for AR5
  90. ! 28 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  91. !
  92. ! !REMARKS:
  93. !
  94. !EOP
  95. !------------------------------------------------------------------------
  96. !BOC
  97. character(len=*), parameter :: rname = mname//'/emission_isop_init'
  98. integer :: region, i1, i2, j1, j2
  99. integer :: lmr, lsec, ntim, lprov
  100. real :: dtime, dy1
  101. ! --- begin -----------------------------------------
  102. status = 0
  103. if(.not. has_isop_emis) return
  104. isop_2dsec = 0
  105. isop_3dsec = 0
  106. do lprov = 1, numb_providers
  107. if (count(used_providers_isop == providers_def(lprov)%name)/=0) then
  108. ! limit AR5 to the 2D biomass burning sector
  109. if ( trim(providers_def(lprov)%name) == 'AR5' ) then
  110. isop_2dsec = isop_2dsec + count( sectors_def%prov == 'AR5 ' &
  111. .and. sectors_def%catname == 'biomassburning')
  112. else
  113. ! use all sectors
  114. isop_2dsec = isop_2dsec + providers_def(lprov)%nsect2d
  115. isop_3dsec = isop_3dsec + providers_def(lprov)%nsect3d
  116. end if
  117. endif
  118. enddo
  119. allocate( isop_emis_2d( nregions, isop_2dsec ) )
  120. allocate( isop_emis_3d( nregions, isop_3dsec ) )
  121. allocate( has_data_2d(isop_2dsec)) ; has_data_2d=.false.
  122. allocate( has_data_3d(isop_3dsec)) ; has_data_3d=.false.
  123. ! allocate information arrays (2d and 3d)
  124. do region=1,nregions
  125. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  126. lmr = lm(region)
  127. do lsec=1,isop_2dsec
  128. allocate( isop_emis_2d(region,lsec)%surf(i1:i2, j1:j2) )
  129. end do
  130. do lsec=1,isop_3dsec
  131. allocate( isop_emis_3d(region,lsec)%d3(i1:i2, j1:j2,lmr) )
  132. end do
  133. dtime=float(ndyn_max)/(2*tref(region)) ! timestep emissions
  134. ntim=86400/nint(dtime) ! number of timesteps in 24 hours for this region
  135. allocate(isop_dat(region)%scalef_isop(ntim,j1:j2)) ! allocate enough memory!
  136. enddo
  137. ! find indices of tropics for splitting emissions
  138. dy1=dy/yref(1)
  139. j_start = floor((-20. - ybeg(1))/dy1) + 1
  140. j_end = floor(( 20. - ybeg(1))/dy1) + 1
  141. ! ok
  142. status = 0
  143. end subroutine Emission_isop_Init
  144. !EOC
  145. !--------------------------------------------------------------------------
  146. ! TM5 !
  147. !--------------------------------------------------------------------------
  148. !BOP
  149. !
  150. ! !IROUTINE: EMISSION_ISOP_DONE
  151. !
  152. ! !DESCRIPTION: Free memory
  153. !\\
  154. !\\
  155. ! !INTERFACE:
  156. !
  157. subroutine Emission_isop_Done( status )
  158. !
  159. ! !OUTPUT PARAMETERS:
  160. !
  161. integer, intent(out) :: status
  162. !
  163. ! !REVISION HISTORY:
  164. ! 1 Oct 2010 - Achim Strunk - adapted to new structures
  165. ! 28 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  166. !
  167. !EOP
  168. !------------------------------------------------------------------------
  169. !BOC
  170. character(len=*), parameter :: rname = mname//'/Emission_isop_Done'
  171. integer :: region, lsec
  172. ! --- begin --------------------------------------
  173. status = 0
  174. if(.not. has_isop_emis) return
  175. do region = 1, nregions
  176. do lsec=1,isop_2dsec
  177. deallocate( isop_emis_2d(region,lsec)%surf )
  178. end do
  179. do lsec=1,isop_3dsec
  180. deallocate( isop_emis_3d(region,lsec)%d3 )
  181. end do
  182. deallocate(isop_dat(region)%scalef_isop )
  183. end do
  184. deallocate( isop_emis_2d, isop_emis_3d )
  185. deallocate( has_data_2d, has_data_3d )
  186. status = 0
  187. end subroutine Emission_isop_Done
  188. !EOC
  189. !--------------------------------------------------------------------------
  190. ! TM5 !
  191. !--------------------------------------------------------------------------
  192. !BOP
  193. !
  194. ! !IROUTINE: EMISSION_ISOP_DECLARE
  195. !
  196. ! !DESCRIPTION: Opens, reads and evaluates input files (per month).
  197. ! Provides emissions on 2d/3d-arrays which are then added
  198. ! to mixing ratios in routine *apply.
  199. !\\
  200. !\\
  201. ! !INTERFACE:
  202. !
  203. SUBROUTINE EMISSION_ISOP_DECLARE( status )
  204. !
  205. ! !USES:
  206. !
  207. use toolbox, only : coarsen_emission
  208. use dims, only : im, jm, lm, idate, sec_month, nlon360, nlat180, iglbsfc
  209. use chem_param, only : xmisop
  210. use emission_data, only : msg_emis, LCMIP6BMB, LAR5BMB, LMEGAN
  211. ! ---------------- CMIP6 - AR5 - MACC --------------------
  212. use emission_data, only : emis_input_year_nmvoc, emis_input_year_nat
  213. use emission_data, only : emis_input_dir_mac
  214. use emission_data, only : emis_input_dir_megan
  215. use emission_data, only : emis_input_dir_retro
  216. use emission_data, only : emis_input_dir_gfed
  217. use emission_read, only : emission_ar5_regrid_aircraft
  218. use emission_read, only : emission_cmip6_ReadSector
  219. use emission_read, only : emission_cmip6bmb_ReadSector
  220. use emission_read, only : emission_ar5_ReadSector
  221. use emission_read, only : emission_macc_ReadSector
  222. use emission_read, only : emission_megan_ReadSector
  223. use emission_read, only : emission_gfed_ReadSector
  224. use emission_read, only : emission_retro_ReadSector
  225. use emission_read, only : sectors_def, numb_sectors
  226. use emission_read, only : ar5_dim_3ddata
  227. !
  228. ! !OUTPUT PARAMETERS:
  229. !
  230. integer, intent(out) :: status
  231. !
  232. ! !REVISION HISTORY:
  233. ! 1 Oct 2010 - Achim Strunk - adapted for AR5
  234. !
  235. !EOP
  236. !------------------------------------------------------------------------
  237. !BOC
  238. character(len=*), parameter :: rname = mname//'/emission_isop_declare'
  239. integer :: region, hasData
  240. integer, parameter :: add_field=0
  241. integer, parameter :: amonth=2
  242. integer :: imr, jmr, lmr, lsec
  243. ! AR5
  244. real,dimension(:,:,:),allocatable :: field3d, field3d2
  245. type(d3_data) :: emis3d, work(nregions)
  246. type(emis_data) :: wrk2D(nregions)
  247. integer :: seccount2d, seccount3d
  248. ! --- begin -----------------------------------------
  249. status = 0
  250. if(.not. has_isop_emis) return
  251. write(gol,'(" EMISS-INFO ------------- read ISOPRENE emissions -------------")'); call goPr
  252. ! flag calculation of daily isoprene emission distribution
  253. day_isop(1:nregions) = -1
  254. do region = 1, nregions
  255. do lsec=1,isop_2dsec
  256. isop_emis_2d(region,lsec)%surf = 0.0
  257. end do
  258. do lsec=1,isop_3dsec
  259. isop_emis_3d(region,lsec)%d3 = 0.0
  260. end do
  261. end do
  262. ! global arrays for coarsening
  263. do region = 1, nregions
  264. if (isRoot)then
  265. allocate(work(region)%d3(im(region),jm(region),ar5_dim_3ddata))
  266. else
  267. allocate(work(region)%d3(1,1,1))
  268. end if
  269. enddo
  270. do region = 1, nregions
  271. wrk2D(region)%surf => work(region)%d3(:,:,1)
  272. end do
  273. ! --------------------------------
  274. ! do a loop over available sectors
  275. ! --------------------------------
  276. ! count 2d and 3d sectors
  277. seccount2d = 0
  278. seccount3d = 0
  279. ! always allocate here 3d data set (for 2d sectors it will be filled in first layer only)
  280. if (isRoot) then
  281. allocate( field3d( nlon360, nlat180, ar5_dim_3ddata ) ) ; field3d = 0.0
  282. else
  283. allocate( field3d( 1, 1, 1 ) )
  284. end if
  285. sec : do lsec = 1, numb_sectors
  286. ! screen out unused providers
  287. if (count(used_providers_isop.eq.sectors_def(lsec)%prov).eq.0) cycle
  288. ! screen out CMIP6 and AR5 non-fires
  289. if ( sectors_def(lsec)%prov == 'AR5 ' .and. sectors_def(lsec)%catname /= 'biomassburning') cycle
  290. field3d = 0.0
  291. if( sectors_def(lsec)%f3d ) then
  292. seccount3d = seccount3d + 1
  293. else
  294. seccount2d = seccount2d + 1
  295. end if
  296. if (isRoot) then ! READ
  297. select case( trim(sectors_def(lsec)%prov) )
  298. case( 'CMIP6BMB' )
  299. call emission_cmip6bmb_ReadSector( 'NMVOC-'//'C5H8', emis_input_year_nmvoc, idate(2), lsec, field3d, status )
  300. IF_NOTOK_RETURN(status=1;deallocate(field3d))
  301. case( 'AR5' )
  302. ! here only if we select AR5, and if sector is BMB
  303. if (LAR5BMB) then
  304. call emission_ar5_ReadSector( 'isoprene', emis_input_year_nmvoc, idate(2), lsec, field3d, status )
  305. IF_NOTOK_RETURN(status=1)
  306. endif
  307. case( 'MACC' )
  308. ! skip if MEGAN is used, screen out sectors w/o isop else
  309. if( (trim(sectors_def(lsec)%name) .eq. 'emiss_bio') .and. (.not. LMEGAN) ) then
  310. if (trim(sectors_def(lsec)%catname) .eq. 'natural') then
  311. call emission_macc_ReadSector( emis_input_dir_mac, 'ISOPRENE', emis_input_year_nat, idate(2), &
  312. '0.5x0.5_kg.nc', sectors_def(lsec)%name, 'kg / s', field3d, status )
  313. IF_NOTOK_RETURN(status=1)
  314. else
  315. call emission_macc_ReadSector( emis_input_dir_mac, 'ISOPRENE', emis_input_year_nmvoc, idate(2), &
  316. '0.5x0.5_kg.nc', sectors_def(lsec)%name, 'kg / s', field3d, status )
  317. IF_NOTOK_RETURN(status=1)
  318. endif
  319. endif
  320. case('GFEDv3')
  321. call emission_gfed_ReadSector( emis_input_dir_gfed, 'isoprene', emis_input_year_nmvoc, idate(2), &
  322. sectors_def(lsec)%name, 'kg / s', field3d(:,:,1), status )
  323. IF_NOTOK_RETURN(status=1)
  324. case('RETRO')
  325. call emission_retro_ReadSector( emis_input_dir_retro, 'ISOPRENE', emis_input_year_nmvoc, idate(2), &
  326. sectors_def(lsec)%name, 'kg / s', field3d(:,:,1), status )
  327. IF_NOTOK_RETURN(status=1)
  328. case('MEGAN')
  329. call emission_megan_ReadSector( emis_input_dir_megan, 'isoprene', emis_input_year_nat, idate(2), &
  330. sectors_def(lsec)%name, 'kg / s', field3d(:,:,1), status )
  331. IF_NOTOK_RETURN(status=1)
  332. case('DUMMY')
  333. case default
  334. write(gol,*) "Error in buidling list of providers USED_PROVIDERS_ISOP" ; call goErr
  335. status=1; TRACEBACK; return
  336. end select
  337. ! nothing found???
  338. if( sum(field3d) < 100.*TINY(1.0) ) then
  339. if (okdebug) then
  340. write(gol,'("EMISS-INFO - no ISOP emissions found for ",a," ",a," for month ",i2 )') &
  341. trim(sectors_def(lsec)%prov), trim(sectors_def(lsec)%name), idate(2) ; call goPr
  342. endif
  343. hasData=0
  344. else
  345. if (okdebug) then
  346. write(gol,'("EMISS-INFO - found ISOP emissions for ",a," ",a," for month ",i2 )') &
  347. trim(sectors_def(lsec)%prov), trim(sectors_def(lsec)%name), idate(2) ; call goPr
  348. endif
  349. ! scale from kg/s to kg/month
  350. field3d = field3d * sec_month ! kg / month
  351. hasData=1
  352. end if
  353. end if
  354. call Par_broadcast(hasData, status)
  355. IF_NOTOK_RETURN(status=1)
  356. if (hasData == 0) then
  357. cycle sec
  358. else
  359. if ( sectors_def(lsec)%f3d ) then
  360. has_data_3d(seccount3d)=.true.
  361. else
  362. has_data_2d(seccount2d)=.true.
  363. end if
  364. end if
  365. ! Distinguish 2d/3d sectors
  366. if( sectors_def(lsec)%f3d ) then
  367. write(gol,'("EMISS-ERROR - Unexpected 3D data: Uncomment code below ")'); call goErr
  368. status=1; TRACEBACK; return
  369. ! ---------------------------
  370. ! 3d data (AIRCRAFT)
  371. ! ---------------------------
  372. ! if (isRoot) then ! regrid
  373. ! ! helper array for regridding
  374. ! allocate( field3d2( nlon360,nlat180,lm(1) ) ) ; field3d2 = 0.0
  375. ! ! aircraft data: regrid vertically to model layers
  376. ! call emission_ar5_regrid_aircraft( iglbsfc, field3d, nlon360, nlat180, ar5_dim_3ddata, lm(1), field3d2, status )
  377. ! IF_NOTOK_RETURN(status=1;deallocate(field3d,field3d2))
  378. ! ! write some numbers
  379. ! call msg_emis( amonth, 'aircraft. mass month', 'ISOP', xmisop, sum(field3d2) )
  380. ! ! distribute to isop_emis in regions
  381. ! call Coarsen_Emission( 'ISOP '//trim(sectors_def(lsec)%name), nlon360, nlat180, lm(1), &
  382. ! field3d2, work, add_field, status )
  383. ! IF_NOTOK_RETURN(status=1;deallocate(field3d,field3d2))
  384. ! deallocate( field3d2 )
  385. ! end if
  386. ! do region = 1, nregions
  387. ! call scatter(dgrid(region), isop_emis_3d(region,seccount3d)%d3, work(region)%d3, 0, status)
  388. ! IF_NOTOK_RETURN(status=1)
  389. ! end do
  390. else
  391. ! ---------------------------
  392. ! 2d data (Anthropogenic, Ships, Biomassburning)
  393. ! ---------------------------
  394. if (isRoot) then ! print total & regrid
  395. call msg_emis( amonth, trim(sectors_def(lsec)%prov), sectors_def(lsec)%name, 'ISOP', xmisop, sum(field3d(:,:,1)) )
  396. call coarsen_emission( 'ISOP '//sectors_def(lsec)%name, nlon360, nlat180, field3d(:,:,1), wrk2D, add_field, status )
  397. IF_NOTOK_RETURN(status=1)
  398. end if
  399. do region = 1, nregions
  400. call scatter(dgrid(region), isop_emis_2d(region,seccount2d)%surf, work(region)%d3(:,:,1), 0, status)
  401. IF_NOTOK_RETURN(status=1)
  402. end do
  403. end if
  404. end do sec ! sectors
  405. deallocate( field3d )
  406. do region = 1, nregions
  407. if (associated(wrk2D(region)%surf)) nullify(wrk2D(region)%surf)
  408. deallocate( work(region)%d3 )
  409. end do
  410. status = 0
  411. END SUBROUTINE EMISSION_ISOP_DECLARE
  412. !EOC
  413. !--------------------------------------------------------------------------
  414. ! TM5 !
  415. !--------------------------------------------------------------------------
  416. !BOP
  417. !
  418. ! !IROUTINE: EMISSION_ISOP_APPLY
  419. !
  420. ! !DESCRIPTION: Take monthly emissions, and
  421. ! - split them vertically
  422. ! - apply time splitting factors
  423. ! - add them up (add_isop)
  424. !\\
  425. !\\
  426. ! !INTERFACE:
  427. !
  428. SUBROUTINE EMISSION_ISOP_APPLY( region, status )
  429. !
  430. ! !USES:
  431. !
  432. use dims, only : itaur, nsrce, tref
  433. use dims, only : im, jm, lm, mlen, ndyn_max
  434. use dims, only : yref, dy, ybeg
  435. use datetime, only : tau2date, get_day
  436. use emission_data, only : emission_vdist_by_sector, bb_cycle
  437. use emission_data, only : emis_bb_trop_cycle
  438. use chem_param, only : iisop, xmisop
  439. use emission_data, only : do_add_3d, do_add_3d_cycle
  440. use emission_read, only : sectors_def, numb_sectors
  441. use tracer_data, only : tracer_print
  442. !
  443. ! !INPUT PARAMETERS:
  444. !
  445. integer, intent(in) :: region
  446. !
  447. ! !OUTPUT PARAMETERS:
  448. !
  449. integer, intent(out) :: status
  450. !
  451. ! !REVISION HISTORY:
  452. ! 1 Oct 2010 - Achim Strunk - adapted for AR5
  453. ! 27 Apr 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  454. !
  455. ! !REMARKS:
  456. !
  457. !EOP
  458. !------------------------------------------------------------------------
  459. !BOC
  460. character(len=*), parameter :: rname = mname//'/emission_isop_apply'
  461. integer, dimension(6) :: idater
  462. real :: dtime, fraction
  463. integer :: imr, jmr, lmr, lsec
  464. integer :: seccount2d, seccount3d
  465. type(d3_data) :: emis3d
  466. real :: dlatr
  467. integer :: day, ntim, i1, i2, j1, j2, j01, j02
  468. ! --- begin -----------------------------------------
  469. status = 0
  470. if(.not. has_isop_emis) return
  471. if( okdebug ) then
  472. write(gol,*) 'start of emission_apply_isop'; call goPr
  473. end if
  474. ! --- WHERE, WHEN
  475. CALL TAU2DATE( itaur(region), idater)
  476. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  477. day = GET_DAY(idater(2),idater(3),mlen)
  478. dtime = float(nsrce)/(2*tref(region)) !emissions are added in two steps...XYZECCEZYX.
  479. if(okdebug) then
  480. write(gol,*)'emission_isop_apply in region ',region,' at date: ',idater, ' with time step:', dtime
  481. call goPr
  482. end if
  483. ! --- DIURNAL CYCLE
  484. if ( day /= day_isop(region) ) then
  485. dlatr = dy/yref(region) ! should be the same as lli%dlat_deg
  486. dtime=float(ndyn_max)/(2*tref(region)) ! timestep emissions
  487. ntim=86400/nint(dtime) ! number of timesteps in 24 hours.
  488. if ( okdebug ) then
  489. write (gol,*) 'day',day,'ntim',ntim,'jm',jm(region),'ybeg',&
  490. ybeg(region),'dlatr',dlatr,'sum(mlen)',sum(mlen),nsrce,dtime
  491. call goPr
  492. end if
  493. ! NOTE : latitude_start must be an integer. This is ok as long as
  494. ! the regions ybeg are integer.
  495. call scale_isop(day, ntim, j1, isop_dat(region)%scalef_isop, ybeg(region), dlatr, sum(mlen))
  496. day_isop(region) = day !avoid recalculation during this day!
  497. endif
  498. ! --- ADD EMISSIONS
  499. ! default: no additional splitting
  500. fraction = 1.0
  501. ! get a working structure for 3d emissions
  502. allocate( emis3d%d3(i1:i2,j1:j2,lm(region)) ) ; emis3d%d3 = 0.0
  503. ! count 2d and 3d sectors
  504. seccount2d = 0
  505. seccount3d = 0
  506. ! cycle over sectors
  507. do lsec = 1, numb_sectors
  508. ! screen out unused providers
  509. if (count(used_providers_isop.eq.sectors_def(lsec)%prov).eq.0) cycle
  510. ! screen out AR5 non-fires
  511. if ( sectors_def(lsec)%prov == 'AR5 ' .and. sectors_def(lsec)%catname /= 'biomassburning') cycle
  512. ! default: no additional splitting
  513. fraction = 1.0
  514. ! ----------------------------------------------------------------------------------------
  515. ! distinguish here between sectors and whether they should have additional splitting
  516. ! if( sectors_def(lsec)%catname == 'biomassburning' ) fraction = fraction * bb_frac etc...
  517. ! ----------------------------------------------------------------------------------------
  518. ! distinguish between 2d/3d sectors
  519. if( sectors_def(lsec)%f3d ) then
  520. seccount3d = seccount3d + 1
  521. if (.not.has_data_3d(seccount3d)) cycle
  522. emis3d%d3 = isop_emis_3d(region,seccount3d)%d3
  523. else
  524. seccount2d = seccount2d + 1
  525. if (.not.has_data_2d(seccount2d)) cycle
  526. emis3d%d3 = 0.0
  527. ! vertically distribute according to sector
  528. call emission_vdist_by_sector( sectors_def(lsec)%vdisttype, 'ISOP', region, isop_emis_2d(region,seccount2d), &
  529. emis3d, status)
  530. IF_NOTOK_RETURN(status=1)
  531. ! is tile in tropics
  532. if ((j_end .lt. j1 ).or.(j_start .gt. j2) ) then
  533. continue
  534. else
  535. ! limit range
  536. j02=j_end
  537. j01=j_start
  538. if (j_end .gt. j2 ) j02 = j2
  539. if (j_start .lt. j1 ) j01 = j1
  540. emis3d%d3(:,j01:j02,1)=0.5*emis3d%d3(:,j01:j02,1)
  541. emis3d%d3(:,j01:j02,2)=emis3d%d3(:,j01:j02,1)
  542. end if
  543. end if
  544. ! add dataset according to sector and category
  545. if( trim(sectors_def(lsec)%catname) == "natural" ) then
  546. call do_add_isop( region, i1, j1, emis3d%d3, status, fraction ) ! special routine with additional emission scaling...
  547. IF_NOTOK_RETURN(status=1)
  548. elseif (trim(sectors_def(lsec)%catname) == "biomassburning") then
  549. if( emis_bb_trop_cycle ) then
  550. call do_add_3d_cycle( region, iisop, i1, j1, emis3d%d3, bb_cycle(region)%scalef, xmisop, xmisop, status, fraction )
  551. IF_NOTOK_RETURN(status=1)
  552. else
  553. call do_add_3d( region, iisop, i1, j1, emis3d%d3, xmisop, xmisop, status, fraction )
  554. IF_NOTOK_RETURN(status=1)
  555. end if
  556. endif
  557. end do
  558. deallocate( emis3d%d3 )
  559. if(okdebug) then
  560. write(gol,*) 'end of emission_isop_apply' ; call goPr
  561. end if
  562. ! OK
  563. status = 0
  564. END SUBROUTINE EMISSION_ISOP_APPLY
  565. !EOC
  566. !--------------------------------------------------------------------------
  567. ! TM5 !
  568. !--------------------------------------------------------------------------
  569. !BOP
  570. !
  571. ! !IROUTINE: SCALE_ISOP
  572. !
  573. ! !DESCRIPTION: calculates factors to be multiplied with an emission field
  574. ! (e.g. isop) in order to simulate a diurnal cycle in
  575. ! emissions (caused by solar dependency), e.g. :
  576. !
  577. ! rm(i,j,1,isop) = rm(i,j,1,isop) + e_isop(i,j)*scalef(ipos,j)*dt
  578. !
  579. ! with ipos depending on time and longitude.
  580. !
  581. ! The scalefactor is calculated for -180 longitude and the
  582. ! mean value for ntim timesteps during a day is scaled to 1.
  583. ! The routine should be called every day, since the position
  584. ! relative to the sun changes. The scaling is based on the
  585. ! cos(zenith) which is 1 for overhead sun and 0 at sunset.
  586. ! For the polar night, the values are set to 1.0 (even distribution)
  587. ! One thing is sure afterwards: we know that e_isop kg/s is added.
  588. !\\
  589. !\\
  590. ! !INTERFACE:
  591. !
  592. SUBROUTINE SCALE_ISOP(day, ntim, j1, scalef, lat_start, dlat, idayy)
  593. !
  594. ! !INPUT PARAMETERS:
  595. !
  596. integer, intent(in) :: day ! day number based on 365 days a year
  597. integer, intent(in) :: ntim ! number of timesteps during one day
  598. integer, intent(in) :: j1 ! start index for latitudes
  599. integer, intent(in) :: lat_start ! southern edge of the domain (integer!)
  600. real, intent(in) :: dlat ! increment (real!)
  601. integer, intent(in) :: idayy ! # days this year
  602. !
  603. ! !OUTPUT PARAMETERS:
  604. !
  605. real, dimension(:,j1:), intent(out) :: scalef
  606. !
  607. ! !REVISION HISTORY:
  608. ! 10 May 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  609. !
  610. ! !REMARKS:
  611. !
  612. !EOP
  613. !------------------------------------------------------------------------
  614. !BOC
  615. real :: pi, piby, obliq, deday, delta, dt, lon, hr, lat, houra, smm
  616. integer :: i, j
  617. pi = acos(-1.0)
  618. piby = pi/180.0
  619. obliq = 23.45 * piby
  620. deday = 4.88 + 2*pi/idayy * day
  621. delta = asin(sin(obliq)*sin(deday))
  622. dt = 24./ntim ! timestep in hours
  623. lon = -180.0*piby ! calculate for dateline
  624. do j=j1,ubound(scalef,2) ! over latitudes
  625. hr = - 0.5*dt ! shift half a interval back
  626. lat = (lat_start + (j-0.5)*dlat)*piby
  627. smm = 0.0
  628. do i=1,ntim
  629. hr = hr + dt
  630. houra = lon - pi + hr * (2.*pi/24.)
  631. scalef(i,j) = &
  632. max((sin(delta)*sin(lat) + cos(delta)*cos(lat)*cos(houra)),0.0)
  633. smm = smm+scalef(i,j)/ntim
  634. end do
  635. if ( smm > 1e-5 ) then
  636. scalef(1:ntim,j) = scalef(1:ntim,j)/smm
  637. else
  638. scalef(1:ntim,j) = 1.0
  639. end if
  640. end do
  641. END SUBROUTINE SCALE_ISOP
  642. !EOC
  643. !--------------------------------------------------------------------------
  644. ! TM5 !
  645. !--------------------------------------------------------------------------
  646. !BOP
  647. !
  648. ! !IROUTINE: DO_ADD_ISOP
  649. !
  650. ! !DESCRIPTION: Add local time splitted emissions to chemical array
  651. !\\
  652. !\\
  653. ! !INTERFACE:
  654. !
  655. SUBROUTINE DO_ADD_ISOP(region, i1, j1, em_isop, status, fraction)
  656. !
  657. ! !USES:
  658. !
  659. use dims, only : tref, nsrce, itaur, ndyn_max
  660. use dims, only : sec_month, lm, dx, xref, xbeg
  661. use global_data, only : mass_dat
  662. use chem_param, only : iisop, xmisop
  663. #ifdef with_budgets
  664. use budget_global, only : budg_dat, nzon_vg
  665. use emission_data, only : sum_emission, budemi_dat
  666. #endif
  667. use datetime, only : tau2date
  668. !
  669. ! !INPUT PARAMETERS:
  670. !
  671. integer, intent(in) :: region, i1, j1
  672. real, intent(in) :: em_isop(i1:,j1:,:)
  673. real, optional, intent(in) :: fraction
  674. !
  675. ! !OUTPUT PARAMETERS:
  676. !
  677. integer, intent(out) :: status
  678. !
  679. ! !REVISION HISTORY:
  680. ! 1 Oct 2010 - Achim Strunk - added fraction input
  681. ! - switch from 2D to 3D input => remove tropics case
  682. ! 10 May 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  683. !
  684. ! !REMARKS:
  685. ! (1) scalef_isop has been calculated w/ ndyn_max.
  686. !EOP
  687. !------------------------------------------------------------------------
  688. !BOC
  689. character(len=*), parameter :: rname = mname//'/do_add_isop'
  690. real :: x, xlon, dtime, month2dt, dtime2
  691. integer :: i, j, l, ipos, nzone, nzone_v
  692. integer :: sec_in_day, ntim, itim, i2, j2
  693. integer, dimension(6) :: idater
  694. real, dimension(:,:,:,:), pointer :: rm
  695. ! --- begin -----------------------------------------
  696. rm => mass_dat(region)%rm
  697. CALL GET_DISTGRID( dgrid(region), I_STOP=i2, J_STOP=j2 )
  698. dtime = float(nsrce) / (2*tref(region)) ! timestep emissions
  699. dtime2 = float(ndyn_max) / (2*tref(region)) ! timestep emissions based on non-CFL interference (CMK 05/2006)
  700. month2dt = dtime/sec_month ! conversion to emission per timestep (CFl induced timestep CMK 05/2006)
  701. ntim = 86400/nint(dtime2) ! number of timesteps in 24 hours based on non-CFL interference (CMK 05/2006)
  702. call tau2date(itaur(region),idater)
  703. sec_in_day = idater(4)*3600 + idater(5)*60 + idater(6) ! elapsd seconds this day
  704. itim = sec_in_day/nint(dtime2)+1 ! # time interval CMK 05/2006
  705. do l= 1,lm(region)
  706. do j=j1,j2
  707. do i=i1,i2
  708. xlon = xbeg(region) + (i-0.5)*dx/xref(region)
  709. ! itim = 1 and lon = -180 --->position 1
  710. ! itim = ntim ant lon = -180 --->position ntim, etc.
  711. ! itim = 1 and lon = 0 ---->position ntim/2
  712. ipos = 1 + mod(int((xlon+180.)*ntim/360.) + (itim-1),ntim) !position in array depending on time and lon.
  713. x=em_isop(i,j,l)*isop_dat(region)%scalef_isop(ipos,j)*month2dt
  714. rm(i,j,l,iisop)=rm(i,j,l,iisop)+x
  715. #ifdef with_budgets
  716. nzone=budg_dat(region)%nzong(i,j) !global budget
  717. nzone_v=nzon_vg(l)
  718. budemi_dat(region)%emi(i,j,nzone_v,iisop) = &
  719. budemi_dat(region)%emi(i,j,nzone_v,iisop) + x/xmisop*1e3
  720. if(iisop ==1) sum_emission(region) = sum_emission(region) + x !in kg
  721. #endif
  722. !--
  723. !AJS: strange statement: injection of emission decreases vertical slope ?
  724. !AJS: this gives negative slopes in case of large emissions ...
  725. !if(adv_scheme.eq.'slope') rzm(i,j,L,iisop)=rzm(i,j,L,iisop)-x
  726. !--
  727. enddo !i
  728. enddo !j
  729. enddo !l
  730. nullify(rm)
  731. status=0
  732. END SUBROUTINE DO_ADD_ISOP
  733. !EOC
  734. END MODULE EMISSION_ISOP