assim_interf_mod.F90 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. ! First include the set of model-wide compiler flags
  2. #include "tm5.inc"
  3. ! macro defs
  4. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  5. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  6. #define IF_NOTOK_MDF(action) if (status/=0) then; TRACEBACK; action; call MDF_CLose(fid,status); status=1; return; end if
  7. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  8. !=====================================================================
  9. !
  10. ! Central interface to link the assimilation code to the TM5 model
  11. !
  12. ! The retrieval-assimilation will be performed on the root node
  13. ! The steps performed:
  14. ! - Gather all arrays needed by the assimilation
  15. ! - call AssimNO2( ntimestep )
  16. ! - Scatter the arrays for the next TM5 time step
  17. !
  18. ! The interface is designed such that the same fields are passed as in the
  19. ! NRT interface, with TM5 fields read from file
  20. !
  21. ! The subroutine AssimNO2 performs a data assimilation time step.
  22. !
  23. ! Henk Eskes, KNMI, March 2015
  24. ! Interface to TM5-mp-CB05
  25. !======================================================================
  26. module assim_interf_mod
  27. ! Definition of structure to store TM5 data
  28. use MTM5Data, only : TTM5Data
  29. implicit none
  30. private
  31. public :: AssimNO2_interface, AssimNO2_interface_init, AssimNO2_interface_done
  32. ! public :: TM5Data
  33. ! This structure stores all info passed from TM5 to the assimilation
  34. type(TTM5Data) :: TM5Data
  35. ! scaling factor, the result of the assimilation
  36. real, dimension(:,:,:), allocatable :: noxscaling
  37. ! This array stores the 3D NOx mass field
  38. real, dimension(:,:,:), allocatable :: store_rm_nox
  39. ! and these arrays the slopes
  40. #ifdef slopes
  41. real, dimension(:,:,:), allocatable :: store_rxm_nox
  42. real, dimension(:,:,:), allocatable :: store_rym_nox
  43. real, dimension(:,:,:), allocatable :: store_rzm_nox
  44. #endif
  45. ! Arrays used to convert the surface pressure and orography from 3D to 2D
  46. real, dimension(:,:,:), allocatable :: sp_temp
  47. real, dimension(:,:,:), allocatable :: oro_temp
  48. real, dimension(:,:,:), allocatable :: gph_temp ! to store geopotential height
  49. character(len=*), parameter :: mname = 'assim_interf_mod'
  50. ! ODIN HNO3 / O3 climatology related
  51. logical :: doNudgeOdinHNO3
  52. character(len=255) :: OdinHNO3File
  53. ! This array stores the 3D HNO3 mass field (to be updated by the HNO3/O3 nudging)
  54. real, dimension(:,:,:), allocatable :: store_rm_hno3
  55. ! Used for debug printing
  56. logical, parameter :: showDebugPrints = .false.
  57. contains
  58. subroutine AssimNO2_interface_init ( rcFile )
  59. !======================================================================
  60. !
  61. ! Initialise storage space for TM5 3D global arrays
  62. !
  63. ! rcFile : name of the rc (settings) file
  64. ! Henk Eskes, KNMI, March 2015
  65. !======================================================================
  66. ! For printing information
  67. use GO, only : gol, goPr, goErr
  68. ! For reading keys from the .rc file
  69. use GO, only : TrcFile, Init, Done, ReadRc
  70. ! To identify root proces
  71. use partools, only : isRoot
  72. ! for dimensions
  73. use meteodata, only : global_lli, levi
  74. ! to read ODIN HNO3/O3 climatology
  75. use MOdinHNO3, only : ReadOdinHNO3
  76. implicit none
  77. ! --- in/out
  78. character(*), intent(in) :: rcFile
  79. ! --- local
  80. character(len=*), parameter :: rname = mname//'/AssimNO2_interface_init'
  81. type(TrcFile) :: rcF
  82. integer :: imr, jmr, lmr, n
  83. integer :: status
  84. ! --- start code ---
  85. if ( isRoot ) then
  86. write(gol,'("Assim_interface: initialise interface")') ; call goPr
  87. end if
  88. ! entire region grid size
  89. n = 1 ! global region
  90. imr = global_lli(n)%nlon
  91. jmr = global_lli(n)%nlat
  92. lmr = levi%nlev
  93. ! Fill fixed-dim constants
  94. TM5Data%im = imr
  95. TM5Data%jm = jmr
  96. TM5Data%lm = lmr
  97. ! Allocate arrays on root, dummy arrays elsewhere
  98. if ( isRoot ) then
  99. allocate ( TM5Data%lon(imr) )
  100. allocate ( TM5Data%lat(jmr) )
  101. allocate ( TM5Data%hyai(lmr+1) )
  102. allocate ( TM5Data%hybi(lmr+1) )
  103. allocate ( TM5Data%hyam(lmr) )
  104. allocate ( TM5Data%hybm(lmr) )
  105. allocate ( TM5Data%ps(imr,jmr) )
  106. allocate ( TM5Data%oro(imr,jmr) )
  107. allocate ( TM5Data%t(imr,jmr,lmr) )
  108. allocate ( TM5Data%ltropo(imr,jmr) )
  109. allocate ( TM5Data%no2(imr,jmr,lmr) )
  110. allocate ( noxscaling(imr,jmr,lmr) )
  111. allocate ( store_rm_nox(imr,jmr,lmr) )
  112. #ifdef slopes
  113. allocate ( store_rxm_nox(imr,jmr,lmr) )
  114. allocate ( store_rym_nox(imr,jmr,lmr) )
  115. allocate ( store_rzm_nox(imr,jmr,lmr) )
  116. #endif
  117. allocate ( sp_temp(imr,jmr,1) )
  118. allocate ( oro_temp(imr,jmr,1) )
  119. allocate ( gph_temp(imr,jmr,lmr+1) )
  120. else
  121. allocate ( TM5Data%lon(1) )
  122. allocate ( TM5Data%lat(1) )
  123. allocate ( TM5Data%hyai(1) )
  124. allocate ( TM5Data%hybi(1) )
  125. allocate ( TM5Data%hyam(1) )
  126. allocate ( TM5Data%hybm(1) )
  127. allocate ( TM5Data%ps(1,1) )
  128. allocate ( TM5Data%oro(1,1) )
  129. allocate ( TM5Data%t(1,1,1) )
  130. allocate ( TM5Data%ltropo(1,1) )
  131. allocate ( TM5Data%no2(1,1,1) )
  132. allocate ( noxscaling(1,1,1) )
  133. allocate ( store_rm_nox(1,1,1) )
  134. #ifdef slopes
  135. allocate ( store_rxm_nox(1,1,1) )
  136. allocate ( store_rym_nox(1,1,1) )
  137. allocate ( store_rzm_nox(1,1,1) )
  138. #endif
  139. allocate ( sp_temp(1,1,1) )
  140. allocate ( oro_temp(1,1,1) )
  141. allocate ( gph_temp(1,1,1) )
  142. end if
  143. if ( isRoot ) then
  144. ! open rcfile:
  145. call Init( rcF, rcfile, status )
  146. IF_NOTOK_RETURN(status=1)
  147. ! Apply the alternative ODIN HNO3/O3 climatology ?
  148. call ReadRc( rcF, 'domino.doNudgeOdinHNO3', doNudgeOdinHNO3, status, default=.false. )
  149. IF_ERROR_RETURN(status=1)
  150. if ( doNudgeOdinHNO3 ) then
  151. ! Read the .nc file name (path/filename) which contains the ODIN HNO3/O3 climatology
  152. call ReadRc( rcF, 'domino.odinclimatologyfile', OdinHNO3File, status, default='list' )
  153. IF_ERROR_RETURN(status=1)
  154. end if
  155. ! close rcfile:
  156. call Done( rcF, status )
  157. IF_NOTOK_RETURN(status=1)
  158. end if
  159. ! Read the ODIN climatology of HNO3 and O3
  160. if ( doNudgeOdinHNO3 ) then
  161. if ( isRoot ) then
  162. write(gol,'("AssimNO2_interface: initialise ODIN HNO3 climatology")') ; call goPr
  163. ! read the ODIN climatology
  164. call ReadOdinHNO3 ( OdinHNO3File, jmr, lmr, status )
  165. IF_NOTOK_RETURN(status=1)
  166. ! Allocate the memory for the hno3 mass to be adjusted
  167. allocate ( store_rm_hno3(imr,jmr,lmr) )
  168. else ! processor is not "root"
  169. ! Allocate the memory for the hno3 mass to be adjusted
  170. allocate ( store_rm_hno3(1,1,1) )
  171. end if
  172. end if
  173. end subroutine AssimNO2_interface_init
  174. subroutine AssimNO2_interface_done ( )
  175. !======================================================================
  176. !
  177. ! Release storage space for TM5 3D global arrays
  178. ! Henk Eskes, KNMI, March 2015
  179. !======================================================================
  180. ! For printing information
  181. use GO, only : gol, goPr, goErr
  182. ! To identify root proces
  183. use partools, only : isRoot
  184. ! Odin-HNO3 climatology
  185. use MOdinHNO3, only : DoneOdinHNO3
  186. implicit none
  187. character(len=*), parameter :: rname = mname//'/AssimNO2_interface_done'
  188. ! --- start code ---
  189. if ( isRoot ) then
  190. write(gol,'("Assim_interface: deallocate arrays")') ; call goPr
  191. end if
  192. if ( allocated(TM5Data%lon) ) deallocate ( TM5Data%lon )
  193. if ( allocated(TM5Data%lat) ) deallocate ( TM5Data%lat )
  194. if ( allocated(TM5Data%hyai) ) deallocate ( TM5Data%hyai )
  195. if ( allocated(TM5Data%hybi) ) deallocate ( TM5Data%hybi )
  196. if ( allocated(TM5Data%hyam) ) deallocate ( TM5Data%hyam )
  197. if ( allocated(TM5Data%hybm) ) deallocate ( TM5Data%hybm )
  198. if ( allocated(TM5Data%ps) ) deallocate ( TM5Data%ps )
  199. if ( allocated(TM5Data%oro) ) deallocate ( TM5Data%oro )
  200. if ( allocated(TM5Data%t) ) deallocate ( TM5Data%t )
  201. if ( allocated(TM5Data%ltropo) ) deallocate ( TM5Data%ltropo )
  202. if ( allocated(TM5Data%no2) ) deallocate ( TM5Data%no2 )
  203. if ( allocated(noxscaling) ) deallocate ( noxscaling )
  204. if ( allocated(store_rm_nox) ) deallocate ( store_rm_nox )
  205. #ifdef slopes
  206. if ( allocated(store_rxm_nox) ) deallocate ( store_rxm_nox )
  207. if ( allocated(store_rym_nox) ) deallocate ( store_rym_nox )
  208. if ( allocated(store_rzm_nox) ) deallocate ( store_rzm_nox )
  209. #endif
  210. if ( allocated(sp_temp) ) deallocate ( sp_temp )
  211. if ( allocated(oro_temp) ) deallocate ( oro_temp )
  212. if ( allocated(gph_temp) ) deallocate ( gph_temp )
  213. ! ODIN climatology of HNO3 and O3
  214. if ( doNudgeOdinHNO3 ) then
  215. ! Remove ODIN-HNO3 storage
  216. call DoneOdinHNO3 ( )
  217. ! De-allocate storage space of the gathered 3D HNO3 field
  218. if ( allocated(store_rm_hno3) ) deallocate ( store_rm_hno3 )
  219. end if
  220. end subroutine AssimNO2_interface_done
  221. subroutine AssimNO2_interface( rcFile, ntimestep, status )
  222. !======================================================================
  223. !
  224. ! Gather - Assimilate - Scatter
  225. ! Henk Eskes, KNMI, March 2015
  226. !======================================================================
  227. ! Observation vector dimensions:
  228. use tm5_distgrid, only : dgrid, Get_DistGrid, Gather, Scatter
  229. ! NOx tracer indices
  230. use chem_param, only : fscale, ino, ino2, ino3, in2o5, ihno4, inox
  231. use chem_param, only : ihno3, io3
  232. ! Tracer concentrations: transported and chemistry-only
  233. use tracer_data, only : mass_dat, chem_dat
  234. ! Meteo fields
  235. use meteodata, only : temper_dat, oro_dat, sp_dat, m_dat, gph_dat
  236. ! grid/level info
  237. use meteodata, only : global_lli, levi
  238. ! contains "dxyp"
  239. use global_data, only : region_dat
  240. ! For printing information
  241. use GO, only : gol, goPr, goErr
  242. ! To identify root proces
  243. use partools, only : isRoot
  244. ! For computing "dxyp"
  245. use binas, only : ae, grav ! earth radius (m), gravitation constant
  246. use dims, only : dx, dy, gtor, idate
  247. ! Routine to perform an NO2 retrieval + assimilation step
  248. use MAssimilation, only : assimNO2
  249. ! to nudge to ODIN HNO3/O3 climatology
  250. use MOdinHNO3, only : NudgeOdinHNO3
  251. implicit none
  252. real, dimension(:,:,:), allocatable :: tile_no2_field
  253. ! For ODIN climatology nudging of HNO3
  254. real, dimension(:,:,:), allocatable :: tile_o3_field, tile_hno3_field
  255. real, dimension(:,:,:), allocatable :: mixratio_3d_hno3, mixratio_3d_o3
  256. real, dimension(:,:), allocatable :: mixratio_zonal_hno3, mixratio_zonal_o3
  257. character(len=*), intent(in) :: rcfile ! name of rc file
  258. integer, intent(out) :: status
  259. integer, intent(in) :: ntimestep
  260. ! --- local varables ---
  261. character(len=*), parameter :: rname = mname//'/AssimNO2_interface'
  262. integer :: imr, jmr, lmr
  263. integer :: i1, i2, j1, j2, i, j, l, n
  264. integer :: nObs
  265. real :: mix_no, mix_no2, mix_no3, mix_n2o5, mix_hno4, mix_nox_transport
  266. real :: mix_hno3, mix_o3
  267. real :: noxratio, chemnox
  268. real :: dxx, dyy, lat
  269. ! --- start code ---
  270. ! entire region grid size
  271. n = 1 ! global region
  272. imr = global_lli(n)%nlon
  273. jmr = global_lli(n)%nlat
  274. lmr = levi%nlev
  275. if ( isRoot ) then
  276. ! Fill grid and time properties that are not distributed
  277. TM5Data%date(:) = idate(:)
  278. TM5Data%im = imr
  279. TM5Data%jm = jmr
  280. TM5Data%lm = lmr
  281. TM5Data%lon(:) = global_lli(n)%lon_deg(:)
  282. TM5Data%lat(:) = global_lli(n)%lat_deg(:)
  283. TM5Data%hyai(1:lmr+1) = levi%a(0:lmr)
  284. TM5Data%hybi(1:lmr+1) = levi%b(0:lmr)
  285. TM5Data%hyam(1:lmr) = levi%fa(1:lmr)
  286. TM5Data%hybm(1:lmr) = levi%fb(1:lmr)
  287. if ( showDebugPrints ) then
  288. print*,'date ',TM5Data%date
  289. print*,'im, jm, lm ',TM5Data%im,TM5Data%jm,TM5Data%lm
  290. print*,'lon range ',TM5Data%lon(1),TM5Data%lon(imr)
  291. print*,'lat range ',TM5Data%lat(1),TM5Data%lat(jmr)
  292. print*,'hyai range ',TM5Data%hyai(1),TM5Data%hyai(lmr+1)
  293. print*,'hybi range ',TM5Data%hybi(1),TM5Data%hybi(lmr+1)
  294. print*,'hyam range ',TM5Data%hyam(1),TM5Data%hyam(lmr)
  295. print*,'hybm range ',TM5Data%hybm(1),TM5Data%hybm(lmr)
  296. end if
  297. end if
  298. ! *** Gather all arrays needed ***
  299. if ( isRoot ) then
  300. write(gol,'("Assim_interface: Gather NO2, NOx and meteo fields")') ; call goPr
  301. end if
  302. ! First, determine updated NO2 after NOx transport (distributed on all arrays)
  303. ! All NOx species are scaled with the same factor
  304. call Get_DistGrid( dgrid(n), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  305. allocate( tile_no2_field(i1:i2, j1:j2, lmr) )
  306. do l = 1, lmr
  307. do j = j1, j2
  308. do i = i1, i2
  309. ! Get NOx after chemistry from sum of non-transported components
  310. ! "fscale(ispec) = xmair/ra(ispec)"
  311. mix_no = chem_dat(n)%rm(i,j,l,ino) * fscale(ino) / m_dat(n)%data(i,j,l)
  312. mix_no2 = chem_dat(n)%rm(i,j,l,ino2) * fscale(ino2) / m_dat(n)%data(i,j,l)
  313. mix_no3 = chem_dat(n)%rm(i,j,l,ino3) * fscale(ino3) / m_dat(n)%data(i,j,l)
  314. mix_n2o5 = chem_dat(n)%rm(i,j,l,in2o5) * fscale(in2o5) / m_dat(n)%data(i,j,l)
  315. mix_hno4 = chem_dat(n)%rm(i,j,l,ihno4) * fscale(ihno4) / m_dat(n)%data(i,j,l)
  316. ! NOx after chemistry, rescaled with molecule mass
  317. chemnox = mix_no + mix_no2 + mix_no3 + 2.0*mix_n2o5 + mix_hno4
  318. ! NOx after time stepping, rescaled with molecule mass
  319. mix_nox_transport = mass_dat(n)%rm(i,j,l,inox) * fscale(inox) / m_dat(n)%data(i,j,l)
  320. ! Get ratio of transported and non-transported NOx
  321. if ( chemnox > 1.0e-15 ) then
  322. noxratio = mix_nox_transport/chemnox
  323. else
  324. noxratio = 1.0
  325. end if
  326. ! Re-scale NO2 mixing ratio field to concentration after transport
  327. tile_no2_field(i,j,l) = noxratio*mix_no2
  328. if ( showDebugPrints ) then
  329. if (l==1 .and. j==j1 .and. i==295 ) &
  330. print '(a,3i4,f8.4,e13.4)',' i,j,l,nox_ratio,nox = ',i,j,l,noxratio,mix_nox_transport
  331. end if
  332. end do
  333. end do
  334. end do
  335. if ( showDebugPrints ) then
  336. if ( isRoot ) then
  337. print '(a,4i4)','i1, i2, j1, j2 ',i1, i2, j1, j2
  338. print '(a,2e10.3)','fscale no, no2 ',fscale(ino),fscale(ino2)
  339. print '(a,34e10.2)', 'Tile no2 (i2,j2,:) ', tile_no2_field(i2,j2,:)
  340. end if
  341. end if
  342. ! Store NO2 field tiles into global NO2 array (volume mixing ratio)
  343. call Gather( dgrid(n), tile_no2_field, TM5Data%no2, 0, status)
  344. IF_NOTOK_RETURN(status=1)
  345. deallocate( tile_no2_field )
  346. ! *** Nudging to ODIN climatology, gather the zonal means of HNO3 and O3 ***
  347. if ( doNudgeOdinHNO3 ) then
  348. write(gol,'("Assim_interface: compute ODIN HNO3 nudging factors ")') ; call goPr
  349. n = 1
  350. call Get_DistGrid( dgrid(n), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  351. ! allocate the tiles
  352. allocate( tile_hno3_field(i1:i2, j1:j2, lmr) )
  353. allocate( tile_o3_field(i1:i2, j1:j2, lmr) )
  354. do l = 1, lmr
  355. do j = j1, j2
  356. do i = i1, i2
  357. ! Get O3 and HNO3 mixing ratios
  358. ! "fscale(ispec) = xmair/ra(ispec)"
  359. tile_hno3_field(i,j,l) = mass_dat(n)%rm(i,j,l,ihno3) * fscale(ihno3) / m_dat(n)%data(i,j,l)
  360. tile_o3_field(i,j,l) = mass_dat(n)%rm(i,j,l,io3) * fscale(io3) / m_dat(n)%data(i,j,l)
  361. end do
  362. end do
  363. end do
  364. if ( showDebugPrints ) then
  365. if ( isRoot ) then
  366. print '(a,4i4)','i1, i2, j1, j2 ',i1, i2, j1, j2
  367. print '(a,2e10.3)','fscale hno3, o3 ',fscale(ihno3),fscale(io3)
  368. print '(a,34e10.2)', 'Tile hno3 (i2,j2,:) ', tile_hno3_field(i2,j2,:)
  369. print '(a,34e10.2)', 'Tile o3 (i2,j2,:) ', tile_o3_field(i2,j2,:)
  370. end if
  371. end if
  372. ! Allocate the memory for the hno3 / o3 3D mixing ratio fields on root
  373. if ( isRoot ) then
  374. allocate ( mixratio_3d_hno3(imr,jmr,lmr) )
  375. allocate ( mixratio_3d_o3(imr,jmr,lmr) )
  376. else
  377. allocate ( mixratio_3d_hno3(1,1,1) )
  378. allocate ( mixratio_3d_o3(1,1,1) )
  379. end if
  380. ! Store O3, HNO3 field tiles into global arrays (volume mixing ratio)
  381. call Gather( dgrid(n), tile_hno3_field, mixratio_3d_hno3, 0, status)
  382. IF_NOTOK_RETURN(status=1)
  383. call Gather( dgrid(n), tile_o3_field, mixratio_3d_o3, 0, status)
  384. IF_NOTOK_RETURN(status=1)
  385. ! remove the tiles
  386. deallocate( tile_hno3_field )
  387. deallocate( tile_o3_field )
  388. ! Store HNO3 mass field tiles into global HNO3 array (kg)
  389. call Gather( dgrid(n), mass_dat(n)%rm(:,:,:,ihno3), store_rm_hno3, mass_dat(n)%halo, status)
  390. IF_NOTOK_RETURN(status=1)
  391. if ( isRoot ) then
  392. ! Allocate zonal mean arrays
  393. allocate ( mixratio_zonal_hno3(jmr,lmr) )
  394. allocate ( mixratio_zonal_o3(jmr,lmr) )
  395. ! Determine 2D zonal mean mixing ratio fields of HNO3 and O3
  396. do l = 1, lmr
  397. do j = 1, jmr
  398. mixratio_zonal_hno3(j,l) = 0.0
  399. mixratio_zonal_o3(j,l) = 0.0
  400. do i = 1, imr
  401. mixratio_zonal_hno3(j,l) = mixratio_zonal_hno3(j,l) + mixratio_3d_hno3(i,j,l)
  402. mixratio_zonal_o3(j,l) = mixratio_zonal_o3(j,l) + mixratio_3d_o3(i,j,l)
  403. end do
  404. mixratio_zonal_hno3(j,l) = mixratio_zonal_hno3(j,l) /imr
  405. mixratio_zonal_o3(j,l) = mixratio_zonal_o3(j,l) / imr
  406. end do
  407. end do
  408. if ( showDebugPrints ) then
  409. print '(a,3i4,i5,5i3,i6)', 'assim_interf: imr, jmr, lmr, idate, timestep = ', imr, jmr, lmr, idate, ntimestep
  410. print '(a,34e10.2)', 'assim_interf: mixratio_zonal_hno3 j 120 = ',mixratio_zonal_hno3(120,:)
  411. print '(a,34e10.2)', 'assim_interf: mixratio_zonal_o3 j 120 = ',mixratio_zonal_o3(120,:)
  412. print '(a,34e10.2)', 'assim_interf: store_rm_hno3 i 1 j 120 = ',store_rm_hno3(1,120,:)
  413. print '(a)', 'assim_interf: calling NudgeOdinHNO3'
  414. end if
  415. ! Determine scaled HNO3 field
  416. call NudgeOdinHNO3 ( imr, jmr, lmr, idate, ntimestep, mixratio_zonal_hno3, mixratio_zonal_o3, store_rm_hno3 )
  417. ! Remove zonal mean arrays
  418. deallocate ( mixratio_zonal_hno3 )
  419. deallocate ( mixratio_zonal_o3 )
  420. end if ! isRoot
  421. ! release storage of the 3D mixing ratio fields
  422. deallocate ( mixratio_3d_hno3 )
  423. deallocate ( mixratio_3d_o3 )
  424. end if ! doNudgeOdinHNO3
  425. ! *** Gather other TM5 fields needed ***
  426. ! Store NOx mass field tiles into global NOx array (kg)
  427. call Gather( dgrid(n), mass_dat(n)%rm(:,:,:,inox), store_rm_nox, mass_dat(n)%halo, status)
  428. IF_NOTOK_RETURN(status=1)
  429. ! Same for the slopes
  430. #ifdef slopes
  431. call Gather( dgrid(n), mass_dat(n)%rxm(:,:,:,inox), store_rxm_nox, mass_dat(n)%halo, status)
  432. IF_NOTOK_RETURN(status=1)
  433. call Gather( dgrid(n), mass_dat(n)%rym(:,:,:,inox), store_rym_nox, mass_dat(n)%halo, status)
  434. IF_NOTOK_RETURN(status=1)
  435. call Gather( dgrid(n), mass_dat(n)%rzm(:,:,:,inox), store_rzm_nox, mass_dat(n)%halo, status)
  436. IF_NOTOK_RETURN(status=1)
  437. #endif
  438. ! Surface pressure (Pa): sp(imr,jmr,1)
  439. call Gather( dgrid(n), sp_dat(n)%data, sp_temp, sp_dat(n)%halo, status)
  440. IF_NOTOK_RETURN(status=1)
  441. ! Orography (m2/s2): oro(imr,jmr,1), divide by "g" for meters
  442. call Gather( dgrid(n), oro_dat(n)%data, oro_temp, oro_dat(n)%halo, status)
  443. IF_NOTOK_RETURN(status=1)
  444. ! Temperature field (K): temper(imr,jmr,lmr)
  445. call Gather( dgrid(n), temper_dat(n)%data, TM5Data%t, temper_dat(n)%halo, status)
  446. IF_NOTOK_RETURN(status=1)
  447. ! Geopotential height (m): gph(imr,jmr,lmr+1)
  448. call Gather( dgrid(n), gph_dat(n)%data, gph_temp, gph_dat(n)%halo, status)
  449. IF_NOTOK_RETURN(status=1)
  450. if ( isRoot ) then
  451. ! Store surface pressure
  452. TM5Data%ps(:,:) = sp_temp(:,:,1)
  453. ! Store model orography
  454. TM5Data%oro(:,:) = oro_temp(:,:,1)/grav
  455. ! Determine tropopause level and store
  456. do i = 1, imr
  457. do j = 1, jmr
  458. TM5Data%ltropo(i,j) = ltropo(lmr,TM5Data%hyai,TM5Data%hybi,TM5Data%t(i,j,:),gph_temp(i,j,:))
  459. end do
  460. end do
  461. ! Initialise assimilation scaling factor
  462. noxscaling(:,:,:) = 1.0
  463. ! *** Call the assimilation ***
  464. ! Assimilation is done only on the root processor
  465. if ( showDebugPrints ) then
  466. i = 350
  467. j = 120
  468. print '(a,i4,a,i4,a)', "Gathered data for cell (",i,", ",j,":, 1) "
  469. print '(a,10e9.2)', " NO2 ", TM5Data%no2(i, j:j+9, 1)
  470. print '(a,10e9.2)', " NOx ", store_rm_nox(i, j:j+9, 1)
  471. print '(a,10e9.2)', " NOx slope x ", store_rxm_nox(i, j:j+9, 1)
  472. print '(a,10e9.2)', " NOx slope y ", store_rym_nox(i, j:j+9, 1)
  473. print '(a,10e9.2)', " NOx slope z ", store_rzm_nox(i, j:j+9, 1)
  474. print '(a,10f9.1)', " temp ", TM5Data%t(i, j:j+9, 1)
  475. print '(a,10f9.1)', " oro ", TM5Data%oro(i, j:j+9)
  476. print '(a,180i3)' , " ltropo_lat ", TM5Data%ltropo(i, 1:180)
  477. print '(a,180i3)' , " ltropo_lon ", TM5Data%ltropo(1:360, j)
  478. print '(a,180f5.0)', " ptropo ", TM5Data%hyai(TM5Data%ltropo(i, 1:180))*0.01+TM5Data%hybi(TM5Data%ltropo(i, 1:180))*1013.0
  479. print '(a,35f6.0)', " plevs ", TM5Data%hyai(:)*0.01+TM5Data%hybi(:)*1013.0
  480. print '(a,10f9.0)', " sp ", TM5Data%ps(i, j:j+9)*0.01
  481. end if
  482. write(gol,'("Assim_interface: Fields have been gathered, now calling assimNO2")') ; call goPr
  483. call assimNO2( rcFile, ntimestep, TM5Data, nObs, noxscaling, status )
  484. IF_NOTOK_RETURN(status=1)
  485. if ( nObs > 0 ) then
  486. ! *** Finally, scatter the analysis NOx field ***
  487. write(gol,'("Assim_interface: Update NOx field, slopes, and scatter")') ; call goPr
  488. ! Apply assimilation scaling to NOx (only) ...
  489. store_rm_nox(:,:,:) = store_rm_nox(:,:,:) * noxscaling(:,:,:)
  490. ! Scale also slopes
  491. #ifdef slopes
  492. store_rxm_nox(:,:,:) = store_rxm_nox(:,:,:) * noxscaling(:,:,:)
  493. store_rym_nox(:,:,:) = store_rym_nox(:,:,:) * noxscaling(:,:,:)
  494. store_rzm_nox(:,:,:) = store_rzm_nox(:,:,:) * noxscaling(:,:,:)
  495. #endif
  496. end if ! nObs > 0
  497. end if ! isRoot
  498. ! ... and scatter NOx back to the MPI tiles
  499. call Scatter( dgrid(n), mass_dat(n)%rm(:,:,:,inox), store_rm_nox, &
  500. mass_dat(n)%halo, status)
  501. IF_NOTOK_RETURN(status=1)
  502. #ifdef slopes
  503. call Scatter( dgrid(n), mass_dat(n)%rxm(:,:,:,inox), store_rxm_nox, &
  504. mass_dat(n)%halo, status)
  505. IF_NOTOK_RETURN(status=1)
  506. call Scatter( dgrid(n), mass_dat(n)%rym(:,:,:,inox), store_rym_nox, &
  507. mass_dat(n)%halo, status)
  508. IF_NOTOK_RETURN(status=1)
  509. call Scatter( dgrid(n), mass_dat(n)%rzm(:,:,:,inox), store_rzm_nox, &
  510. mass_dat(n)%halo, status)
  511. IF_NOTOK_RETURN(status=1)
  512. #endif
  513. ! *** Scatter result of the HNO3 nudging to ODIN climatology ***
  514. if ( doNudgeOdinHNO3 ) then
  515. write(gol,'("Assim_interface: now scattering updated HNO3 concentration (ODIN nudging) ")') ; call goPr
  516. call Scatter( dgrid(n), mass_dat(n)%rm(:,:,:,ihno3), store_rm_hno3, &
  517. mass_dat(n)%halo, status)
  518. IF_NOTOK_RETURN(status=1)
  519. end if
  520. end subroutine AssimNO2_interface
  521. !-----------------------------------------------------------------------
  522. ! TM5 !
  523. !-----------------------------------------------------------------------
  524. !BOP
  525. !
  526. ! !FUNCTION: ltropo
  527. !
  528. ! !DESCRIPTION: determine tropopause level from temperature gradient
  529. ! reference: WMO /Bram Bregman
  530. !\\
  531. !\\
  532. ! !INTERFACE:
  533. !
  534. integer function ltropo(lmx,at,bt,tx,gphx)
  535. !
  536. ! !INPUT PARAMETERS:
  537. !
  538. integer,intent(in) :: lmx
  539. real,dimension(lmx+1), intent(in) :: at, bt
  540. real,dimension(lmx),intent(in) :: tx
  541. real,dimension(lmx+1),intent(in) :: gphx
  542. !
  543. ! !REVISION HISTORY:
  544. ! programmed by fd 01-11-1996
  545. ! changed to function fd 12-07-2002
  546. ! 16 Jul 2010 - Achim Strunk -
  547. !
  548. ! !REMARKS:
  549. !
  550. !EOP
  551. !------------------------------------------------------------------------
  552. !BOC
  553. integer :: ltmin,ltmax,l
  554. real :: dz,dt
  555. ! ltropo is highest tropospheric level
  556. ! above is defined as stratosphere
  557. ! min tropopause level 450 hPa (ca. 8 km)
  558. ltmin=lvlpress(lmx,at,bt,45000.,98400.)
  559. ! max tropopause level 70 hPa (ca. 20 km)
  560. ltmax=lvlpress(lmx,at,bt,7000.,98400.)
  561. ltropo=ltmin
  562. do l=ltmin,ltmax
  563. dz=(gphx(l)-gphx(l-2))/2.
  564. dt=(tx(l)-tx(l-1))/dz
  565. if ( dt < -0.002) ltropo=l !wmo 85 criterium for stratosphere
  566. ! increase upper tropospheric level
  567. end do !l
  568. end function ltropo
  569. !EOC
  570. !---------------------------------------------------------------------------
  571. ! TM5 !
  572. !---------------------------------------------------------------------------
  573. !BOP
  574. !
  575. ! !FUNCTION: lvlpress
  576. !
  577. ! !DESCRIPTION: lvlpress determines the index of the level with a pressure
  578. ! greater than press i.e. in height below press
  579. ! determines level independent of vertical resolution lm
  580. ! uses hybrid level coefficients to determine lvlpress
  581. !\\
  582. !\\
  583. ! !INTERFACE:
  584. !
  585. integer function lvlpress(lm,at,bt,press,press0)
  586. !
  587. ! !INPUT PARAMETERS:
  588. !
  589. integer, intent(in) :: lm
  590. real, dimension(lm+1), intent(in) :: at, bt
  591. real, intent(in) :: press
  592. real, intent(in) :: press0
  593. !
  594. ! !REVISION HISTORY:
  595. ! programmed by Peter van Velthoven, 6-november-2000
  596. ! 16 Jul 2010 - Achim Strunk -
  597. !
  598. ! !REMARKS:
  599. !
  600. !EOP
  601. !------------------------------------------------------------------------
  602. !BOC
  603. real :: zpress0, zpress
  604. integer :: l,lvl
  605. if ( press0 == 0.0 ) then
  606. zpress0 = 98400.
  607. else
  608. zpress0 = press0
  609. endif
  610. lvl = 1
  611. ! l increases from bottom (l=1) to top (l=lm)
  612. do l = 1, lm
  613. zpress = (at(l)+at(l+1) + (bt(l)+bt(l+1))*zpress0)*0.5
  614. if ( press < zpress ) then
  615. lvl = l
  616. endif
  617. end do
  618. lvlpress = lvl
  619. end function lvlpress
  620. !EOC
  621. end module assim_interf_mod