emission_dms.F90 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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_DMS
  14. !
  15. ! !DESCRIPTION:
  16. !\\
  17. !\\
  18. ! !INTERFACE:
  19. !
  20. MODULE EMISSION_DMS
  21. !
  22. ! !USES:
  23. !
  24. use GO, only : gol, goErr, goPr
  25. use tm5_distgrid, only : dgrid, get_distgrid, scatter, gather
  26. use partools, only : isRoot
  27. use dims, only : nregions
  28. use global_types, only : emis_data, d3_data
  29. IMPLICIT NONE
  30. PRIVATE
  31. !
  32. ! !PUBLIC MEMBER FUNCTIONS:
  33. !
  34. public :: emission_dms_init ! allocate
  35. public :: emission_dms_declare ! read monthly input
  36. public :: emission_dms_apply ! distribute & add emissions to tracer array
  37. public :: emission_dms_done ! deallocate
  38. public :: getDMS ! compute DMS from ocean
  39. !
  40. ! !PRIVATE DATA MEMBERS:
  41. !
  42. character(len=*), parameter :: mname = 'emission_dms'
  43. type(emis_data), dimension(nregions), target :: dms_land, dms_sea ! land and sea flux
  44. type(emis_data), dimension(nregions), target :: dms_tool ! work array
  45. real, dimension(:,:), allocatable :: dms_conc ! 1x1 ocean concentrations
  46. !
  47. ! !REVISION HISTORY:
  48. ! 1 Oct 2010 - Achim Strunk - standardized routines name, new apply method
  49. ! 22 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  50. !
  51. ! !REMARKS:
  52. ! (1) see getDMS
  53. !
  54. !EOP
  55. !------------------------------------------------------------------------
  56. CONTAINS
  57. !--------------------------------------------------------------------------
  58. ! TM5 !
  59. !--------------------------------------------------------------------------
  60. !BOP
  61. !
  62. ! !IROUTINE: EMISSION_DMS_INIT
  63. !
  64. ! !DESCRIPTION: Allocate space needed to handle the emissions.
  65. !\\
  66. !\\
  67. ! !INTERFACE:
  68. !
  69. SUBROUTINE EMISSION_DMS_INIT( status )
  70. !
  71. ! !USES:
  72. !
  73. use dims, only : im, jm, iglbsfc
  74. !
  75. ! !OUTPUT PARAMETERS:
  76. !
  77. integer, intent(out) :: status
  78. !
  79. ! !REVISION HISTORY:
  80. ! 1 Oct 2010 - Achim Strunk - extracted from old 'declare' routine
  81. ! 22 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  82. !
  83. !EOP
  84. !------------------------------------------------------------------------
  85. !BOC
  86. character(len=*), parameter :: rname = mname//'/Emission_DMS_Init'
  87. integer :: region
  88. integer :: imr, jmr, i1, i2, j1, j2
  89. ! --- begin --------------------------------------
  90. CALL GET_DISTGRID( dgrid(iglbsfc), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  91. allocate( dms_conc(i1:i2, j1:j2) )
  92. do region = 1, nregions
  93. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  94. imr = im(region) ; jmr = jm(region)
  95. allocate(dms_land(region)%surf(i1:i2,j1:j2))
  96. allocate(dms_sea (region)%surf(i1:i2,j1:j2))
  97. ! work array used in coarsen/scatter
  98. if (isRoot) then
  99. allocate(dms_tool(region)%surf(imr, jmr ))
  100. else
  101. allocate(dms_tool(region)%surf(1, 1))
  102. end if
  103. enddo
  104. status = 0
  105. END SUBROUTINE EMISSION_DMS_INIT
  106. !EOC
  107. !--------------------------------------------------------------------------
  108. ! TM5 !
  109. !--------------------------------------------------------------------------
  110. !BOP
  111. !
  112. ! !IROUTINE: EMISSION_DMS_DONE
  113. !
  114. ! !DESCRIPTION: Deallocate space needed to handle the emissions.
  115. !\\
  116. !\\
  117. ! !INTERFACE:
  118. !
  119. SUBROUTINE EMISSION_DMS_DONE( status )
  120. !
  121. ! !OUTPUT PARAMETERS:
  122. !
  123. integer, intent(out) :: status
  124. !
  125. ! !REVISION HISTORY:
  126. ! 1 Oct 2010 - Achim Strunk - rename old 'free_emission_dms'
  127. !
  128. !EOP
  129. !------------------------------------------------------------------------
  130. !BOC
  131. character(len=*), parameter :: rname = mname//'/Emission_DMS_Done'
  132. integer :: region
  133. ! --- begin ---------------------------------
  134. do region = 1, nregions
  135. deallocate( dms_land (region)%surf)
  136. deallocate( dms_tool (region)%surf)
  137. deallocate( dms_sea (region)%surf)
  138. end do
  139. deallocate(dms_conc)
  140. status = 0
  141. END SUBROUTINE EMISSION_DMS_DONE
  142. !EOC
  143. !--------------------------------------------------------------------------
  144. ! TM5 !
  145. !--------------------------------------------------------------------------
  146. !BOP
  147. !
  148. ! !IROUTINE: EMISSION_DMS_DECLARE
  149. !
  150. ! !DESCRIPTION: Opens, reads and evaluates input files (per month).
  151. ! Land surface fluxes is the Spiro dataset.
  152. ! Ocean concentrations are used to retrieve fluxes by
  153. ! temperature and wind speed.
  154. !\\
  155. !\\
  156. ! !INTERFACE:
  157. !
  158. SUBROUTINE EMISSION_DMS_DECLARE( status )
  159. !
  160. ! !USES:
  161. !
  162. USE MDF, ONLY : MDF_Open, MDF_HDF4, MDF_READ, MDF_Get_Var, MDF_Close
  163. use toolbox, only : coarsen_emission
  164. use dims, only : idate, sec_month, sec_year, iglbsfc, nlat180, nlon360
  165. use chem_param, only : xms
  166. use emission_data, only : msg_emis, emis_input_dir_dms
  167. !
  168. ! !OUTPUT PARAMETERS:
  169. !
  170. integer, intent(out) :: status
  171. !
  172. ! !REVISION HISTORY:
  173. ! 1 Oct 2010 - Achim Strunk - updated to emission standard
  174. ! 22 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition
  175. !
  176. !EOP
  177. !------------------------------------------------------------------------
  178. !BOC
  179. character(len=*), parameter :: rname = mname//'/declare_emission_dms'
  180. integer :: region, i1, i2, j1, j2, nlatsrc, nlonsrc
  181. integer, parameter :: add_field=0
  182. integer, parameter :: amonth=2
  183. real :: year2month
  184. integer :: hid
  185. ! work array on 1x1 resolution
  186. real, dimension(:,:), allocatable :: glb_dms_conc
  187. ! --- begin ---------------------------------
  188. year2month = sec_month/sec_year ! scale factor for yearly total to specific month
  189. nlatsrc = nlat180 ! or dgrid(iglbsfc)%jm_region, accessible thru get_distgrid(...)
  190. nlonsrc = nlon360 ! or dgrid(iglbsfc)%im_region, accessible thru get_distgrid(...)
  191. ! to deal with sea water at 1x1
  192. if(isRoot)then
  193. allocate(glb_dms_conc(nlonsrc,nlatsrc))
  194. else
  195. allocate(glb_dms_conc(1,1))
  196. end if
  197. !
  198. ! DMS emissions from landsurface
  199. ! DMS seawater concentrations. The actual flux is a function of windspeed and temperature
  200. ! and is calculated each time step. The resolution dependency needs to be checked.
  201. ! We will use the 2m winds on 1x1 resolution.....
  202. !
  203. write(gol,'(" EMISS-INFO ------------- read DMS emissions -------------")'); call goPr
  204. if (isRoot) then
  205. ! monthly emissions from Land Spiro dataset
  206. CALL MDF_Open( trim(emis_input_dir_dms)//'/DMSland.hdf', MDF_HDF4, MDF_READ, hid, status )
  207. IF_NOTOK_RETURN(status=1)
  208. CALL MDF_Get_Var( hid, idate(2), glb_dms_conc, status )
  209. IF_NOTOK_RETURN(status=1)
  210. CALL MDF_Close( hid, status )
  211. IF_NOTOK_RETURN(status=1)
  212. call msg_emis(amonth, 'SPIRO', 'vegetation/soil', 'DMS', xms, sum(glb_dms_conc))
  213. call coarsen_emission('dms_land', nlonsrc, nlatsrc, glb_dms_conc, dms_tool, add_field, status)
  214. IF_NOTOK_RETURN(status=1)
  215. ! seawater concentrations
  216. CALL MDF_Open( trim(emis_input_dir_dms)//'/DMSconc.hdf', MDF_HDF4, MDF_READ, hid, status )
  217. IF_NOTOK_RETURN(status=1)
  218. CALL MDF_Get_Var( hid, idate(2), glb_dms_conc, status )
  219. IF_NOTOK_RETURN(status=1)
  220. CALL MDF_Close( hid, status )
  221. IF_NOTOK_RETURN(status=1)
  222. end if
  223. do region = 1, nregions
  224. call scatter(dgrid(region), dms_land(region)%surf, dms_tool(region)%surf, 0, status)
  225. IF_NOTOK_RETURN(status=1)
  226. end do
  227. call scatter(dgrid(iglbsfc), dms_conc, glb_dms_conc, 0, status)
  228. IF_NOTOK_RETURN(status=1)
  229. deallocate(glb_dms_conc)
  230. ! ok
  231. status = 0
  232. END SUBROUTINE EMISSION_DMS_DECLARE
  233. !EOC
  234. !--------------------------------------------------------------------------
  235. ! TM5 !
  236. !--------------------------------------------------------------------------
  237. !BOP
  238. !
  239. ! !IROUTINE: EMISSION_DMS_APPLY
  240. !
  241. ! !DESCRIPTION: Take monthly emissions, and
  242. ! - split them vertically
  243. ! - apply time splitting factors
  244. ! - add them up (add_3d)
  245. !\\
  246. !\\
  247. ! !INTERFACE:
  248. !
  249. SUBROUTINE EMISSION_DMS_APPLY( region, status )
  250. !
  251. ! !USES:
  252. !
  253. use dims, only : okdebug, itaur, nsrce, tref
  254. use dims, only : im, jm, lm
  255. use datetime, only : tau2date
  256. use emission_data, only : emission_vdist_by_sector
  257. use emission_data, only : do_add_3d
  258. use chem_param, only : idms, xmdms, xms
  259. use emission_data, only : vd_class_name_len
  260. !
  261. ! !INPUT PARAMETERS:
  262. !
  263. integer, intent(in) :: region
  264. !
  265. ! !OUTPUT PARAMETERS:
  266. !
  267. integer, intent(out) :: status
  268. !
  269. ! !REVISION HISTORY:
  270. ! 1 Oct 2010 - Achim Strunk - updated to use new vertical distribution method
  271. ! 28 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  272. !
  273. !EOP
  274. !------------------------------------------------------------------------
  275. !BOC
  276. character(len=*), parameter :: rname = mname//'/emission_dms_apply'
  277. integer,dimension(6) :: idater
  278. real :: dtime, fraction
  279. integer :: imr, jmr, lmr, i1, i2, j1, j2
  280. type(d3_data) :: emis3d
  281. character(len=vd_class_name_len) :: splittype
  282. ! --- begin -----------------------------------------
  283. if( okdebug ) then
  284. write(gol,*) 'start of emission_dms_apply'; call goPr
  285. endif
  286. call tau2date(itaur(region),idater)
  287. dtime=float(nsrce)/(2*tref(region)) !emissions are added in two steps...XYZECCEZYX.
  288. if( okdebug ) then
  289. write(gol,*) 'emission_dms_apply in region ',region,' at date: ',idater, ' with time step:', dtime ; call goPr
  290. endif
  291. ! get a working structure for 3d emissions
  292. call get_distgrid( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  293. allocate( emis3d%d3(i1:i2,j1:j2,lm(region)) ) ; emis3d%d3 = 0.0
  294. ! default: no additional splitting
  295. fraction = 1.0
  296. ! ----------------------------------------------------------------------------------------
  297. ! distinguish here between sectors and whether they should have additional splitting
  298. ! if( ar5_sectors(lsec)%catname == 'biomassburning' ) fraction = fraction * bb_frac etc...
  299. ! ----------------------------------------------------------------------------------------
  300. splittype = 'surface'
  301. ! -------
  302. ! dms sea
  303. ! -------
  304. ! vertically distribute according to sector
  305. call emission_vdist_by_sector( splittype, 'DMS', region, dms_sea(region), emis3d, status )
  306. IF_NOTOK_RETURN(status=1;deallocate(emis3d%d3))
  307. ! add dataset
  308. call do_add_3d( region, idms, i1, j1, emis3d%d3, xmdms, xms, status, fraction )
  309. IF_NOTOK_RETURN(status=1)
  310. ! -------
  311. ! dms land
  312. ! -------
  313. emis3d%d3 = 0.0
  314. ! vertically distribute according to sector
  315. call emission_vdist_by_sector( splittype, 'DMS', region, dms_land(region), emis3d, status )
  316. IF_NOTOK_RETURN(status=1;deallocate(emis3d%d3))
  317. ! add dataset
  318. call do_add_3d( region, idms, i1, j1, emis3d%d3, xmdms, xms, status, fraction )
  319. IF_NOTOK_RETURN(status=1)
  320. if( okdebug ) then
  321. write(gol,*) 'end of emission_dms_apply'; call goPr
  322. endif
  323. deallocate( emis3d%d3 )
  324. ! OK
  325. status = 0
  326. END SUBROUTINE EMISSION_DMS_APPLY
  327. !EOC
  328. !--------------------------------------------------------------------------
  329. ! TM5 !
  330. !--------------------------------------------------------------------------
  331. !BOP
  332. !
  333. ! !IROUTINE: GETDMS
  334. !
  335. ! !DESCRIPTION: calculate the DMS flux based on high resolution ocean
  336. ! concentration and wind speeds and temperatures,
  337. ! and calculate the 'coarser' resolution fluxes from it
  338. !
  339. ! input needed: U2 and T2 on 1x1
  340. !\\
  341. !\\
  342. ! !INTERFACE:
  343. !
  344. SUBROUTINE GETDMS( status )
  345. !
  346. ! !USES:
  347. !
  348. use toolbox, only : coarsen_emission
  349. use binas, only : T0
  350. use meteodata, only : t2m_dat, u10m_dat, v10m_dat
  351. use datetime, only : tau2date
  352. use Dims, only : itau, staggered, sec_year, sec_month, dxy11, iglbsfc, im, jm
  353. use chem_param, only : xms
  354. !
  355. ! !OUTPUT PARAMETERS:
  356. !
  357. integer, intent(out) :: status
  358. !
  359. ! !REVISION HISTORY:
  360. ! 22 Jun 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  361. !
  362. ! !REMARKS:
  363. ! (1) Required inputs: U2 and T2 on 1x1
  364. !
  365. !EOP
  366. !------------------------------------------------------------------------
  367. !BOC
  368. character(len=*), parameter :: rname = mname//'/getdms'
  369. real, dimension(:,:), allocatable :: emi_dms, emis_glb, u_wind, v_wind, temperature
  370. real :: xwind, zschmidt, resfac, tot_flux, kw, tt, xlon, xlat, piston_dms
  371. integer :: i, j, l, region, i1, j1, i2, j2
  372. integer, dimension(6) :: idates
  373. integer, parameter :: level1=1, add_field=0
  374. integer :: nlatsrc, nlonsrc
  375. ! determine correction factor to account for less effective mixing
  376. ! at lower averaged windspeeds occuring at lower resolution
  377. CALL GET_DISTGRID( dgrid(iglbsfc), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  378. nlatsrc = jm(iglbsfc) ! or nlat180, or dgrid(iglbsfc)%jm_region, accessible thru get_distgrid(...)
  379. nlonsrc = im(iglbsfc) ! or nlon360, or dgrid(iglbsfc)%jm_region, accessible thru get_distgrid(...)
  380. if (iglbsfc /= 1) then ! assume no zoom region if region #1 is at 1x1 (see below)
  381. if (isRoot)then
  382. allocate(emis_glb (nlonsrc,nlatsrc))
  383. else
  384. allocate(emis_glb (1,1))
  385. end if
  386. end if
  387. allocate(emi_dms (i1:i2, j1:j2))
  388. allocate(u_wind (i1:i2, j1:j2))
  389. allocate(v_wind (i1:i2, j1:j2))
  390. allocate(temperature(i1:i2, j1:j2))
  391. call tau2date(itau+staggered,idates) !CMK at end 3-hourly interval
  392. temperature = t2m_dat(iglbsfc)%data(:,:,1)
  393. ! convert to celsius
  394. temperature = temperature - T0
  395. u_wind = u10m_dat(iglbsfc)%data(:,:,1)
  396. v_wind = v10m_dat(iglbsfc)%data(:,:,1)
  397. resfac=1.
  398. ! THE RESOLUTION DEPENDENCY WITH PREVIOUS TM3 RUNS WAS AS FOLLOWS
  399. ! NEEDS TO BE CHECKED FD
  400. !FD if (jm.eq.24) resfac=1.32
  401. !FD if (jm.eq.48) resfac=1.065
  402. emi_dms=0.
  403. do j=j1,j2
  404. do i=i1,i2
  405. !
  406. ! ocean surface temperature is approximated by air surface temperature
  407. ! we assume that if temperature<-20. ! sea ice prevents DMS emissions (sea-ice data from ECMWF would be usefull)
  408. ! max ocean temperature is 28.0 C
  409. ! minumum ocean temperature 0. C
  410. !fd tt=min(28.,ts(i,j)-273.15) ! the original parameterisation needs the seawater temperature
  411. ! as a proxy we use the air temperature, but restrict it to 28 C.
  412. ! surface or 2m temperature of air is probably the best proxy.
  413. tt=min(28.0,temperature(i,j))
  414. if (dms_conc(i,j).gt.0..and.tt.gt.-20.) then
  415. zschmidt=max(0.0,3652.047271-246.99*TT+8.536397*TT*TT-0.124397*TT*TT*TT)
  416. xwind=sqrt(u_wind(i,j)**2+v_wind(i,j)**2)
  417. !
  418. ! Liss and Merlivat windspeed dependency of transfer velocity kw
  419. ! including correction for Schmidt number
  420. ! windspeed at middle of gridbox is used should be 10 m windspeed [m/s]
  421. if (xwind.le.3.6) then
  422. kw=0.17*xwind
  423. piston_dms=kw*(zschmidt/600.)**(-0.666)
  424. else !xwind>3.6)
  425. if (xwind.le.13.0) then
  426. kw=2.85*xwind-9.65
  427. piston_dms=kw*(zschmidt/600.)**(-0.5)
  428. else !xwind>13.0
  429. kw=5.9*xwind-49.3
  430. piston_dms=kw*(zschmidt/600.)**(-0.5)
  431. endif !x<13.0
  432. endif
  433. !
  434. ! cm/hr=> m/s * nmol/l=>mol/m3 * m2 * g S/mol=>g S/s
  435. !
  436. emi_dms(i,j)=resfac*piston_dms/360000.*dms_conc(i,j)*1e-6*dxy11(j)*xms
  437. endif !(dms_conc gt 0)
  438. enddo
  439. enddo
  440. !-----------------------------------------------------------
  441. ! Fill target array
  442. !-----------------------------------------------------------
  443. ! Test for optimization: if region #1 is at 1x1, assume no zoom region and skip call to coarsen and mpi comm
  444. if (iglbsfc == 1) then
  445. dms_sea(1)%surf = emi_dms*sec_month*1e-3 !expected in kgS/month
  446. else
  447. !-----------------------------------------------------------
  448. ! gather on 1x1, coarsen to other grid on root, then scatter
  449. !-----------------------------------------------------------
  450. ! FIXME-PERF : Need a coarsen that works independtly on each proc
  451. call gather(dgrid(iglbsfc), emi_dms, emis_glb, 0, status)
  452. IF_NOTOK_RETURN(status=1)
  453. if (isRoot) then
  454. ! FIXME : if really needed, write into budget - here, it gives too much output
  455. !write(gol,*)'the yearly sum of GETDMS would be ',sum(emis_glb) *1e-12*sec_year,' Tg S/a'; call goPr
  456. ! assume equal emissions over season
  457. call coarsen_emission('emi_dms', nlonsrc, nlatsrc, emis_glb, dms_tool, add_field, status)
  458. IF_NOTOK_RETURN(status=1)
  459. end if
  460. do region = 1, nregions
  461. call scatter(dgrid(region), dms_sea(region)%surf, dms_tool(region)%surf, 0, status)
  462. IF_NOTOK_RETURN(status=1)
  463. dms_sea(region)%surf = dms_sea(region)%surf*sec_month*1e-3 !expected in kgS/month
  464. enddo
  465. deallocate(emis_glb)
  466. end if
  467. !-----------------------------------------------------------
  468. deallocate(emi_dms)
  469. deallocate(temperature)
  470. deallocate(u_wind)
  471. deallocate(v_wind)
  472. END SUBROUTINE GETDMS
  473. !EOC
  474. END MODULE EMISSION_DMS