optics.F90 59 KB

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