optics.F90 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705
  1. #define TRACEBACK write (gol,'("in ",a," (",a,i6,")")') rname, __FILE__, __LINE__ ; call goErr
  2. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  3. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  4. !
  5. #include "tm5.inc"
  6. !
  7. !-----------------------------------------------------------------------------
  8. ! TM5 !
  9. !-----------------------------------------------------------------------------
  10. !BOP
  11. !
  12. ! !MODULE: OPTICS
  13. !
  14. ! !DESCRIPTION: Optics module to calculate optical depth from m7 output,
  15. ! based on the AOP_Package op Michael Kahnert.
  16. !
  17. ! The optics code should be used in the following way (see
  18. ! examples in photolysis.F90, ecearth_optics.F90, and
  19. ! user_output_aerocom.F90):
  20. !
  21. ! 1) prepare the optics calculation by calling
  22. ! 'OPTICS_INIT' --> lookuptables etc.
  23. ! this routine reads the wavelengths, lookupable and calculates
  24. ! refr. indices at these wavelengths.
  25. !
  26. ! 2) allocate AOP arrays aop_out_ext/a/g with
  27. ! (n_gridcells, n_wavelengths, n_split), with:
  28. ! 'n_split' = 1 for (split == .false.) or
  29. ! 'n_split' = 11 for (split == .true. ), ie.
  30. ! partial contributions by
  31. ! Total, SO4, BC, OC, SS, DU, NO3, Water, Fine, Fine Dust, Fine SS
  32. ! additional fields are also provided for split==.true. in
  33. ! aop_out_add, which has to have size
  34. ! (n_gridcells, n_wavelengths, n_add) with nadd = 2 for
  35. ! surface PM10 dry extinction and surface PM10 dry absorption
  36. ! 3) Compute AOP for current conditions by calling 'OPTICS_AOP_GET'
  37. ! 4) done: 'OPTICS_DONE'
  38. !
  39. ! IMPORTANT: *) Skipped the ZOOM options! (temporary)
  40. ! *) OC is actually POM. Remember converting OC to POM
  41. ! when sending it to optics_calculate_aop
  42. !\\
  43. !\\
  44. ! !INTERFACE:
  45. !
  46. MODULE OPTICS
  47. !
  48. ! !USES:
  49. !
  50. use GO, only : gol, goErr, goPr
  51. Use mo_aero_m7, only : nmod
  52. Use global_data, only : rcfile
  53. use GO, only : TrcFile, Init, Done, ReadRc
  54. Use Dims, only : nregions
  55. IMPLICIT NONE
  56. PRIVATE
  57. !
  58. ! !PUBLIC MEMBER FUNCTIONS:
  59. !
  60. public :: optics_init, optics_done ! init/done methods for a wavelendep object
  61. public :: optics_aop_get ! compute aerosol optical properties
  62. !
  63. ! !PRIVATE DATA MEMBERS:
  64. !
  65. type(TrcFile) :: rcF
  66. character(len=256) :: lookuptable, refractive_indices
  67. !
  68. ! !PUBLIC TYPES:
  69. !
  70. ! wavelength type (to be used by methods using the optics)
  71. type, public :: wavelendep
  72. real :: wl ! user requested wavelength unit = um (e.g. 0.550)
  73. real, dimension(7) :: n ! SO4, BC, OC, SOA, SS, DU, WATER
  74. real, dimension(7) :: k ! SO4, BC, OC, SOA, SS, DU, WATER
  75. logical :: split, insitu
  76. end type wavelendep
  77. !
  78. ! !PRIVATE TYPES:
  79. !
  80. ! AOP input type and field
  81. type aopi
  82. real, dimension(nmod) :: SO4, NO3, BC, OC, SOA, SS, DU, H2O, numdens, rg, rgd
  83. end type aopi
  84. type(aopi), dimension(:), allocatable :: aop_in
  85. ! characteristics of the lookup-tables
  86. integer, parameter :: n_rii = 15
  87. integer, parameter :: n_rir = 40
  88. integer, parameter :: n_x = 100
  89. real,dimension(n_rii) :: lkval ! -log img part refr. index
  90. real,dimension(n_rii) :: kval ! img part refr. index, 10^(-lkval)
  91. real,dimension(n_rir) :: n1r ! real part refr. index
  92. Real, Dimension(n_x) :: xs
  93. Real, Dimension(n_x,n_rir,n_rii),Target :: cext_159, a_159, g_159
  94. real, dimension(n_x,n_rir,n_rii),Target :: cext_200, a_200, g_200
  95. character(len=*), parameter :: mname = 'Optics'
  96. ! lookup table information for interpolation to wavelength properties
  97. Integer, Parameter :: opacdim = 61 ! Wavelength dimension of OPAC data
  98. Integer, Parameter :: echamhamdim = 49 ! Wavelength dimension of ECHAM-HAM data
  99. Integer, Parameter :: segelsteindim = 1261 ! Wavelength dimension of Segelstein data
  100. Real, Dimension(:,:), allocatable :: opac, echamham, segelstein
  101. !
  102. ! !REVISION HISTORY:
  103. ! Implemented by Maarten Krol 03/2009
  104. ! Extended by Joost Aan de Brugh
  105. !
  106. ! 6 Feb 2011 - Achim Strunk - complete revision
  107. ! - worked on DECOUPLING optics routines
  108. ! from (optics)_output, in order to
  109. ! (re)establish a flexible way of using it
  110. ! - remaining parts have been moved to
  111. ! (the new routine) user_output_optics
  112. !
  113. ! 24 Jun 2011 - Achim Strunk - added NO3 explicitly in order to allow
  114. ! for a slightly better split of the
  115. ! optical properties of (SO4+NO3)
  116. ! 20 Jun 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  117. !
  118. ! !REMARKS:
  119. !
  120. !EOP
  121. !------------------------------------------------------------------------
  122. CONTAINS
  123. !--------------------------------------------------------------------------
  124. ! TM5 !
  125. !--------------------------------------------------------------------------
  126. !BOP
  127. !
  128. ! !IROUTINE: OPTICS_INIT
  129. !
  130. ! !DESCRIPTION: Initialize a wavelendep object: Input/lookuptables are
  131. ! opened and read in, and wavelength dependent parameters are
  132. ! calculated.
  133. !\\
  134. !\\
  135. ! !INTERFACE:
  136. !
  137. SUBROUTINE OPTICS_INIT( nwav, wdep, status )
  138. !
  139. ! !USES:
  140. !
  141. USE MDF, ONLY : MDF_OPEN, MDF_NETCDF, MDF_READ, MDF_Get_Var, MDF_Close, MDF_Inq_VarID
  142. !
  143. ! !INPUT PARAMETERS:
  144. !
  145. integer, intent(in) :: nwav
  146. !
  147. ! !OUTPUT PARAMETERS:
  148. !
  149. type(wavelendep), dimension(nwav), intent(inout) :: wdep
  150. integer, intent(out) :: status
  151. !
  152. ! !REMARKS: read by each core (FIXME?)
  153. !
  154. !EOP
  155. !------------------------------------------------------------------------
  156. !BOC
  157. integer :: fid, varid, i
  158. character(len=*), parameter :: rname = mname//'/Optics_Init'
  159. ! --- begin --------------------------------
  160. allocate( opac (7, opacdim ) )
  161. allocate( echamham (5, echamhamdim ) )
  162. allocate( segelstein(3, segelsteindim) )
  163. ! get filenames from rcfile
  164. call Init( rcF, rcfile, status )
  165. IF_NOTOK_RETURN(status=1)
  166. call ReadRc( rcF, 'optics.lookuptable', lookuptable, status )
  167. IF_NOTOK_RETURN(status=1)
  168. call ReadRc( rcF, 'optics.refractive_indices', refractive_indices, status )
  169. IF_NOTOK_RETURN(status=1)
  170. ! read lookup table
  171. CALL MDF_Open( TRIM(lookuptable), MDF_NETCDF, MDF_READ, fid, status )
  172. IF_NOTOK_RETURN(status=1)
  173. CALL MDF_Inq_VarID( fid, 'mr', varid, status )
  174. IF_NOTOK_RETURN(status=1)
  175. CALL MDF_Get_Var( fid, varid, n1r, status )
  176. IF_NOTOK_RETURN(status=1)
  177. CALL MDF_Inq_VarID( fid, 'mi', varid, status )
  178. IF_NOTOK_RETURN(status=1)
  179. CALL MDF_Get_Var( fid, varid, kval, status )
  180. IF_NOTOK_RETURN(status=1)
  181. lkval = -log10(kval)
  182. CALL MDF_Inq_VarID( fid, 'x', varid, status )
  183. IF_NOTOK_RETURN(status=1)
  184. CALL MDF_Get_Var( fid, varid, xs, status )
  185. IF_NOTOK_RETURN(status=1)
  186. CALL MDF_Inq_VarID( fid, 'ext_159', varid, status )
  187. IF_NOTOK_RETURN(status=1)
  188. CALL MDF_Get_Var( fid, varid, cext_159, status )
  189. IF_NOTOK_RETURN(status=1)
  190. CALL MDF_Inq_VarID( fid, 'ext_200', varid, status )
  191. IF_NOTOK_RETURN(status=1)
  192. CALL MDF_Get_Var( fid, varid, cext_200, status )
  193. IF_NOTOK_RETURN(status=1)
  194. CALL MDF_Inq_VarID( fid, 'a_159', varid, status )
  195. IF_NOTOK_RETURN(status=1)
  196. CALL MDF_Get_Var( fid, varid, a_159, status )
  197. IF_NOTOK_RETURN(status=1)
  198. CALL MDF_Inq_VarID( fid, 'a_200', varid, status )
  199. IF_NOTOK_RETURN(status=1)
  200. CALL MDF_Get_Var( fid, varid, a_200, status )
  201. IF_NOTOK_RETURN(status=1)
  202. CALL MDF_Inq_VarID( fid, 'g_159', varid, status )
  203. IF_NOTOK_RETURN(status=1)
  204. CALL MDF_Get_Var( fid, varid, g_159, status )
  205. IF_NOTOK_RETURN(status=1)
  206. CALL MDF_Inq_VarID( fid, 'g_200', varid, status )
  207. IF_NOTOK_RETURN(status=1)
  208. CALL MDF_Get_Var( fid, varid, g_200, status )
  209. IF_NOTOK_RETURN(status=1)
  210. CALL MDF_Close( fid, status )
  211. IF_NOTOK_RETURN(status=1)
  212. ! Read refractive indices
  213. CALL MDF_Open( TRIM(refractive_indices), MDF_NETCDF, MDF_READ, fid, status )
  214. IF_NOTOK_RETURN(status=1)
  215. ! Get Opac data
  216. CALL MDF_Inq_VarID( fid, 'Opac', varid, status )
  217. IF_NOTOK_RETURN(status=1)
  218. CALL MDF_Get_Var( fid, varid, opac, status )
  219. IF_NOTOK_RETURN(status=1)
  220. ! Get ECHAM-HAM data
  221. CALL MDF_Inq_VarID( fid, 'ECHAM-HAM', varid, status )
  222. IF_NOTOK_RETURN(status=1)
  223. CALL MDF_Get_Var( fid, varid, echamham, status )
  224. IF_NOTOK_RETURN(status=1)
  225. ! Get Segelstein data
  226. CALL MDF_Inq_VarID( fid, 'Segelstein', varid, status )
  227. IF_NOTOK_RETURN(status=1)
  228. CALL MDF_Get_Var( fid, varid, segelstein, status )
  229. IF_NOTOK_RETURN(status=1)
  230. CALL MDF_Close( fid, status )
  231. IF_NOTOK_RETURN(status=1)
  232. call optics_wavelen_init( wdep, status )
  233. IF_ERROR_RETURN( status=1 )
  234. write(gol,*) 'Optical parameters:'; call goPr
  235. do i = 1, nwav
  236. write(gol,*) 'Wavelength :', wdep(i)%wl ; call goPr
  237. write(gol,*) ' SO4 (real/img) :', wdep(i)%n(1), wdep(i)%k(1) ; call goPr
  238. write(gol,*) ' BC (real/img) :', wdep(i)%n(2), wdep(i)%k(2) ; call goPr
  239. write(gol,*) ' OC (real/img) :', wdep(i)%n(3), wdep(i)%k(3) ; call goPr
  240. write(gol,*) ' SOA (real/img) :', wdep(i)%n(4), wdep(i)%k(4) ; call goPr
  241. write(gol,*) ' SS (real/img) :', wdep(i)%n(5), wdep(i)%k(5) ; call goPr
  242. write(gol,*) ' DU (real/img) :', wdep(i)%n(6), wdep(i)%k(6) ; call goPr
  243. write(gol,*) ' H2O (real/img) :', wdep(i)%n(7), wdep(i)%k(7) ; call goPr
  244. enddo
  245. ! Done
  246. ! -------------
  247. call Done( rcF, status )
  248. IF_NOTOK_RETURN(status=1)
  249. deallocate( opac, echamham, segelstein )
  250. status = 0
  251. END SUBROUTINE OPTICS_INIT
  252. !EOC
  253. !--------------------------------------------------------------------------
  254. ! TM5 !
  255. !--------------------------------------------------------------------------
  256. !BOP
  257. !
  258. ! !IROUTINE: OPTICS_DONE
  259. !
  260. ! !DESCRIPTION: dummy for now
  261. !\\
  262. !\\
  263. ! !INTERFACE:
  264. !
  265. SUBROUTINE OPTICS_DONE( status )
  266. !
  267. ! !OUTPUT PARAMETERS:
  268. !
  269. integer, intent(out) :: status
  270. !
  271. ! !REVISION HISTORY:
  272. ! 6 Feb 2011 - Achim Strunk -
  273. !
  274. ! !REMARKS:
  275. !
  276. !EOP
  277. !------------------------------------------------------------------------
  278. !BOC
  279. ! ok
  280. status = 0
  281. END SUBROUTINE OPTICS_DONE
  282. !EOC
  283. !--------------------------------------------------------------------------
  284. ! TM5 !
  285. !--------------------------------------------------------------------------
  286. !BOP
  287. !
  288. ! !IROUTINE: OPTICS_WAVELEN_INIT
  289. !
  290. ! !DESCRIPTION: Initialise parameters which are depending on given
  291. ! wavelengths.
  292. !\\
  293. !\\
  294. ! !INTERFACE:
  295. !
  296. SUBROUTINE OPTICS_WAVELEN_INIT( wdep, status )
  297. !
  298. ! !INPUT/OUTPUT PARAMETERS:
  299. !
  300. ! wavelength properties (wavelength itself and real/img part of refractive index)
  301. type(wavelendep), intent(inout), dimension(:) :: wdep
  302. !
  303. ! !OUTPUT PARAMETERS:
  304. !
  305. integer, intent(out) :: status
  306. !
  307. ! !REVISION HISTORY:
  308. ! 6 Feb 2011 - Achim Strunk -
  309. !
  310. ! !REMARKS:
  311. !
  312. !EOP
  313. !------------------------------------------------------------------------
  314. !BOC
  315. character(len=*), parameter :: rname = mname//'/optics_wavelen_init'
  316. integer :: nwl, i, idx
  317. real :: wl, h
  318. real :: nscale, kscale
  319. ! Real part n and imaginary part k of refractive index
  320. ! for each wavelength:
  321. !>>> TvN
  322. ! The refractive index for 'sulfate' is taken from
  323. ! the OPAC database (Hess et al., 1998;
  324. ! Koepke et al., MPI report no. 243, 1997).
  325. ! The value used is that of 'sulfate solution',
  326. ! i.e. particles consisting of 75% of sulfuric acid (H2SO4),
  327. ! based on Fenn et al. (chapter 18 in Handbook of Geophysics
  328. ! and Space Environment, 1985).
  329. ! This is in line with Kinne et al. (JGR, 2003),
  330. ! who write that refractive indices for sulfate
  331. ! are usually based on 75% sulfuric acid solution.
  332. ! Actually, the OPAC refractive index agrees very well
  333. ! with the expression given by Boucher and Anderson (JGR, 1995)
  334. ! for H2SO4 at visible wavelengths.
  335. ! Thus, the OPAC data can be considered to apply to pure H2SO4,
  336. ! which is consistent of our application of mixing rules.
  337. ! For BC, the OPAC refractive index is scaled to one of
  338. ! the values proposed by Bond and Bergstrom (2006),
  339. ! valid at 550 nm (see their Table 5).
  340. ! Selected values for high, medium and low absorption are
  341. ! 1.95 + 0.79 i, 1.85 + 0.71 i, and 1.75 + 0.63 i, respectively.
  342. ! We select the low-absorption value,
  343. ! because it produces results in best agreement
  344. ! with AAOD from MODIS Collection 6 Deep Blue.
  345. ! Note that the medium-absorption value 1.85 + 0.71 i
  346. ! was used in ECHAM simulations by Stier et al. (2007),
  347. ! and found to give reasonable results.
  348. ! Lowenthal et al. (Atmos. Environ., 2000)
  349. ! give a value of 1.90 + 0.6 i.
  350. ! The reference value used in the scaling
  351. ! is the OPAC value at 550 nm: 1.75 + 0.44 i.
  352. ! It would be better to include the scaling
  353. ! in the input file.
  354. !nscale = 1.0 ! for using OPAC
  355. !kscale = 1.0 ! for using OPAC
  356. !nscale = 1.95/1.75
  357. !kscale = 0.79/0.44
  358. nscale = 1.85/1.75
  359. kscale = 0.71/0.44
  360. !nscale = 1.75/1.75
  361. !kscale = 0.63/0.44
  362. !<<< TvN
  363. nwl = size(wdep)
  364. do i = 1, nwl
  365. wl = wdep(i)%wl
  366. ! Interpolate Opac data
  367. findOpac: Do idx = 1,opacdim
  368. If(opac(1,idx) .gt. wl) exit findOpac
  369. End Do findOpac
  370. If(idx .gt. opacdim) then
  371. idx = opacdim
  372. h = 1.0
  373. Else If(idx .eq. 1) then
  374. idx = 2
  375. h = 0.0
  376. Else
  377. h = (wl-opac(1,idx-1))/(opac(1,idx)-opac(1,idx-1))
  378. End If
  379. ! SO4
  380. wdep(i)%n(1) = opac(2,idx-1)+h*(opac(2,idx)-opac(2,idx-1))
  381. wdep(i)%k(1) = opac(3,idx-1)+h*(opac(3,idx)-opac(3,idx-1))
  382. ! BC
  383. !>>> TvN
  384. !wdep(i)%n(2) = opac(4,idx-1)+h*(opac(4,idx)-opac(4,idx-1))
  385. !wdep(i)%k(2) = opac(5,idx-1)+h*(opac(5,idx)-opac(5,idx-1))
  386. wdep(i)%n(2) = nscale * ( opac(4,idx-1)+h*(opac(4,idx)-opac(4,idx-1)) )
  387. wdep(i)%k(2) = kscale * ( opac(5,idx-1)+h*(opac(5,idx)-opac(5,idx-1)) )
  388. !<<< TvN
  389. ! SS
  390. wdep(i)%n(5) = opac(6,idx-1)+h*(opac(6,idx)-opac(6,idx-1))
  391. wdep(i)%k(5) = opac(7,idx-1)+h*(opac(7,idx)-opac(7,idx-1))
  392. ! Interpolate ECHAM-HAM data
  393. findEchamham: Do idx = 1,echamhamdim
  394. If(echamham(1,idx) .gt. wl) exit findEchamham
  395. End Do findEchamham
  396. If(idx .gt. echamhamdim) then
  397. idx = echamhamdim
  398. h = 1.0
  399. Else If(idx .eq. 1) then
  400. idx = 2
  401. h = 0.0
  402. Else
  403. h = (wl-echamham(1,idx-1))/(echamham(1,idx)-echamham(1,idx-1))
  404. End If
  405. ! OC
  406. !>>> TvN
  407. ! The 'ECHAM-HAM' data currently used for POM
  408. ! are based on the data from Fenn et al. (1985)
  409. ! for the 'water soluble' component,
  410. ! but at a reduced number of wavelengths up to 15 um.
  411. ! It would be better to use the original table
  412. ! in the input file.
  413. !<<< TvN
  414. wdep(i)%n(3) = echamham(2,idx-1)+h*(echamham(2,idx)-echamham(2,idx-1))
  415. wdep(i)%k(3) = echamham(3,idx-1)+h*(echamham(3,idx)-echamham(3,idx-1))
  416. ! SOA
  417. ! >>TB
  418. ! For now (March 2017) we use OC indices for SOA
  419. ! <<TB
  420. wdep(i)%n(4) = echamham(2,idx-1)+h*(echamham(2,idx)-echamham(2,idx-1))
  421. wdep(i)%k(4) = echamham(3,idx-1)+h*(echamham(3,idx)-echamham(3,idx-1))
  422. ! DU
  423. wdep(i)%n(6) = echamham(4,idx-1)+h*(echamham(4,idx)-echamham(4,idx-1))
  424. wdep(i)%k(6) = echamham(5,idx-1)+h*(echamham(5,idx)-echamham(5,idx-1))
  425. ! Interpolate Segelstein data
  426. findSegelstein: Do idx = 1,segelsteindim
  427. If(segelstein(1,idx) .gt. wl) exit findSegelstein
  428. End Do findSegelstein
  429. If(idx .gt. segelsteindim) then
  430. idx = segelsteindim
  431. h = 1.0
  432. Else If(idx .eq. 1) then
  433. idx = 2
  434. h = 0.0
  435. Else
  436. h = (wl-segelstein(1,idx-1))/(segelstein(1,idx)-segelstein(1,idx-1))
  437. End If
  438. ! H2O
  439. wdep(i)%n(7) = segelstein(2,idx-1)+h*(segelstein(2,idx)-segelstein(2,idx-1))
  440. wdep(i)%k(7) = segelstein(3,idx-1)+h*(segelstein(3,idx)-segelstein(3,idx-1))
  441. enddo
  442. status=0
  443. END SUBROUTINE OPTICS_WAVELEN_INIT
  444. !EOC
  445. !--------------------------------------------------------------------------
  446. ! TM5 !
  447. !--------------------------------------------------------------------------
  448. !BOP
  449. !
  450. ! !IROUTINE: OPTICS_GET
  451. !
  452. ! !DESCRIPTION: Main optical properties routine. Here the interpolated
  453. ! values for extinction coefficient, single scattering
  454. ! albedo and assymetry parameter are retrieved and returned.
  455. !\\
  456. !\\
  457. ! !INTERFACE:
  458. !
  459. PURE SUBROUTINE OPTICS_GET(m_eff, xg, Cext, a, g, cext_table, a_table, g_table, status, gol )
  460. !
  461. ! !INPUT PARAMETERS:
  462. !
  463. complex, intent(in) :: m_eff
  464. real, intent(in) :: xg
  465. real, dimension(:,:,:), intent(in) :: cext_table, a_table, g_table
  466. !
  467. ! !OUTPUT PARAMETERS:
  468. !
  469. real, intent(out) :: Cext, a, g
  470. integer, intent(inout) :: status
  471. character(len=*), intent(inout) :: gol
  472. !
  473. ! !REVISION HISTORY:
  474. ! 15 Jul 2010 - P. Le Sager - Added check on i_n (out-of-bound)
  475. ! 6 Feb 2011 - Achim Strunk -
  476. !
  477. ! !REMARKS:
  478. ! - By using "pure" subroutine, we cannot use any of the goPr, goErr,
  479. ! IF_NOTOK_RETURN, ... routines. Traceback is limited:
  480. ! 1) only one statement can be recorded in variable gol
  481. ! 2) the calling routine should issue the "call goErr"
  482. !
  483. !EOP
  484. !------------------------------------------------------------------------
  485. !BOC
  486. real :: n, k, n1, k1, dk1, dk2, lk
  487. real :: modrad, modrad1, dr, dr1, slope, cext1, a1, g1
  488. integer :: i
  489. integer :: i_n, i_k, i_knew
  490. character(len=*), parameter :: rname = mname//'/Optics_Get'
  491. ! --- begin --------------------------------
  492. status = 0
  493. n=real(m_eff)
  494. k=imag(m_eff)
  495. if(k.lt.kval(1))then
  496. k1=kval(1)
  497. i_knew=1
  498. elseif(k.gt.kval(15))then
  499. k1=kval(15)
  500. i_knew=15
  501. else
  502. get_k: do i=2,15
  503. if(k.lt.kval(i))then
  504. dk1=k-kval(i-1)
  505. dk2=kval(i)-k
  506. if(dk1.le.dk2)then
  507. k1=kval(i-1)
  508. i_knew=i-1
  509. else
  510. k1=kval(i)
  511. i_knew=i
  512. endif
  513. exit get_k
  514. endif
  515. enddo get_k
  516. endif
  517. lk=-log10(k1)
  518. !#n1=float(int(50*n+0.5))/50.
  519. !do i_n = 1, n_rir
  520. ! if (abs(n1 - n1r(i_n)) < 1e-4) exit
  521. !enddo
  522. !i_n = 1 + int((n-1.12)*50+0.5)
  523. !AJS: I guess n is a number on the (increasing) n1r axis; search nearest index:
  524. i_n = size(n1r)
  525. do i = 1, size(n1r)
  526. if ( n <= n1r(i) ) then
  527. i_n = i
  528. exit
  529. end if
  530. end do
  531. if ( i_n > 1 ) then
  532. if ( abs(n-n1r(i_n-1)) < abs(n-n1r(i_n)) ) i_n = i_n - 1
  533. else if ( i_n < n_rir ) then
  534. if ( abs(n-n1r(i_n+1)) < abs(n-n1r(i_n)) ) i_n = i_n + 1
  535. end if
  536. do i_k = 1, n_rii
  537. if (abs(lk - lkval(i_k)) < 1e-4) exit
  538. enddo
  539. ! ! PLS - test : ik can be determined without the preceding loop "do i_k = 1, n_rii"
  540. ! if (i_k.ne.i_knew) then
  541. ! status = 1
  542. ! write (gol,'(" PLSPLS ik NE iknew = ",2(i2,2x))')i_k,i_knew
  543. ! endif
  544. ! following the "get_k" loop above, the only way to get into this is to
  545. ! have a NaN for k in the first place ?
  546. if (i_k > n_rii) then
  547. status = 1
  548. write(gol,*)'FATAL ERROR: i_k value outside LUT'
  549. ! write (gol,'(" lk = ",E16.4)')lk
  550. ! write (gol,'(" k1 = ",E16.4)')k1
  551. ! write (gol,'(" k = ",E16.4)')k
  552. ! write (gol,'(" n = ",E16.4)')n
  553. ! do i_n = 1, 15
  554. ! write (gol,'(" lkval(",i2,") = ",E16.4)')i_n,lkval(i_n)
  555. ! call goPr
  556. ! write (gol,'(" kval(",i2,") = ",E16.4)')i_n,kval(i_n)
  557. ! call goPr
  558. ! enddo
  559. return
  560. endif
  561. ! Added check (15-7-2010 - P. Le Sager)
  562. if (i_n > n_rir) then
  563. status = 1
  564. write(gol,*)'FATAL ERROR: i_n value out of range'
  565. return
  566. endif
  567. !>>> TvN
  568. ! Since xs(1) equals zero a problem may occur when xg is negative,
  569. ! because modrad.gt.xg would become true for i=1 in that case,
  570. ! while modrad1, Cext1, a1 and g1 are not yet set.
  571. ! It is not clear if negative xg values can ever occur,
  572. ! but if they do that should be prevented when calculating rg.
  573. !
  574. ! However, the problem may perhaps already occur
  575. ! when xg equals zero, because of the finite machine precision.
  576. !
  577. ! In any case, it is desired to initialize modrad1, Cext1, a1 and g1.
  578. ! Cext1, a1 and g1 should be set to their table entries for i=1,
  579. ! which are all zero:
  580. Cext1 = cext_table(1,i_n,i_k)
  581. a1 = a_table(1,i_n,i_k)
  582. g1 = g_table(1,i_n,i_k)
  583. ! modrad1 can be initialized to any value different from xs(1),
  584. ! to prevent division by zero.
  585. modrad1=xs(1)-9.99e-4
  586. ! This combination will force slope to zero
  587. ! and Cext, a and g to the table entries for i=1 (zero),
  588. ! in case modrad.gt.xg is true for i=1.
  589. !<<< TvN
  590. get_values: do i = 1, n_x
  591. modrad = xs(i)
  592. a = a_table(i,i_n, i_k)
  593. g = g_table(i,i_n, i_k)
  594. cext = cext_table(i,i_n, i_k)
  595. ! With small concentrations, like in the stratosphere, M7 does not trust its radii.
  596. ! See m7_averageproperties -> zinsvol. The M7-radius goes to zero
  597. ! Modrad may never be larger than xg the first time. Modrad1 is not set,
  598. ! will be zero (or something worse) and dr will be zero (or something worse).
  599. ! slope is demolished, makeing all values NaN. Therefore, it is modrad .gt. xg
  600. ! instead of modrad .ge. xg
  601. !
  602. ! PLS-TRANSLATION - It boils down to: "on the first iteration of this loop, if modrad=xg and
  603. ! you go into the if-statement below, you are in trouble, because modrad1 can be
  604. ! anything. To prevent that, replace GE with GT to avoid going into the if-statement at the
  605. ! first iteration."
  606. !
  607. if(modrad.gt.xg)then
  608. dr=modrad-modrad1
  609. dr1=xg-modrad1
  610. slope=(Cext-Cext1)/dr
  611. Cext=Cext1+slope*dr1
  612. slope=(a-a1)/dr
  613. a=a1+slope*dr1
  614. slope=(g-g1)/dr
  615. g=g1+slope*dr1
  616. exit get_values
  617. endif
  618. modrad1=modrad
  619. Cext1=Cext
  620. a1=a
  621. g1=g
  622. enddo get_values
  623. END SUBROUTINE OPTICS_GET
  624. !EOC
  625. !--------------------------------------------------------------------------
  626. ! TM5 !
  627. !--------------------------------------------------------------------------
  628. !BOP
  629. !
  630. ! !IROUTINE: GET_REFR_IDX
  631. !
  632. ! !DESCRIPTION: Compute refractive index of internally mixed aerosols by use
  633. ! of effective medium theory for the size-dependent aerosol
  634. ! mixtures assumed in M7.
  635. !\\
  636. !\\
  637. ! !INTERFACE:
  638. !
  639. PURE SUBROUTINE GET_REFR_IDX(wdep, SO4, BC, OC, SOA, SS, DU, water, mode, m_eff, status, gol)
  640. !
  641. ! !USES:
  642. !
  643. use binas, only: rol
  644. use chem_param, only: ss_density, dust_density, carbon_density
  645. use chem_param, only: pom_density, so4_density, soa_density
  646. !
  647. ! !INPUT PARAMETERS:
  648. !
  649. type(wavelendep), intent(in) :: wdep ! wavelength properties (wavelength, re/img part of refractive index)
  650. real, intent(in) :: SO4, BC, OC,SOA ! mass mixing ratios or concentrations of sulphate, black carbon, organic carbon
  651. real, intent(in) :: SS, DU, water ! sea salt, dust, and water
  652. integer, intent(in) :: mode ! mode number (M7)
  653. !
  654. ! !OUTPUT PARAMETERS:
  655. !
  656. complex, intent(out) :: m_eff ! effective refractive index of mixture
  657. integer, intent(out) :: status
  658. character(len=*), intent(inout) :: gol
  659. !
  660. ! !REVISION HISTORY:
  661. ! 12 Aug 2008 - Michael Kahnert, SMHI
  662. ! 6 Feb 2011 - Achim Strunk -
  663. !
  664. ! !REMARKS:
  665. ! - see remarks of OPTICS_GET subroutine about PURE routine
  666. !
  667. !EOP
  668. !------------------------------------------------------------------------
  669. !BOC
  670. character(len=*), parameter :: rname = mname//'/get_refr_idx'
  671. ! refractive indices
  672. complex :: m_SO4, m_BC, m_OC, m_SOA, m_SS, m_DU, m_water
  673. ! volume fractions
  674. real :: v_SO4, v_BC, v_OC, v_SOA, v_SS, v_DU, v_water, water_iv
  675. integer :: i_test
  676. real :: vtot, v2
  677. complex :: m00, m0, m1, m2
  678. real :: rpls, ipls
  679. ! --- begin --------------------------------
  680. ! Get the refractive indices from the lookup-tables and put them into complex numbers.
  681. m_so4 = cmplx( wdep%n(1),wdep%k(1) ) ! H2-SO4 + NH4NO3
  682. m_bc = cmplx( wdep%n(2),wdep%k(2) ) ! BC
  683. m_oc = cmplx( wdep%n(3),wdep%k(3) ) ! POM
  684. m_soa = cmplx( wdep%n(4),wdep%k(4) ) ! SOA
  685. m_ss = cmplx( wdep%n(5),wdep%k(5) ) ! SS
  686. m_du = cmplx( wdep%n(6),wdep%k(6) ) ! DU
  687. m_water = cmplx( wdep%n(7),wdep%k(7) ) ! Water
  688. status = 0
  689. ! no mixing for mode=6,7:
  690. if(mode.ge.6)then
  691. m_eff=m_DU
  692. return
  693. endif
  694. ! compute volume fractions:
  695. v_SO4=0.
  696. v_BC=0.
  697. v_OC=0.
  698. v_SOA=0.
  699. v_SS=0.
  700. v_DU=0.
  701. v_water=0.
  702. vtot=0.
  703. ! Added sanity check (15-7-2010 - P. Le Sager) : Avoid negative water
  704. ! mixing ratio!
  705. ! The bruggeman logically assumes that v_water is between 0 and 1, but
  706. ! this is never checked in the call chain :
  707. ! ECEarth_Optics_Step -> calculate_aop -> get_refr_idx [here] ->
  708. ! Bruggeman
  709. ! We do it here, with a warning since it reflects a problem upstream:
  710. if(water.lt.0.0)then
  711. !write (gol,*)" WARNING - [Get_refr_idx] : negative relative humidity..." ; call goPr
  712. !write (gol,*)" WARNING - [Get_refr_idx] : .....set to 0" ; call goPr
  713. water_iv=0.0
  714. else
  715. water_iv=water
  716. endif
  717. if(mode.le.4)then
  718. v_SO4=SO4/so4_density
  719. v_water=water_iv/rol
  720. vtot=vtot+v_SO4+v_water
  721. endif
  722. if(mode.le.5)then
  723. !v_OC=OC/pom_density
  724. v_SOA=SOA/soa_density
  725. vtot=vtot+v_SOA
  726. end if
  727. if(mode.ge.2.and.mode.le.5)then
  728. v_BC=BC/carbon_density
  729. v_OC=OC/pom_density
  730. vtot=vtot+v_BC+v_OC
  731. endif
  732. if(mode.ge.3.and.mode.le.4)then
  733. v_SS=SS/ss_density
  734. vtot=vtot+v_SS
  735. endif
  736. if(mode.ge.3.and.mode.ne.5)then
  737. v_DU=DU/dust_density
  738. vtot=vtot+v_DU
  739. endif
  740. ! If vtot is zero, we will get 0.0/0.0's causing NaNs. In that case, the
  741. ! refractive index does not matter and will be set to (1.0,1.0e-9). The
  742. ! reason not to take (1.0,0.0) is that someone with humour might take
  743. ! the logarithm of the imaginary part. Dust particles get their usual
  744. ! refractive index, because they already returned m_DU. But that does
  745. ! not matter, because there are zero aerosols in this case.
  746. If (vtot .le. 1e-20) Then
  747. m_eff = Cmplx(1.0,1.0e-9)
  748. Else
  749. v_SO4=v_SO4/vtot
  750. v_BC=v_BC/vtot
  751. v_OC=v_OC/vtot
  752. v_SOA=v_SOA/vtot
  753. v_SS=v_SS/vtot
  754. v_DU=v_DU/vtot
  755. v_water=v_water/vtot
  756. !-----------------------------------------------------------------------
  757. ! effective medium computations for each mode
  758. !-----------------------------------------------------------------------
  759. if(mode.eq.1)then
  760. ! Bruggeman mixing rule for SO4 OC and water:
  761. m1=m_SO4
  762. m2=m_SOA
  763. vtot=v_SO4+v_SOA
  764. v2=v_SOA/vtot
  765. call Bruggeman(m1,m2,v2,m0)
  766. m1=m0
  767. m2=m_water
  768. v2=v_water
  769. call Bruggeman(m1,m2,v2,m0)
  770. elseif(mode.eq.2)then
  771. ! iterative Bruggeman mixing rule for SO4, OC, and water:
  772. m1=m_SO4
  773. m2=m_OC
  774. vtot=v_SO4+v_OC
  775. v2=v_OC/vtot
  776. call Bruggeman(m1,m2,v2,m00)
  777. m1=m00
  778. m2=m_SOA
  779. vtot=vtot+v_SOA
  780. v2=v_SOA/vtot
  781. call Bruggeman(m1,m2,v2,m00)
  782. m1=m00
  783. m2=m_water
  784. vtot=vtot+v_water
  785. v2=v_water/vtot
  786. call Bruggeman(m1,m2,v2,m00)
  787. ! Maxwell-Garnett mixing rule for BC inclusions:
  788. m1=m00
  789. m2=m_BC
  790. v2=v_BC
  791. call Maxwell_Garnett(m1,m2,v2,m0)
  792. elseif(mode.eq.3.or.mode.eq.4)then
  793. ! iterative Bruggeman mixing rule for SO4, OC, SS, and water:
  794. m1=m_SO4
  795. m2=m_OC
  796. vtot=v_SO4+v_OC
  797. if ( vtot < TINY( vtot ) ) then
  798. v2=0.0
  799. else
  800. v2=v_OC/vtot
  801. end if
  802. call Bruggeman(m1,m2,v2,m00)
  803. m1=m00
  804. m2=m_SOA
  805. vtot=vtot+v_SOA
  806. if ( vtot < TINY( vtot ) ) then
  807. v2=0.0
  808. else
  809. v2=v_SOA/vtot
  810. end if
  811. call Bruggeman(m1,m2,v2,m00)
  812. m1=m00
  813. m2=m_SS
  814. vtot=vtot+v_SS
  815. if ( vtot < TINY( vtot ) ) then
  816. v2=0.0
  817. else
  818. v2=v_SS/vtot
  819. end if
  820. call Bruggeman(m1,m2,v2,m00)
  821. m1=m00
  822. m2=m_water
  823. vtot=vtot+v_water
  824. v2=v_water/vtot
  825. call Bruggeman(m1,m2,v2,m00)
  826. ! iterative Maxwell-Garnett mixing rule for BC and dust
  827. ! inclusions:
  828. m1=m00
  829. m2=m_BC
  830. vtot=vtot+v_BC
  831. if ( vtot < TINY( vtot ) ) then
  832. v2=0.0
  833. else
  834. v2=v_BC/vtot
  835. end if
  836. call Maxwell_Garnett(m1,m2,v2,m00)
  837. m1=m00
  838. m2=m_DU
  839. v2=v_DU
  840. call Maxwell_Garnett(m1,m2,v2,m0)
  841. elseif(mode.eq.5)then
  842. ! Maxwell-Garnett mixing rule for BC inclusions:
  843. m1=m_OC
  844. m2=m_BC
  845. v2=v_BC
  846. call Maxwell_Garnett(m1,m2,v2,m00)
  847. m1=m00
  848. m2=m_SOA
  849. vtot=vtot+v_SOA
  850. v2=v_SOA/vtot
  851. call Bruggeman(m1,m2,v2,m0)
  852. endif
  853. m_eff = m0
  854. End If
  855. ! Debug : trap for a NAN (13-7-2010 - P. Le Sager)
  856. rpls=real(m_eff)
  857. ipls=imag(m_eff)
  858. IF ((rpls.NE.rpls).or.(ipls.NE.ipls)) then
  859. status = 1
  860. write (gol,'(" GET_REFR_IDX-NAN: ", 3(E16.4,2x),i4,2x,7(E16.4,2x))') rpls, ipls, vtot, mode,&
  861. & SO4,BC,OC,SOA,SS,DU,water
  862. endif
  863. END SUBROUTINE GET_REFR_IDX
  864. !EOC
  865. !--------------------------------------------------------------------------
  866. ! TM5 !
  867. !--------------------------------------------------------------------------
  868. !BOP
  869. !
  870. ! !IROUTINE: BRUGGEMAN
  871. !
  872. ! !DESCRIPTION: Compute effective refractive index of a mixture of 2 components
  873. ! by use of the Bruggeman mixing rule
  874. !\\
  875. !\\
  876. ! !INTERFACE:
  877. !
  878. PURE SUBROUTINE BRUGGEMAN(m1,m2,v2,m0)
  879. !
  880. ! !INPUT PARAMETERS:
  881. !
  882. complex, intent(in) :: m1,m2
  883. real, intent(in) :: v2
  884. !
  885. ! !OUTPUT PARAMETERS:
  886. !
  887. complex, intent(out) :: m0
  888. !
  889. ! !REVISION HISTORY:
  890. ! 12 Aug 2008 - Michael Kahnert, SMHI
  891. ! 6 Feb 2011 - Achim Strunk -
  892. !
  893. ! !REMARKS:
  894. !
  895. !EOP
  896. !------------------------------------------------------------------------
  897. !BOC
  898. complex m1s,m2s,mt
  899. real fac1,fac2
  900. if(v2.eq.1.0)then
  901. m0=m2
  902. return
  903. elseif(v2.eq.0.0)then
  904. m0=m1
  905. return
  906. endif
  907. fac1=2.-3.*v2
  908. fac2=3.*v2-1.
  909. m1s=m1**2
  910. m2s=m2**2
  911. mt=m1s*fac1+m2s*fac2
  912. m0=1./16.*mt**2+0.5*m1s*m2s
  913. m0=csqrt(m0)
  914. m0=m0+0.25*mt
  915. m0=csqrt(m0)
  916. END SUBROUTINE BRUGGEMAN
  917. !EOC
  918. !--------------------------------------------------------------------------
  919. ! TM5 !
  920. !--------------------------------------------------------------------------
  921. !BOP
  922. !
  923. ! !IROUTINE: MAXWELL_GARNETT
  924. !
  925. ! !DESCRIPTION: Compute effective refractive index for a medium consisting of
  926. ! a matrix with refractive index m1 and inclusions with refractive
  927. ! index m2 and volume fraction v2 by use of the Maxwell-Garnett
  928. ! mixing rule.
  929. !\\
  930. !\\
  931. ! !INTERFACE:
  932. !
  933. PURE SUBROUTINE MAXWELL_GARNETT( m1, m2, v2, m0)
  934. !
  935. ! !INPUT PARAMETERS:
  936. !
  937. complex, intent(in) :: m1, m2
  938. real, intent(in) :: v2
  939. !
  940. ! !OUTPUT PARAMETERS:
  941. !
  942. complex, intent(out) :: m0
  943. !
  944. ! !REVISION HISTORY:
  945. ! 12 Aug 2008 - Michael Kahnert, SMHI
  946. ! 6 Feb 2011 - Achim Strunk -
  947. !
  948. ! !REMARKS:
  949. !
  950. !EOP
  951. !------------------------------------------------------------------------
  952. !BOC
  953. complex :: m1s,m2s
  954. real :: fac1,fac2
  955. fac1=3.0-2.0*v2
  956. fac2=3.0-v2
  957. m1s=m1**2
  958. m2s=m2**2
  959. m0=m2s*(fac1*m1s+2.0*v2*m2s)/(v2*m1s+fac2*m2s)
  960. m0=csqrt(m0)
  961. END SUBROUTINE MAXWELL_GARNETT
  962. !EOC
  963. !--------------------------------------------------------------------------
  964. ! TM5 !
  965. !--------------------------------------------------------------------------
  966. !BOP
  967. !
  968. ! !IROUTINE: OPTICS_CALCULATE_AOP
  969. !
  970. ! !DESCRIPTION: This routine writes on aop_out_* (module wide parameters)
  971. ! the retrieved aerosol properties. The caller has to ensure
  972. ! that these fields have been allocated properly.
  973. ! IMPORTANT: OC is actually POM.
  974. ! Remember converting OC to POM when sending it to this method.
  975. !\\
  976. !\\
  977. ! !INTERFACE:
  978. !
  979. SUBROUTINE OPTICS_CALCULATE_AOP( nwl, wdep, lvec, ecearth_units, &
  980. aop_out_ext, aop_out_a, aop_out_g, status, aop_out_add )
  981. !
  982. ! !USES:
  983. !
  984. use binas, only : rol, twopi
  985. use chem_param, only : ss_density, dust_density, carbon_density
  986. use chem_param, only : pom_density, so4_density, soa_density
  987. Use mo_aero_m7, only : nmod, cmedr2mmedr, sigma
  988. !
  989. ! !INPUT PARAMETERS:
  990. !
  991. integer, intent(in) :: nwl
  992. type(wavelendep), intent(in), dimension(nwl) :: wdep ! wavelength depending properties
  993. integer, intent(in) :: lvec
  994. logical, intent(in) :: ecearth_units
  995. !
  996. ! !OUTPUT PARAMETERS:
  997. !
  998. Real, Dimension(:,:,:), intent(out) :: aop_out_ext ! extinctions
  999. Real, Dimension(:,:), intent(out) :: aop_out_a ! single scattering albedo
  1000. Real, Dimension(:,:), intent(out) :: aop_out_g ! assymetry factor
  1001. integer, intent(out) :: status
  1002. Real, Dimension(:,:,:), intent(out), optional :: aop_out_add ! additional parameters
  1003. !
  1004. ! !REVISION HISTORY:
  1005. ! 12 Aug 2008 - Michael Kahnert, SMHI
  1006. ! 6 Feb 2011 - Achim Strunk -
  1007. ! 23 Jan 2013 - Narcisa Banda - included OMP (PLS: commented in TM5-MP)
  1008. !
  1009. ! !REMARKS:
  1010. !
  1011. !EOP
  1012. !------------------------------------------------------------------------
  1013. !BOC
  1014. real, dimension(:), allocatable :: NCsca, incext
  1015. real :: Cexti, ai, gi, NCscai, xg
  1016. complex :: m_eff
  1017. real, dimension(:), allocatable :: lnsigma
  1018. integer :: i, imode, ivec!, lss, lee
  1019. integer :: statusomp
  1020. Logical :: coarse
  1021. real :: totvoldry, modfrac
  1022. ! real :: t1, t2 , omp_get_wtime
  1023. Real, Dimension(:,:,:), Pointer :: cext_table, a_table, g_table
  1024. ! --- const ------------------------------
  1025. character(len=*), parameter :: rname = mname//'/optics_calculate_AOP'
  1026. ! --- begin --------------------------------
  1027. allocate( NCsca ( lvec ) )
  1028. ! allocate( NCscai( lvec ) )
  1029. ! allocate( Cexti ( lvec ) )
  1030. ! allocate( ai ( lvec ) )
  1031. ! allocate( gi ( lvec ) )
  1032. ! allocate( xg ( lvec ) )
  1033. ! allocate( m_eff ( lvec ) )
  1034. allocate( incext( lvec ) )
  1035. !t1= omp_get_wtime()
  1036. status = 0
  1037. !pls! !$OMP PARALLEL &
  1038. !pls! !$OMP default (none) &
  1039. !pls! !$OMP shared (nwl, lvec, NCsca, incext, &
  1040. !pls! !$OMP wdep, aop_in, aop_out_Ext, aop_out_g, aop_out_a, aop_out_add, sigma, cmedr2mmedr,&
  1041. !pls! !$OMP cext_200, a_200, g_200, cext_159, a_159, g_159, status, gol) &
  1042. !pls! !$OMP private (lnsigma, i, imode, modfrac, coarse, totvoldry, lss, lee, ivec, &
  1043. !pls! !$OMP NCscai, Cexti, ai, gi, xg, m_eff, cext_table, a_table, g_table, statusomp )
  1044. !pls! call my_omp_domain (1, lvec, lss, lee)
  1045. ! Sulphate based on OPAC (Hess et al., 1998):
  1046. !=======================================================================
  1047. ! Get refractive indices of each component at the given wavelength:
  1048. !=======================================================================
  1049. do i = 1, nwl ! loop over wavelengths
  1050. if( wdep(i)%split .or. wdep(i)%insitu ) then
  1051. allocate( lnsigma( nmod ) )
  1052. lnsigma = log(sigma)
  1053. end if
  1054. aop_out_Ext(:,i,:) = 0.0
  1055. aop_out_g (:,i) = 0.0
  1056. aop_out_a (:,i) = 0.0
  1057. if( wdep(i)%insitu ) aop_out_add(:,i,:) = 0.0
  1058. NCsca (:) = 0.0
  1059. do imode = 1, 7 ! loop over M7 modes
  1060. coarse = (imode .eq. 4 .or. imode .eq. 7)
  1061. If (coarse) then
  1062. cext_table => cext_200
  1063. a_table => a_200
  1064. g_table => g_200
  1065. Else
  1066. cext_table => cext_159
  1067. a_table => a_159
  1068. g_table => g_159
  1069. End if
  1070. !=======================================================================
  1071. ! Compute effective refractive index of internally mixed aerosols
  1072. ! for each grid cell and mode:
  1073. !=======================================================================
  1074. do ivec = 1, lvec
  1075. !write(1001,*) aop_in(ivec)%SO4(imode), aop_in(ivec)%NO3(imode)
  1076. !write(1002,*) aop_in(ivec)%SOA(imode)
  1077. !write(1003,*) aop_in(ivec)%BC(imode), aop_in(ivec)%OC(imode)
  1078. !write(1004,*) aop_in(ivec)%SS(imode), aop_in(ivec)%DU(imode)
  1079. call get_refr_idx( wdep(i), &
  1080. aop_in(ivec)%SO4(imode) + aop_in(ivec)%NO3(imode), & ! H2-SO4 + NH4NO3
  1081. aop_in(ivec)%BC (imode), aop_in(ivec)%OC (imode), &
  1082. aop_in(ivec)%SOA (imode), &
  1083. aop_in(ivec)%SS (imode), aop_in(ivec)%DU (imode), &
  1084. aop_in(ivec)%h2o(imode), imode, m_eff, statusomp, gol)
  1085. if (statusomp ==1) then
  1086. call GoErr
  1087. status = 1
  1088. IF_ERROR_RETURN( status=1 )
  1089. endif
  1090. ! cmk added towpi for new netcdf lookup table
  1091. xg = twopi*aop_in(ivec)%rg(imode) / wdep(i)%wl
  1092. !=======================================================================
  1093. ! get aerosol optical properties from data base for each mode
  1094. !=======================================================================
  1095. call Optics_Get(m_eff, xg, Cexti, ai, gi, cext_table, a_table, g_table, statusomp, gol )
  1096. if (statusomp ==1) then
  1097. call GoErr
  1098. status = 1
  1099. IF_ERROR_RETURN( status=1 )
  1100. endif
  1101. ! Multiply Cext with lambda^2 to get the cross section.
  1102. Cexti = Cexti*(wdep(i)%wl**2)
  1103. ! this here is extinction coefficient in this mode
  1104. incext(ivec) = aop_in(ivec)%numdens(imode) * Cexti
  1105. ! sum up partial coefficients
  1106. Aop_out_ext(ivec,i,1) = Aop_out_Ext(ivec,i,1) + incext(ivec)
  1107. ! scattering portion
  1108. NCscai = ai * incext(ivec)
  1109. ! sum up weights for average (both albedo and asymmetry)
  1110. NCsca (ivec) = NCsca (ivec) + NCscai
  1111. aop_out_g(ivec,i) = aop_out_g(ivec,i) + NCscai * gi
  1112. end do
  1113. ! Split extinction to separate contributions from constituents in modes.
  1114. ! A volume mixing is assumed (in contrast to the explicit mixing in get_refr_ind).
  1115. if( wdep(i)%split .or. wdep(i)%insitu) then
  1116. do ivec = 1, lvec
  1117. if (wdep(i)%split) then
  1118. ! The fine-mode contributions to the extinction
  1119. ! includes the contributions from particles
  1120. ! with (wet) diameters smaller than 1 micron.
  1121. ! For wet particles, only part of the accumulation mode
  1122. ! should be included, and the coarse mode should be excluded.
  1123. if (.not.coarse) then
  1124. ! Currently, the contribution of the accumulation mode
  1125. ! is approximated using weighting by volume scaling factor modfrac.
  1126. ! For extinction, area weighting would probably be more appropriate!!
  1127. if (imode .eq. 3 .or. imode .eq. 6 ) then
  1128. ! - convert number mean radius to volume mean radius (by cmedr2mmedr(imode))
  1129. ! - 1 micron diameter --> radius is 0.5 microns (rg is also in microns)
  1130. modfrac = 0.5 + 0.5 * ERF( log( 0.5 / (aop_in(ivec)%rg(imode) * cmedr2mmedr(imode)) ) / &
  1131. (sqrt(2.0) * lnsigma(imode)) )
  1132. else
  1133. ! Include full nucleation and Aitken mode contributions.
  1134. modfrac = 1.0
  1135. endif
  1136. aop_out_ext(ivec,i,10) = aop_out_ext(ivec,i,10) + modfrac * incext(ivec)
  1137. endif
  1138. ! total volume from so4/no3/bc/oc/ss/du in this mode (ATTENTION: DRY!!)
  1139. ! take no3 as so4
  1140. totvoldry = aop_in(ivec)%so4(imode)/so4_density + aop_in(ivec)%no3(imode)/so4_density + &
  1141. aop_in(ivec)%bc (imode)/carbon_density + aop_in(ivec)%oc (imode)/pom_density + &
  1142. aop_in(ivec)%soa (imode)/soa_density + &
  1143. aop_in(ivec)%ss (imode)/ss_density + aop_in(ivec)%du (imode)/dust_density
  1144. ! check whether there is some volume available
  1145. ! otherwise assign zeros to extinction increments
  1146. if( totvoldry < tiny(totvoldry) ) then
  1147. write(gol,'("WARNING: no volume in mode (",i3,"). assigning zero extinctions")') imode; call goPr
  1148. cycle
  1149. end if
  1150. ! H2-SO4 contribution
  1151. aop_out_ext(ivec,i,2) = aop_out_ext(ivec,i,2) + incext(ivec) * (aop_in(ivec)%so4(imode)/so4_density ) / totvoldry
  1152. ! BC contribution
  1153. aop_out_ext(ivec,i,3) = aop_out_ext(ivec,i,3) + incext(ivec) * (aop_in(ivec)%bc (imode)/carbon_density) / totvoldry
  1154. ! POM contribution
  1155. aop_out_ext(ivec,i,4) = aop_out_ext(ivec,i,4) + incext(ivec) * (aop_in(ivec)%oc (imode)/pom_density ) / totvoldry
  1156. ! SOA contribution
  1157. aop_out_ext(ivec,i,5) = aop_out_ext(ivec,i,5) + incext(ivec) * (aop_in(ivec)%soa (imode)/soa_density ) / totvoldry
  1158. ! SS contribution
  1159. aop_out_ext(ivec,i,6) = aop_out_ext(ivec,i,6) + incext(ivec) * (aop_in(ivec)%ss (imode)/ss_density ) / totvoldry
  1160. ! DU contribution
  1161. aop_out_ext(ivec,i,7) = aop_out_ext(ivec,i,7) + incext(ivec) * (aop_in(ivec)%du (imode)/dust_density ) / totvoldry
  1162. ! NH4NO3 contribution
  1163. aop_out_ext(ivec,i,8) = aop_out_ext(ivec,i,8) + incext(ivec) * (aop_in(ivec)%no3(imode)/so4_density ) / totvoldry
  1164. ! Fine-mode contributions for dust and sea salt
  1165. if (.not.coarse) then
  1166. aop_out_ext(ivec,i,11) = aop_out_ext(ivec,i,11) + incext(ivec) * (aop_in(ivec)%du (imode)/dust_density ) / totvoldry * modfrac
  1167. aop_out_ext(ivec,i,12) = aop_out_ext(ivec,i,12) + incext(ivec) * (aop_in(ivec)%ss (imode)/ss_density ) / totvoldry * modfrac
  1168. endif
  1169. endif
  1170. ! Water contribution:
  1171. ! Get optical properties without water, the difference will be extinction due to
  1172. ! water existence
  1173. ! - mis-use gi for this
  1174. gi = 0.0
  1175. call get_refr_idx( wdep(i), &
  1176. aop_in(ivec)%SO4(imode) + aop_in(ivec)%NO3(imode), &
  1177. aop_in(ivec)%BC (imode), aop_in(ivec)%OC (imode), &
  1178. aop_in(ivec)%SOA (imode), &
  1179. aop_in(ivec)%SS (imode), aop_in(ivec)%DU (imode), &
  1180. gi, imode, m_eff, statusomp, gol)
  1181. if (statusomp ==1) then
  1182. status = 1
  1183. call GoErr
  1184. IF_NOTOK_RETURN(status = 1)
  1185. endif
  1186. ! here we need the dry radius!!!
  1187. !>>> TvN
  1188. ! 2*pi should be included (see comment above)
  1189. !xg = aop_in(ivec)%rgd(imode) / wdep(i)%wl
  1190. xg = twopi*aop_in(ivec)%rgd(imode) / wdep(i)%wl
  1191. !<<< TvN
  1192. call Optics_Get(m_eff, xg, Cexti, ai, gi, cext_table, a_table, g_table, statusomp, gol )
  1193. if (statusomp ==1) then
  1194. call GoErr
  1195. status = 1
  1196. IF_ERROR_RETURN( status=1 )
  1197. endif
  1198. Cexti = Cexti*(wdep(i)%wl**2)
  1199. if (wdep(i)%split) then
  1200. ! add difference to water subarray
  1201. Aop_out_ext(ivec,i,9) = aop_out_ext(ivec,i,9) + (incext(ivec) - aop_in(ivec)%numdens(imode) * Cexti)
  1202. endif
  1203. if (wdep(i)%insitu) then
  1204. ! Surface dry extinction and absorption:
  1205. !>>> TvN
  1206. ! Remove cut off for the total values:
  1207. !modfrac = 0.5 + 0.5 * ERF( log( 5.0 / (aop_in(ivec)%rgd(imode) * cmedr2mmedr(imode)) ) / &
  1208. ! (sqrt(2.0) * lnsigma(imode)) )
  1209. ! extinction and absorption (extinction-scattering):
  1210. !Aop_out_add(ivec,i,1) = aop_out_add(ivec,i,1) + modfrac * aop_in(ivec)%numdens(imode) * Cexti
  1211. !Aop_out_add(ivec,i,2) = aop_out_add(ivec,i,2) + modfrac * aop_in(ivec)%numdens(imode) * Cexti * (1. - ai)
  1212. aop_out_add(ivec,i,1) = aop_out_add(ivec,i,1) + aop_in(ivec)%numdens(imode) * Cexti
  1213. aop_out_add(ivec,i,2) = aop_out_add(ivec,i,2) + aop_in(ivec)%numdens(imode) * Cexti * (1. - ai)
  1214. aop_out_add(ivec,i,3) = aop_out_add(ivec,i,3) + aop_in(ivec)%numdens(imode) * Cexti * ai * gi
  1215. ! Add fine-mode contributions
  1216. ! For dry aerosol, the fine-mode optical properties include
  1217. ! the full accumulation mode, but not the coarse mode:
  1218. if (.not.coarse) then
  1219. aop_out_add(ivec,i,4) = aop_out_add(ivec,i,4) + aop_in(ivec)%numdens(imode) * Cexti
  1220. aop_out_add(ivec,i,5) = aop_out_add(ivec,i,5) + aop_in(ivec)%numdens(imode) * Cexti * (1. - ai)
  1221. endif
  1222. !<<< TvN
  1223. endif
  1224. end do ! ivec
  1225. end if
  1226. enddo ! modes
  1227. if (ecearth_units == .true.) then
  1228. ! return extinction due to absorption
  1229. ! and asymmetry factor multiplied by extinction due to scattering
  1230. ! and convert um**2/m**3 into 1/m (as for extinction below)
  1231. Aop_out_a(:,i) = ( Aop_out_Ext(:,i,1) - NCsca(:) ) * 1.e-12
  1232. Aop_out_g(:,i) = Aop_out_g(:,i) * 1.e-12
  1233. else
  1234. ! return single-scattering albedo and asymmetry factor
  1235. ! take into account small extinction values
  1236. where( Aop_out_Ext(:,i,1) > tiny(0.0) )
  1237. Aop_out_a(:,i) = NCsca(:) / Aop_out_Ext(:,i,1)
  1238. elsewhere
  1239. ! No extinction -> Fill 1.0 for albedo because it looks clean.
  1240. Aop_out_a(:,i) = 1.0
  1241. endwhere
  1242. ! take into account small extinction values
  1243. where( NCsca(:) > tiny(0.0) )
  1244. Aop_out_g(:,i) = Aop_out_g(:,i) / NCsca(:)
  1245. elsewhere
  1246. ! No scattering at all -> Fill 1.0 for asymmetry because it looks clean.
  1247. Aop_out_g(:,i) = 1.0
  1248. endwhere
  1249. endif
  1250. ! convert um**2/m**3 into 1/m
  1251. Aop_out_Ext(:,i,:) = Aop_out_Ext(:,i,:) * 1e-12
  1252. if( wdep(i)%insitu) then
  1253. ! take into account small extinction values
  1254. where( aop_out_add(:,i,1) - aop_out_add(:,i,2) > tiny(0.0) )
  1255. aop_out_add(:,i,3) = aop_out_add(:,i,3) / (aop_out_add(:,i,1)-aop_out_add(:,i,2))
  1256. elsewhere
  1257. ! No scattering at all -> Fill 1.0 for asymmetry because it looks clean.
  1258. aop_out_add(:,i,3) = 1.0
  1259. endwhere
  1260. Aop_out_add(:,i,1) = aop_out_add(:,i,1) * 1e-12
  1261. Aop_out_add(:,i,2) = aop_out_add(:,i,2) * 1e-12
  1262. Aop_out_add(:,i,4) = aop_out_add(:,i,4) * 1e-12
  1263. Aop_out_add(:,i,5) = aop_out_add(:,i,5) * 1e-12
  1264. endif
  1265. if( wdep(i)%split .or. wdep(i)%insitu ) then
  1266. deallocate( lnsigma )
  1267. endif
  1268. !=======================================================================
  1269. enddo ! loop over wavelengths
  1270. Nullify(Cext_table)
  1271. Nullify(a_table)
  1272. Nullify(g_table)
  1273. !$OMP END PARALLEL
  1274. if (status==1) then
  1275. call goPr
  1276. IF_NOTOK_RETURN(status=1)
  1277. endif
  1278. !do imode = 1,7
  1279. ! print *, 'Radius,mode :', imode, sum(aop_in(:)%rg(imode))/lvec
  1280. ! print *, 'numden,mode :', imode, sum(aop_in(:)%numdens(imode))/lvec
  1281. !enddo
  1282. deallocate( NCsca, incext )
  1283. !do i = 1,nwl
  1284. ! print *, 'AOD per grid box:', wdep(i)%wl, sum(Aop_out_Ext(:,i,1))/lvec
  1285. !enddo
  1286. ! ok
  1287. status = 0
  1288. END SUBROUTINE OPTICS_CALCULATE_AOP
  1289. !EOC
  1290. !--------------------------------------------------------------------------
  1291. ! TM5 !
  1292. !--------------------------------------------------------------------------
  1293. !BOP
  1294. !
  1295. ! !IROUTINE: OPTICS_AOP_GET
  1296. !
  1297. ! !DESCRIPTION: Initialise the fields "aop_in" and then calculate the
  1298. ! optical properties through a call to optics_calculate_aop.
  1299. !\\
  1300. !\\
  1301. ! !INTERFACE:
  1302. !
  1303. SUBROUTINE OPTICS_AOP_GET( lvec, region, nwav, wdep, ncontr, ecearth_units, &
  1304. aop_out_ext, aop_out_a, aop_out_g, status, aop_out_add )
  1305. !
  1306. ! !USES:
  1307. !
  1308. USE TM5_DISTGRID, ONLY : dgrid, Get_DistGrid
  1309. use Meteo, only : Set
  1310. Use Meteodata, only : gph_dat, m_dat
  1311. Use Dims, only : im, jm, lm
  1312. use global_data, only : region_dat, mass_dat
  1313. Use chem_param, only : inus_n, iso4nus, isoanus, nmod
  1314. use chem_param, only : iais_n, iso4ais, ibcais, ipomais, isoaais
  1315. Use chem_param, only : iacs_n, iso4acs, ibcacs, ipomacs, isoaacs, issacs, iduacs, ino3_a
  1316. use chem_param, only : imsa
  1317. use chem_param, only : icos_n, iso4cos, ibccos, ipomcos, isoacos, isscos, iducos
  1318. use chem_param, only : iaii_n, ibcaii, ipomaii, isoaaii
  1319. use chem_param, only : iaci_n, icoi_n, iduaci, iducoi
  1320. use chem_param, only : h2so4_factor, nh4no3_factor
  1321. use chem_param, only : so4_density, nh4no3_density, msa_density
  1322. Use m7_data, only : h2o_mode, rw_mode, rwd_mode
  1323. !
  1324. ! !INPUT PARAMETERS:
  1325. !
  1326. Integer, Intent(In) :: region, lvec
  1327. Integer, Intent(In) :: nwav, ncontr
  1328. type(wavelendep), dimension(nwav), Intent(In) :: wdep
  1329. logical, intent(in) :: ecearth_units
  1330. !
  1331. ! !OUTPUT PARAMETERS:
  1332. !
  1333. real, dimension(lvec,nwav,ncontr), intent(out) :: aop_out_ext ! extinctions
  1334. real, dimension(lvec,nwav), intent(out) :: aop_out_a ! single scattering albedo
  1335. real, dimension(lvec,nwav), intent(out) :: aop_out_g ! assymetry factor
  1336. integer, intent(out) :: status
  1337. real, dimension(:,:,:), intent(out), optional :: aop_out_add ! additional parameters
  1338. !
  1339. ! !REVISION HISTORY:
  1340. ! 29 Nov 2010 - Achim Strunk - v0
  1341. ! 24 Jun 2011 - Achim Strunk - Added NO3 to allow for explicit
  1342. ! AOD split of (SO4+NO3)
  1343. ! 20 Jun 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
  1344. !
  1345. ! !REMARKS:
  1346. !
  1347. !EOP
  1348. !------------------------------------------------------------------------
  1349. !BOC
  1350. character(len=*), parameter :: rname = mname//'/optics_aop_get'
  1351. real, dimension(:,:,:,:), pointer :: rm
  1352. real, dimension(:,:,:), pointer :: m
  1353. real, dimension(:,:,:), allocatable :: volume
  1354. Integer :: i, j, l, iloop, i1, i2, j1, j2, lmr
  1355. ! --- start ------------------------------
  1356. ! ensure met fields being available
  1357. call Set( gph_dat(region), status, used=.true. )
  1358. ! air & tracers mass
  1359. m => m_dat(region)%data
  1360. rm => mass_dat(region)%rm
  1361. ! tile grid size
  1362. CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  1363. ! Generalize to allow for reduced number of levels
  1364. ! when called from ECEarth_Optics_Step
  1365. !lmr=lm(region)
  1366. lmr = lvec / ( (i2-i1+1)*(j2-j1+1) )
  1367. allocate( aop_in(lvec) )
  1368. do i = 1, nmod
  1369. aop_in(:)%so4 (i) = 0.0 ; aop_in(:)%bc (i) = 0.0
  1370. aop_in(:)%oc (i) = 0.0 ; aop_in(:)%soa (i) = 0.0
  1371. aop_in(:)%ss (i) = 0.0
  1372. aop_in(:)%du (i) = 0.0 ; aop_in(:)%h2o (i) = 0.0
  1373. aop_in(:)%numdens(i) = 0.0 ; aop_in(:)%rg (i) = 0.0
  1374. aop_in(:)%rgd (i) = 0.0 ; aop_in(:)%no3 (i) = 0.0
  1375. end do
  1376. !>>> TvN
  1377. ! In M7 sulphate is assumed to be H2-SO4 with corresponding particle density so4_density
  1378. ! The sulphate mass should therefore also include the small contribution from the H atoms
  1379. ! NUS
  1380. aop_in(:)%so4(1) = reshape( 1.e9 * h2so4_factor * rm(i1:i2,j1:j2,1:lmr,iso4nus) / &
  1381. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1382. aop_in(:)%soa(1) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,isoanus) / &
  1383. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1384. ! AIS
  1385. aop_in(:)%so4(2) = reshape( 1.e9 * h2so4_factor * rm(i1:i2,j1:j2,1:lmr,iso4ais) / &
  1386. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1387. aop_in(:)%bc (2) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ibcais ) / &
  1388. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1389. aop_in(:)%oc (2) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ipomais) / &
  1390. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1391. aop_in(:)%soa(2) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,isoaais) / &
  1392. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1393. ! ACS (additional: NO3)
  1394. ! The contribution from methane sulfonate (MSA-) aerosol is added
  1395. ! to that for sulfate.
  1396. ! As the addition is done by volume,
  1397. ! we need to account for the difference in densities
  1398. ! (as done below for ammonium nitrate).
  1399. aop_in(:)%so4(3) = reshape( 1.e9 * ( h2so4_factor * rm(i1:i2,j1:j2,1:lmr,iso4acs) + &
  1400. (so4_density / msa_density) * rm(i1:i2,j1:j2,1:lmr,imsa) ) / &
  1401. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1402. ! Since nh4no3_density is the density of NH4NO3, the contribution from NH4 should be included.
  1403. ! Moreover, assuming the same refractive index for NH4NO3 as for H2-SO4,
  1404. ! the contributions from both components can be added by volume;
  1405. ! thus we need to account for the difference in densities.
  1406. ! Estimates of the refractive index of NH4NO3 are available from literature
  1407. ! (e.g. Lowenthal et al., Atmos. Environ., 2000).
  1408. ! For practical purposes, it can be set equal to the value used for sulfate,
  1409. ! i.e. the value for a solution containing 75% H2SO4 (Fenn et al., 1985).
  1410. aop_in(:)%no3(3) = reshape( 1.e9 * nh4no3_factor * (so4_density / nh4no3_density) * &
  1411. rm(i1:i2,j1:j2,1:lmr,ino3_a ) / &
  1412. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1413. aop_in(:)%bc (3) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ibcacs ) / &
  1414. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1415. aop_in(:)%oc (3) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ipomacs) / &
  1416. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1417. aop_in(:)%soa(3) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,isoaacs) / &
  1418. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1419. aop_in(:)%ss (3) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,issacs ) / &
  1420. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1421. aop_in(:)%du (3) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,iduacs ) / &
  1422. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1423. ! COS
  1424. aop_in(:)%so4(4) = reshape( 1.e9 * h2so4_factor * rm(i1:i2,j1:j2,1:lmr,iso4cos) / &
  1425. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1426. !<<< TvN
  1427. aop_in(:)%bc (4) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ibccos ) / &
  1428. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1429. aop_in(:)%oc (4) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ipomcos) / &
  1430. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1431. aop_in(:)%soa(4) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,isoacos) / &
  1432. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1433. aop_in(:)%ss (4) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,isscos ) / &
  1434. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1435. aop_in(:)%du (4) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,iducos ) / &
  1436. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1437. ! AII
  1438. aop_in(:)%bc (5) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ibcaii ) / &
  1439. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1440. aop_in(:)%oc (5) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,ipomaii) / &
  1441. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1442. aop_in(:)%soa(5) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,isoaaii) / &
  1443. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1444. ! ACI
  1445. aop_in(:)%du (6) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,iduaci ) / &
  1446. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1447. ! COI
  1448. aop_in(:)%du (7) = reshape( 1.e9 * rm(i1:i2,j1:j2,1:lmr,iducoi ) / &
  1449. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1450. ! Water in (hydrophillic) modes
  1451. aop_in(:)%h2o(1) = reshape( 1.e9 * h2o_mode(region,1)%d3(i1:i2,j1:j2,1:lmr) / &
  1452. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1453. aop_in(:)%h2o(2) = reshape( 1.e9 * h2o_mode(region,2)%d3(i1:i2,j1:j2,1:lmr) / &
  1454. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1455. aop_in(:)%h2o(3) = reshape( 1.e9 * h2o_mode(region,3)%d3(i1:i2,j1:j2,1:lmr) / &
  1456. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1457. aop_in(:)%h2o(4) = reshape( 1.e9 * h2o_mode(region,4)%d3(i1:i2,j1:j2,1:lmr) / &
  1458. m(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1459. aop_in(:)%rg (1) = reshape( 1.e6 * rw_mode (region,1)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1460. aop_in(:)%rg (2) = reshape( 1.e6 * rw_mode (region,2)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1461. aop_in(:)%rg (3) = reshape( 1.e6 * rw_mode (region,3)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1462. aop_in(:)%rg (4) = reshape( 1.e6 * rw_mode (region,4)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1463. aop_in(:)%rg (5) = reshape( 1.e6 * rw_mode (region,5)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1464. aop_in(:)%rg (6) = reshape( 1.e6 * rw_mode (region,6)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1465. aop_in(:)%rg (7) = reshape( 1.e6 * rw_mode (region,7)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1466. ! dry radius for soluble modes / rest equals the usual radii
  1467. aop_in(:)%rgd(1) = reshape( 1.e6 * rwd_mode(region,1)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1468. aop_in(:)%rgd(2) = reshape( 1.e6 * rwd_mode(region,2)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1469. aop_in(:)%rgd(3) = reshape( 1.e6 * rwd_mode(region,3)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1470. aop_in(:)%rgd(4) = reshape( 1.e6 * rwd_mode(region,4)%d3(i1:i2,j1:j2,1:lmr), (/lvec/) )
  1471. aop_in(:)%rgd(5) = aop_in(:)%rg (5)
  1472. aop_in(:)%rgd(6) = aop_in(:)%rg (6)
  1473. aop_in(:)%rgd(7) = aop_in(:)%rg (7)
  1474. ! volume for number density
  1475. allocate( volume( i1:i2, j1:j2, 1:lmr ) )
  1476. do j = j1, j2
  1477. volume(:,j,:) = ( gph_dat(region)%data(i1:i2, j, 2:lmr+1) - &
  1478. gph_dat(region)%data(i1:i2, j, 1:lmr ) ) * &
  1479. region_dat(region)%dxyp(j) ! m3
  1480. end do
  1481. aop_in(:)%numdens(1) = reshape( rm(i1:i2,j1:j2,1:lmr,inus_n) / volume, (/lvec/) )
  1482. aop_in(:)%numdens(2) = reshape( rm(i1:i2,j1:j2,1:lmr,iais_n) / volume, (/lvec/) )
  1483. aop_in(:)%numdens(3) = reshape( rm(i1:i2,j1:j2,1:lmr,iacs_n) / volume, (/lvec/) )
  1484. aop_in(:)%numdens(4) = reshape( rm(i1:i2,j1:j2,1:lmr,icos_n) / volume, (/lvec/) )
  1485. aop_in(:)%numdens(5) = reshape( rm(i1:i2,j1:j2,1:lmr,iaii_n) / volume, (/lvec/) )
  1486. aop_in(:)%numdens(6) = reshape( rm(i1:i2,j1:j2,1:lmr,iaci_n) / volume, (/lvec/) )
  1487. aop_in(:)%numdens(7) = reshape( rm(i1:i2,j1:j2,1:lmr,icoi_n) / volume, (/lvec/) )
  1488. deallocate( volume )
  1489. ! check valid ranges in particle sizes (might be zero)
  1490. where( aop_in%rg (1) .lt. 1.E-15 ) aop_in%rg (1) = 1.E-15
  1491. where( aop_in%rgd(1) .lt. 1.E-15 ) aop_in%rgd(1) = 1.E-15
  1492. where( aop_in%rg (2) .lt. 1.E-15 ) aop_in%rg (2) = 1.E-15
  1493. where( aop_in%rgd(2) .lt. 1.E-15 ) aop_in%rgd(2) = 1.E-15
  1494. where( aop_in%rg (3) .lt. 1.E-15 ) aop_in%rg (3) = 1.E-15
  1495. where( aop_in%rgd(3) .lt. 1.E-15 ) aop_in%rgd(3) = 1.E-15
  1496. where( aop_in%rg (4) .lt. 1.E-15 ) aop_in%rg (4) = 1.E-15
  1497. where( aop_in%rgd(4) .lt. 1.E-15 ) aop_in%rgd(4) = 1.E-15
  1498. where( aop_in%rg (5) .lt. 1.E-15 ) aop_in%rg (5) = 1.E-15
  1499. where( aop_in%rgd(5) .lt. 1.E-15 ) aop_in%rgd(5) = 1.E-15
  1500. where( aop_in%rg (6) .lt. 1.E-15 ) aop_in%rg (6) = 1.E-15
  1501. where( aop_in%rgd(6) .lt. 1.E-15 ) aop_in%rgd(6) = 1.E-15
  1502. where( aop_in%rg (7) .lt. 1.E-15 ) aop_in%rg (7) = 1.E-15
  1503. where( aop_in%rgd(7) .lt. 1.E-15 ) aop_in%rgd(7) = 1.E-15
  1504. nullify(rm)
  1505. nullify(m)
  1506. !
  1507. aop_out_ext=0.0
  1508. aop_out_a=0.0
  1509. aop_out_g=0.0
  1510. if (present(aop_out_add)) then
  1511. call optics_calculate_aop( nwav, wdep, lvec, ecearth_units, &
  1512. aop_out_ext, aop_out_a, aop_out_g, status, aop_out_add )
  1513. else
  1514. call optics_calculate_aop( nwav, wdep, lvec, ecearth_units, &
  1515. aop_out_ext, aop_out_a, aop_out_g, status )
  1516. endif
  1517. IF_NOTOK_RETURN(status=1)
  1518. ! OK
  1519. Deallocate( aop_in )
  1520. status = 0
  1521. END SUBROUTINE OPTICS_AOP_GET
  1522. !EOC
  1523. END MODULE OPTICS