MOdinHNO3.F90 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. ! First include the set of model-wide compiler flags
  2. #include "tm5.inc"
  3. ! macro
  4. #define TRACEBACK write (gol,'("in ",a," (",a,i6,")")') rname, __FILE__, __LINE__ ; call goErr
  5. #define IF_NOTOK_RETURN if (status/=0) then; TRACEBACK; return; end if
  6. #define IF_ERROR_RETURN if (status> 0) then; TRACEBACK; return; end if
  7. ! First include the set of model-wide compiler flags
  8. ! #include "tm5.inc"
  9. ! The ODIN LUT netcdf file contains:
  10. !
  11. ! netcdf odin_hno3_o3_ratio {
  12. ! dimensions:
  13. ! nmonth = 12 ;
  14. ! nlat = 180 ;
  15. ! npres = 58 ;
  16. ! nprestm5 = 6 ;
  17. ! variables:
  18. ! float month(nmonth) ;
  19. ! month:long_name = "index of the month" ;
  20. ! month:units = "-" ;
  21. ! float latitude(nlat) ;
  22. ! latitude:long_name = "latitudes" ;
  23. ! latitude:units = "degrees north" ;
  24. ! float pressure(npres) ;
  25. ! pressure:long_name = "pressure" ;
  26. ! pressure:units = "hPa" ;
  27. ! float pressure_tm5(nprestm5) ;
  28. ! pressure_tm5:long_name = "pressure at the bottom of the TM5 layer" ;
  29. ! pressure_tm5:units = "hPa" ;
  30. ! float layerindex_tm5(nprestm5) ;
  31. ! layerindex_tm5:long_name = "index of the TM5 layer (between 1 and 34)" ;
  32. ! layerindex_tm5:units = "-" ;
  33. ! float hno3_o3_ratio(nmonth, nlat, npres) ;
  34. ! hno3_o3_ratio:long_name = "hno3/o3 ratio" ;
  35. ! hno3_o3_ratio:units = "ppm/ppm" ;
  36. ! float hno3_o3_ratio_tm5(nmonth, nlat, nprestm5) ;
  37. ! hno3_o3_ratio_tm5:long_name = "hno3/o3 ratio integrated over the TM5 layers (34 layer model version)" ;
  38. ! hno3_o3_ratio_tm5:units = "ppm/ppm" ;
  39. ! float hno3(nmonth, nlat, npres) ;
  40. ! hno3:long_name = "mole_fraction_of_hno3_in_air" ;
  41. ! hno3:units = "mole/mole" ;
  42. ! float o3(nmonth, nlat, npres) ;
  43. ! o3:long_name = "mole_fraction_of_ozone_in_air" ;
  44. ! o3:units = "mole/mole" ;
  45. !
  46. ! pressure_tm5 = 60.18, 39.603, 16.806, 7.132, 2.985, 0.956 ;
  47. ! layerindex_tm5 = 29, 30, 31, 32, 33, 34 ;
  48. !
  49. module MOdinHNO3
  50. !
  51. ! Module to load the ODIN climatologies of O3 and HNO3
  52. !
  53. ! subroutine ReadOdinHNO3
  54. !
  55. ! Henk Eskes, KNMI, May 2016
  56. use GO, only : gol, goErr
  57. implicit none
  58. private
  59. public :: ReadOdinHNO3, NudgeOdinHNO3, DoneOdinHNO3
  60. ! Type definition for the ODIN data
  61. type TOdinHNO3
  62. integer :: npresTM5 ! nr of TM5 layers on which the climatology is defined
  63. integer :: nmonth ! nr of months
  64. integer :: nlat ! nr of latitudes
  65. real, dimension(:), allocatable :: latitudes ! the climatology
  66. real, dimension(:), allocatable :: pressure_tm5 ! the pressures
  67. integer, dimension(:), allocatable :: layerindex_tm5 ! the TM5 layer index
  68. real, dimension(:,:,:), allocatable :: hno3_o3_ratio_tm5 ! the climatology for TM5 layers
  69. end type TOdinHNO3
  70. ! Permanent storage for the ODIN data
  71. type(TOdinHNO3) :: OdinHNO3
  72. ! Nudging time scales in days
  73. ! real, dimension(6), parameter :: nudgingTime = (/ 0.0417, 0.0417, 0.0417, 0.0417, 0.0417, 0.0417 /) ! 1 hour
  74. ! real, dimension(6), parameter :: nudgingTime = (/ 0.25, 0.25, 0.25, 0.25, 0.25, 0.1 /) ! 6 hours
  75. real, dimension(6), parameter :: nudgingTime = (/ 120.0, 60.0, 30.0, 7.0, 2.0, 1.0 /)
  76. ! applied to pressure layers = 60.2, 39.6, 16.8, 7.1, 3.0, 1.0 hPa
  77. character(len=*), parameter :: mname = 'MOdinHNO3Read'
  78. ! for debug output to screen
  79. logical, parameter :: showDebugPrints = .true.
  80. contains
  81. subroutine NudgeOdinHNO3 ( im, jm, lm, idate, tstep, mixratio_zonal_hno3, mixratio_zonal_o3, rm_hno3 )
  82. !=======================================================================
  83. !
  84. ! Determine scaled HNO3 field based on ODIN climatology
  85. !
  86. ! input:
  87. ! im = nr of TM5 longitudes
  88. ! jm = nr of TM5 latitudes
  89. ! lm = nr of TM5 layers (climatol only defined for lm=34)
  90. ! idate = current date-time
  91. ! tstep = time step in seconds (integer)
  92. ! mixratio_zonal_hno3 = zonal-mean hno3 mixing ratio in TM5
  93. ! mixratio_zonal_o3 = zonal-mean ozone mixing ratio in TM5
  94. ! input/output:
  95. ! rm_hno3 = HNO3 mass in TM5
  96. !
  97. ! The routine will allocate the arrays in "OdinHNO3",
  98. ! using the dimensions in the file
  99. ! Henk Eskes, KNMI, May 2016
  100. !=======================================================================
  101. implicit none
  102. ! in/out
  103. integer, intent(in) :: im, jm, lm
  104. integer, intent(in) :: tstep
  105. integer, dimension(6), intent(in) :: idate
  106. real, dimension(jm,lm), intent(in) :: mixratio_zonal_hno3
  107. real, dimension(jm,lm), intent(in) :: mixratio_zonal_o3
  108. real, dimension(im,jm,lm), intent(inout) :: rm_hno3
  109. ! local
  110. integer :: i, j, l, lOdin
  111. real :: c, tfac, expfac, ratio_model, ratio_odin_intp, ratio
  112. integer :: month, month_other
  113. real :: fraction_othermonth, fraction_thismonth
  114. ! start code
  115. ! determine time interpolation factors between 2 months
  116. month = idate(2)
  117. month_other = month
  118. fraction_thismonth = 1.0
  119. fraction_othermonth = 0.0
  120. if ( idate(3) .lt. 10 ) then
  121. month_other = month - 1
  122. if ( month_other < 1 ) month_other = 12
  123. fraction_othermonth = ( 10.0 - real(idate(3)) ) / 19.0
  124. fraction_thismonth = 1.0 - fraction_othermonth
  125. end if
  126. if ( idate(3) .gt. 20 ) then
  127. month_other = month + 1
  128. if ( month_other > 12 ) month_other = 1
  129. fraction_othermonth = (real(idate(3))-20.0) / 22.0
  130. fraction_thismonth = 1.0 - fraction_othermonth
  131. end if
  132. ! nudge HNO3 field to ratio of ODIN HNO3/O3 climatology using the zonal mean
  133. do lOdin = 1, OdinHNO3%npresTM5
  134. tfac = real(tstep) / (nudgingTime(lOdin)*3600.0*24.0) ! nudgingTime in days, tstep in seconds
  135. expfac = exp(-1.0*tfac)
  136. do j = 1, jm
  137. l = OdinHNO3%layerindex_tm5(lOdin)
  138. ratio_odin_intp = fraction_thismonth * OdinHNO3%hno3_o3_ratio_tm5(l,j,month) + &
  139. fraction_othermonth * OdinHNO3%hno3_o3_ratio_tm5(l,j,month_other)
  140. ratio_model = mixratio_zonal_hno3(j,l) / mixratio_zonal_o3(j,l)
  141. ratio = ratio_odin_intp/ratio_model
  142. c = ratio - expfac*(ratio_odin_intp-ratio_model)/ratio_model
  143. if ( showDebugPrints ) then
  144. if ( j == 120 ) then
  145. if ( lOdin == 1 ) print '(a,i5,5i3)', 'idate = ',idate
  146. print *, ''
  147. print '(a,5i4,f8.3)', 'j, l, lOdin, month, month_other, pres = ',j, l, lOdin, month, month_other, OdinHNO3%pressure_tm5(lOdin)
  148. print '(a,4e12.3)', 'Odin: intp, month, other, fraction_thismonth = ',ratio_odin_intp,Odinhno3%hno3_o3_ratio_tm5(l,j,month),OdinHNO3%hno3_o3_ratio_tm5(l,j,month_other), fraction_thismonth
  149. print '(a,3e12.3)', 'hno3/o3, hno3, o3 = ', mixratio_zonal_hno3(j,l)/mixratio_zonal_o3(j,l) , mixratio_zonal_hno3(j,l), mixratio_zonal_o3(j,l)
  150. print '(a,f10.5,f7.0,f10.6,f7.1,f10.6)', 'ratio, tstep, tfac, nudgingTime, multfactor = ',ratio, real(tstep), tfac, nudgingTime(lOdin), c
  151. end if
  152. end if
  153. ! multiply all zonal values with the same correction factor
  154. do i = 1, im
  155. rm_hno3(i,j,l) = rm_hno3(i,j,l) * c
  156. end do
  157. end do
  158. end do
  159. if ( showDebugPrints ) then
  160. print *, ' '
  161. print '(a,6f8.3)', 'nudging times = ',nudgingTime
  162. print '(a,4e12.3)', 'min/max of hno3, o3 = ', minval(mixratio_zonal_hno3(:,:)), maxval(mixratio_zonal_hno3(:,:)), minval(mixratio_zonal_o3(:,:)), maxval(mixratio_zonal_o3(:,:))
  163. end if
  164. end subroutine NudgeOdinHNO3
  165. subroutine ReadOdinHNO3 ( OdinHNO3File, jm, lm, status )
  166. !=======================================================================
  167. !
  168. ! ReadOdinHNO3: read ODIN climatology of [HNO3]/[O3]
  169. ! as a function of the month and the TM5 layer
  170. ! (lookup table created by Henk Eskes, KNMI, April 2016)
  171. !
  172. ! input:
  173. ! OdinHNO3File = path+name of the file containing the ODIN Climatology
  174. ! jm = nr of TM5 latitudes
  175. ! lm = nr of TM5 layers (climatol only defined for lm=34)
  176. ! output:
  177. ! status = status ( 0 means OK )
  178. !
  179. ! The routine will allocate the arrays in "OdinHNO3",
  180. ! using the dimensions in the file
  181. ! Henk Eskes, KNMI, May 2016
  182. !=======================================================================
  183. use MDF, only : MDF_Open, MDF_NETCDF, MDF_READ
  184. use MDF, only : MDF_Inq_VarID, MDF_Get_Var, MDF_Close
  185. use MDF, only : MDF_Inquire_Dimension, MDF_Inq_DimID
  186. implicit none
  187. ! in/out
  188. character(*), intent(in) :: OdinHNO3File
  189. integer, intent(in) :: jm, lm
  190. integer, intent(out) :: status
  191. ! local
  192. character(len=*), parameter :: rname = mname//'/ReadOdinHNO3'
  193. integer :: fid
  194. integer :: dimid, id_lat, id_pres, id_ind, id_hno3
  195. integer, dimension(:), allocatable :: dphi_int, psurf_int
  196. real :: amfGeo
  197. ! start code
  198. status = 0
  199. call MDF_Open( trim(OdinHNO3File), MDF_NETCDF, MDF_READ, fid, status )
  200. IF_NOTOK_RETURN
  201. ! get the dimensions
  202. call MDF_Inq_DimID( fid, 'nmonth', dimid, status )
  203. IF_NOTOK_RETURN
  204. call MDF_Inquire_Dimension( fid, dimid, status, length=OdinHNO3%Nmonth )
  205. IF_NOTOK_RETURN
  206. call MDF_Inq_DimID( fid, 'nlat', dimid, status )
  207. IF_NOTOK_RETURN
  208. call MDF_Inquire_Dimension( fid, dimid, status, length=OdinHNO3%nlat )
  209. IF_NOTOK_RETURN
  210. call MDF_Inq_DimID( fid, 'nprestm5', dimid, status )
  211. IF_NOTOK_RETURN
  212. call MDF_Inquire_Dimension( fid, dimid, status, length=OdinHNO3%nprestm5 )
  213. IF_NOTOK_RETURN
  214. print '(a,3i4)', 'ReadOdinHNO3, array dimensions (pressure,lat,month) = ', OdinHNO3%nprestm5, OdinHNO3%nlat, OdinHNO3%nmonth
  215. ! Allocate storage space
  216. allocate ( OdinHNO3%latitudes(OdinHNO3%nlat) )
  217. allocate ( OdinHNO3%pressure_tm5(OdinHNO3%nprestm5) )
  218. allocate ( OdinHNO3%layerindex_tm5(OdinHNO3%nprestm5) )
  219. allocate ( OdinHNO3%hno3_o3_ratio_tm5(OdinHNO3%nprestm5, OdinHNO3%nlat, OdinHNO3%nmonth) )
  220. ! Define variables
  221. CALL MDF_Inq_VarID( fid, 'latitude', id_lat, status )
  222. IF_ERROR_RETURN
  223. CALL MDF_Inq_VarID( fid, 'pressure_tm5', id_pres, status )
  224. IF_ERROR_RETURN
  225. CALL MDF_Inq_VarID( fid, 'layerindex_tm5', id_ind, status )
  226. IF_ERROR_RETURN
  227. CALL MDF_Inq_VarID( fid, 'hno3_o3_ratio_tm5', id_hno3, status )
  228. IF_ERROR_RETURN
  229. ! Read variables
  230. CALL MDF_Get_Var( fid, id_lat, OdinHNO3%latitudes, status ) ! latitudes
  231. IF_NOTOK_RETURN
  232. CALL MDF_Get_Var( fid, id_pres, OdinHNO3%pressure_tm5, status ) ! pressures
  233. IF_NOTOK_RETURN
  234. CALL MDF_Get_Var( fid, id_ind, OdinHNO3%layerindex_tm5, status ) ! TM5 layer indices
  235. IF_NOTOK_RETURN
  236. CALL MDF_Get_Var( fid, id_hno3, OdinHNO3%hno3_o3_ratio_tm5, status ) ! HNO3 / O3 ratios at the TM5 layers
  237. IF_NOTOK_RETURN
  238. ! Close file
  239. CALL MDF_Close( fid, status )
  240. IF_NOTOK_RETURN
  241. ! check if this version of TM5 is consistent with the climatology
  242. if ( (jm /= OdinHNO3%nlat) .or. (lm /= OdinHNO3%layerindex_tm5(OdinHNO3%nprestm5)) ) then
  243. status = -1
  244. print *, 'ReadOdinHNO3: ERROR dimensions incorrect'
  245. print *, ' TM5 jm, lm = ',jm,lm
  246. print *, ' ODIN climatol jm, lm = ',OdinHNO3%nlat,OdinHNO3%layerindex_tm5(OdinHNO3%nprestm5)
  247. IF_NOTOK_RETURN
  248. end if
  249. if ( showDebugPrints ) then
  250. print '(a,2f8.2)', 'ReadOdinHNO3, lat range = ',OdinHNO3%latitudes(1),OdinHNO3%latitudes(OdinHNO3%nlat)
  251. print '(a,6f10.4)', 'ReadOdinHNO3, press = ',OdinHNO3%pressure_tm5
  252. print '(a,6i4)', 'ReadOdinHNO3, index = ',OdinHNO3%layerindex_tm5
  253. print '(a,6e12.3)', 'ReadOdinHNO3, hno3/o3, month 12, lat 120 = ',OdinHNO3%hno3_o3_ratio_tm5(:,120,12)
  254. end if
  255. end subroutine ReadOdinHNO3
  256. subroutine DoneOdinHNO3 ( )
  257. !
  258. ! Deallocate arrays
  259. !
  260. implicit none
  261. ! De-allocate storage space of the ODIN climatology
  262. if ( allocated ( OdinHNO3%latitudes ) ) deallocate ( OdinHNO3%latitudes )
  263. if ( allocated ( OdinHNO3%pressure_tm5 ) ) deallocate ( OdinHNO3%pressure_tm5 )
  264. if ( allocated ( OdinHNO3%layerindex_tm5 ) ) deallocate ( OdinHNO3%layerindex_tm5 )
  265. if ( allocated ( OdinHNO3%hno3_o3_ratio_tm5 ) ) deallocate ( OdinHNO3%hno3_o3_ratio_tm5 )
  266. end subroutine DoneOdinHNO3
  267. end module MOdinHNO3