source: LMDZ6/branches/contrails/libf/phylmd/ecrad/radiation/radiation_aerosol_optics.F90 @ 5912

Last change on this file since 5912 was 5791, checked in by aborella, 4 months ago

Merge with trunk r5789

File size: 49.1 KB
Line 
1! radiation_aerosol_optics.F90 - Computing aerosol optical properties
2!
3! (C) Copyright 2015- ECMWF.
4!
5! This software is licensed under the terms of the Apache Licence Version 2.0
6! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
7!
8! In applying this licence, ECMWF does not waive the privileges and immunities
9! granted to it by virtue of its status as an intergovernmental organisation
10! nor does it submit to any jurisdiction.
11!
12! Author:  Robin Hogan
13! Email:   r.j.hogan@ecmwf.int
14!
15! Modifications
16!   2018-04-15  R. Hogan  Add "direct" option
17!   2020-11-14  R. Hogan  Add setup_general_aerosol_optics for ecCKD compatibility
18!   2022-03-27  R. Hogan  Add setup_general_aerosol_optics_legacy to use RRTM aerosol files with ecCKD
19!   2022-11-22  P. Ukkonen / R. Hogan  Optimizations to enhance vectorization
20
21#include "ecrad_config.h"
22
23module radiation_aerosol_optics
24
25  implicit none
26  public
27
28contains
29
30  ! Provides the elemental function "delta_eddington_extensive"
31#include "radiation_delta_eddington.h"
32
33  !---------------------------------------------------------------------
34  ! Load aerosol scattering data; this subroutine delegates to one
35  ! in radiation_aerosol_optics_data.F90
36  subroutine setup_aerosol_optics(config)
37
38    use parkind1,                      only : jprb
39    use yomhook,                       only : lhook, dr_hook, jphook
40    use radiation_config,              only : config_type
41    use radiation_aerosol_optics_data, only : aerosol_optics_type
42    use radiation_io,                  only : nulerr, radiation_abort
43
44    type(config_type), intent(inout) :: config
45
46    real(jphook) :: hook_handle
47
48    if (lhook) call dr_hook('radiation_aerosol_optics:setup_aerosol_optics',0,hook_handle)
49
50    if (config%n_aerosol_types > 0) then
51      ! Load data from file and prepare to map config%n_aerosol_types
52      ! aerosol types
53      if (config%use_general_aerosol_optics) then
54        ! Read file containing high spectral resolution optical
55        ! properties and average to the spectral intervals of the
56        ! current gas-optics scheme
57        call setup_general_aerosol_optics(config)
58      else
59        ! Read file containing optical properties already in the bands
60        ! of the gas-optics scheme
61        call config%aerosol_optics%setup(trim(config%aerosol_optics_file_name), &
62             &                           iverbose=config%iverbosesetup)
63      end if
64
65      call config%aerosol_optics%initialize_types(config%n_aerosol_types)
66
67      ! Check agreement in number of bands
68      if (config%n_bands_lw /= config%aerosol_optics%n_bands_lw) then
69        write(nulerr,'(a,i0,a,i0,a)') '*** Error: number of longwave bands (', &
70             &  config%n_bands_lw, ') does not match aerosol optics look-up table (', &
71             &  config%aerosol_optics%n_bands_lw, ')'
72        call radiation_abort()
73      end if
74      if (config%n_bands_sw /= config%aerosol_optics%n_bands_sw) then
75        write(nulerr,'(a)') '*** Error: number of shortwave bands does not match aerosol optics look-up table'
76        call radiation_abort()
77      end if
78
79      ! Map aerosol types to those loaded from the data file
80      call config%aerosol_optics%set_types(config%i_aerosol_type_map(1:config%n_aerosol_types))
81    end if
82
83    if (config%iverbosesetup >= 1) then
84      call config%aerosol_optics%print_description(config%i_aerosol_type_map(1:config%n_aerosol_types))
85    end if
86
87    if (lhook) call dr_hook('radiation_aerosol_optics:setup_aerosol_optics',1,hook_handle)
88
89  end subroutine setup_aerosol_optics
90
91
92  !---------------------------------------------------------------------
93  ! Read file containing high spectral resolution optical properties
94  ! and average to the spectral intervals of the current gas-optics
95  ! scheme
96  subroutine setup_general_aerosol_optics(config)
97
98    use parkind1,                      only : jprb
99    use yomhook,                       only : lhook, dr_hook, jphook
100#ifdef EASY_NETCDF_READ_MPI
101    use easy_netcdf_read_mpi,          only : netcdf_file
102#else
103    use easy_netcdf,                   only : netcdf_file
104#endif
105    use radiation_config,              only : config_type
106    use radiation_aerosol_optics_data, only : aerosol_optics_type
107    use radiation_spectral_definition, only : SolarReferenceTemperature, &
108         &                                    TerrestrialReferenceTemperature
109    use radiation_io,                  only : nulout
110
111    type(config_type), intent(inout), target :: config
112
113    ! The NetCDF file containing the aerosol optics data
114    type(netcdf_file)  :: file
115
116    ! Wavenumber points in NetCDF file
117    real(jprb), allocatable :: wavenumber(:) ! cm-1
118
119    ! Hydrophilic aerosol properties
120    real(jprb), allocatable :: mass_ext_philic(:,:,:)    ! Mass-ext coefficient (m2 kg-1)
121    real(jprb), allocatable :: ssa_philic(:,:,:)         ! Single-scattering albedo
122    real(jprb), allocatable :: g_philic(:,:,:)           ! Asymmetry factor
123    real(jprb), allocatable :: lidar_ratio_philic(:,:,:) ! Lidar ratio (sr)
124
125    ! Hydrophobic aerosol properties
126    real(jprb), allocatable :: mass_ext_phobic(:,:)      ! Mass-ext coefficient (m2 kg-1)
127    real(jprb), allocatable :: ssa_phobic(:,:)           ! Single-scattering albedo
128    real(jprb), allocatable :: g_phobic(:,:)             ! Asymmetry factor
129    real(jprb), allocatable :: lidar_ratio_phobic(:,:)   ! Lidar ratio (sr)
130
131    ! Mapping matrix between optical properties at the wavenumbers in
132    ! the file, and spectral intervals used by the gas-optics scheme
133    real(jprb), allocatable :: mapping(:,:)
134
135    ! Target monochromatic wavenumber for interpolation (cm-1)
136    real(jprb) :: wavenumber_target
137
138    ! Number of spectral points describing aerosol properties in the
139    ! shortwave and longwave
140    integer    :: nspecsw, nspeclw
141
142    ! Number of monochromatic wavelengths required
143    integer    :: nmono
144
145    integer    :: n_type_philic, n_type_phobic, nrh, nwn
146    integer    :: jtype, jwl, iwn
147
148    ! Weight of first point in interpolation
149    real(jprb) :: weight1
150
151    real(jphook) :: hook_handle
152
153    if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics',0,hook_handle)
154
155    associate(ao => config%aerosol_optics)
156
157      call file%open(trim(config%aerosol_optics_file_name), iverbose=config%iverbosesetup)
158
159      if (.not. file%exists('wavenumber')) then
160        ! Assume we have an old-style aerosol optics file with optical
161        ! properties provided per pre-defined band
162        call file%close()
163        if (config%iverbosesetup >= 2) then
164          write(nulout,'(a)') 'Legacy aerosol optics file: mapping between bands'
165        end if
166        call setup_general_aerosol_optics_legacy(config, trim(config%aerosol_optics_file_name))
167        if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics',1,hook_handle)
168        return
169      end if
170
171      if (file%exists('mass_ext_hydrophilic')) then
172        ao%use_hydrophilic = .true.
173      else
174        ao%use_hydrophilic = .false.
175      end if
176
177      call file%get('wavenumber', wavenumber)
178      nwn = size(wavenumber)
179
180      ! Read the raw scattering data
181      call file%get('mass_ext_hydrophobic',    mass_ext_phobic)
182      call file%get('ssa_hydrophobic',         ssa_phobic)
183      call file%get('asymmetry_hydrophobic',   g_phobic)
184      call file%get('lidar_ratio_hydrophobic', lidar_ratio_phobic)
185
186      call file%get_global_attribute('description_hydrophobic', &
187          &                         ao%description_phobic_str)
188
189      if (ao%use_hydrophilic) then
190        call file%get('mass_ext_hydrophilic',    mass_ext_philic)
191        call file%get('ssa_hydrophilic',         ssa_philic)
192        call file%get('asymmetry_hydrophilic',   g_philic)
193        call file%get('lidar_ratio_hydrophilic', lidar_ratio_philic)
194
195        call file%get('relative_humidity1',      ao%rh_lower)
196
197        call file%get_global_attribute('description_hydrophilic', &
198            &                         ao%description_philic_str)
199      end if
200
201      ! Close aerosol scattering file
202      call file%close()
203
204      n_type_phobic = size(mass_ext_phobic, 2)
205      if (ao%use_hydrophilic) then
206        n_type_philic = size(mass_ext_philic, 3)
207        nrh = size(ao%rh_lower)
208      else
209        n_type_philic = 0
210        nrh = 0
211      end if
212
213      if (config%do_cloud_aerosol_per_sw_g_point) then
214        nspecsw = config%gas_optics_sw%spectral_def%ng
215      else
216        nspecsw = config%gas_optics_sw%spectral_def%nband
217      end if
218
219      if (config%do_cloud_aerosol_per_lw_g_point) then
220        nspeclw = config%gas_optics_lw%spectral_def%ng
221      else
222        nspeclw = config%gas_optics_lw%spectral_def%nband
223      end if
224
225      if (allocated(ao%wavelength_mono)) then
226        ! Monochromatic wavelengths also required
227        nmono = size(ao%wavelength_mono)
228      else
229        nmono = 0
230      end if
231
232      call ao%allocate(n_type_phobic, n_type_philic, nrh, nspeclw, nspecsw, nmono)
233
234      if (config%do_sw) then
235        call config%gas_optics_sw%spectral_def%calc_mapping(wavenumber, mapping, &
236            &          use_bands=(.not. config%do_cloud_aerosol_per_sw_g_point))
237
238        ao%mass_ext_sw_phobic = matmul(mapping, mass_ext_phobic)
239        ao%ssa_sw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic) &
240            &           / ao%mass_ext_sw_phobic
241        ao%g_sw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic*g_phobic) &
242            &         / (ao%mass_ext_sw_phobic*ao%ssa_sw_phobic)
243
244        if (ao%use_hydrophilic) then
245          do jtype = 1,n_type_philic
246            ao%mass_ext_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype))
247            ao%ssa_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) &
248                &                                        *ssa_philic(:,:,jtype)) &
249                &           / ao%mass_ext_sw_philic(:,:,jtype)
250            ao%g_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) &
251                &                       *ssa_philic(:,:,jtype)*g_philic(:,:,jtype)) &
252                &         / (ao%mass_ext_sw_philic(:,:,jtype)*ao%ssa_sw_philic(:,:,jtype))
253          end do
254        end if
255      end if
256
257      if (config%do_lw) then
258        call config%gas_optics_lw%spectral_def%calc_mapping(wavenumber, mapping, &
259            &          use_bands=(.not. config%do_cloud_aerosol_per_lw_g_point))
260
261        ao%mass_ext_lw_phobic = matmul(mapping, mass_ext_phobic)
262        ao%ssa_lw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic) &
263            &           / ao%mass_ext_lw_phobic
264        ao%g_lw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic*g_phobic) &
265            &         / (ao%mass_ext_lw_phobic*ao%ssa_lw_phobic)
266
267        if (ao%use_hydrophilic) then
268          do jtype = 1,n_type_philic
269            ao%mass_ext_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype))
270            ao%ssa_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) &
271                &                                        *ssa_philic(:,:,jtype)) &
272                &           / ao%mass_ext_lw_philic(:,:,jtype)
273            ao%g_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) &
274                &                       *ssa_philic(:,:,jtype)*g_philic(:,:,jtype)) &
275                &         / (ao%mass_ext_lw_philic(:,:,jtype)*ao%ssa_lw_philic(:,:,jtype))
276          end do
277        end if
278      end if
279
280      if (allocated(ao%wavelength_mono)) then
281        ! Monochromatic wavelengths also required
282        do jwl = 1,nmono
283          ! Wavelength (m) to wavenumber (cm-1)
284          wavenumber_target = 0.01_jprb / ao%wavelength_mono(jwl)
285          ! Find index to first interpolation point, and its weight
286          if (wavenumber_target <= wavenumber(1)) then
287            weight1 = 1.0_jprb
288            iwn = 1
289          else if (wavenumber_target >= wavenumber(nwn)) then
290            iwn = nwn-1
291            weight1 = 0.0_jprb
292          else
293            iwn = 1
294            do while (wavenumber(iwn+1) < wavenumber_target .and. iwn < nwn-1)
295              iwn = iwn + 1
296            end do
297            weight1 = (wavenumber(iwn+1)-wavenumber_target) &
298                &  / (wavenumber(iwn+1)-wavenumber(iwn))
299          end if
300          ! Linear interpolation
301          ao%mass_ext_mono_phobic(jwl,:) = weight1 * mass_ext_phobic(iwn,:) &
302              &             + (1.0_jprb - weight1)* mass_ext_phobic(iwn+1,:)
303          ao%ssa_mono_phobic(jwl,:)      = weight1 * ssa_phobic(iwn,:) &
304              &             + (1.0_jprb - weight1)* ssa_phobic(iwn+1,:)
305          ao%g_mono_phobic(jwl,:)        = weight1 * g_phobic(iwn,:) &
306              &             + (1.0_jprb - weight1)* g_phobic(iwn+1,:)
307          ao%lidar_ratio_mono_phobic(jwl,:) = weight1 * lidar_ratio_phobic(iwn,:) &
308              &                + (1.0_jprb - weight1)* lidar_ratio_phobic(iwn+1,:)
309          if (ao%use_hydrophilic) then
310            ao%mass_ext_mono_philic(jwl,:,:) = weight1 * mass_ext_philic(iwn,:,:) &
311                &               + (1.0_jprb - weight1)* mass_ext_philic(iwn+1,:,:)
312            ao%ssa_mono_philic(jwl,:,:)      = weight1 * ssa_philic(iwn,:,:) &
313                &               + (1.0_jprb - weight1)* ssa_philic(iwn+1,:,:)
314            ao%g_mono_philic(jwl,:,:)        = weight1 * g_philic(iwn,:,:) &
315                &               + (1.0_jprb - weight1)* g_philic(iwn+1,:,:)
316            ao%lidar_ratio_mono_philic(jwl,:,:) = weight1 * lidar_ratio_philic(iwn,:,:) &
317                &                  + (1.0_jprb - weight1)* lidar_ratio_philic(iwn+1,:,:)
318          end if
319        end do
320      end if
321
322      ! Deallocate memory local to this routine
323      deallocate(mass_ext_phobic)
324      deallocate(ssa_phobic)
325      deallocate(g_phobic)
326      deallocate(lidar_ratio_phobic)
327      if (ao%use_hydrophilic) then
328        deallocate(mass_ext_philic)
329        deallocate(ssa_philic)
330        deallocate(g_philic)
331        deallocate(lidar_ratio_philic)
332      end if
333
334    end associate
335
336    if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics',1,hook_handle)
337
338  end subroutine setup_general_aerosol_optics
339
340
341  !---------------------------------------------------------------------
342  ! Read file containing legacy-style band-wise aerosol optical
343  ! properties and average to the spectral intervals of the current
344  ! gas-optics scheme
345  subroutine setup_general_aerosol_optics_legacy(config, file_name)
346
347    use parkind1,                      only : jprb
348    use yomhook,                       only : lhook, dr_hook, jphook
349#ifdef EASY_NETCDF_READ_MPI
350    use easy_netcdf_read_mpi,          only : netcdf_file
351#else
352    use easy_netcdf,                   only : netcdf_file
353#endif
354    use radiation_config,              only : config_type
355    use radiation_aerosol_optics_data, only : aerosol_optics_type
356    use radiation_spectral_definition, only : SolarReferenceTemperature, &
357         &                                    TerrestrialReferenceTemperature
358
359    type(config_type), intent(inout), target :: config
360
361    ! The NetCDF file containing the aerosol optics data
362    character(len=*), intent(in) :: file_name
363
364    ! Mapping matrix between optical properties at the wavenumbers in
365    ! the file, and spectral intervals used by the gas-optics scheme
366    real(jprb), allocatable :: mapping(:,:), mapping_transp(:,:)
367
368    ! Pointer to the aerosol optics coefficients for brevity of access
369    type(aerosol_optics_type), pointer :: ao
370
371    ! Local copy of aerosol optical properties in the spectral
372    ! intervals of the file, which is deallocated when it goes out of
373    ! scope
374    type(aerosol_optics_type) :: ao_legacy
375
376    integer :: jtype
377
378    real(jphook) :: hook_handle
379
380    if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics_legacy',0,hook_handle)
381    ao => config%aerosol_optics
382
383    ! Load file into a local structure
384    call ao_legacy%setup(file_name, iverbose=config%iverbosesetup)
385
386    ! Copy over scalars and coordinate variables
387    call ao%allocate(ao_legacy%n_type_phobic, ao_legacy%n_type_philic, ao_legacy%nrh, &
388         &           config%n_bands_lw, config%n_bands_sw, ao_legacy%n_mono_wl)
389    ao%description_phobic_str = ao_legacy%description_phobic_str
390    if (ao_legacy%use_hydrophilic) then
391      ao%description_philic_str = ao_legacy%description_philic_str
392      ao%rh_lower = ao_legacy%rh_lower
393    end if
394
395    ! use_hydrophilic = ao_legacy%use_hydrophilic
396    ! ao%iclass = ao_legacy%iclass
397    ! ao%itype = ao_legacy%itype
398    ! ao%ntype = ao_legacy%ntype
399    ! ao%n_type_phobic = ao_legacy%n_type_phobic
400    ! ao%n_type_philic = ao_legacy%n_type_philic
401    ! ao%n_mono_wl = ao_legacy%n_mono_wl
402    ! ao%use_monochromatic = ao_legacy%use_monochromatic
403
404    if (config%do_sw) then
405      call config%gas_optics_sw%spectral_def%calc_mapping_from_wavenumber_bands( &
406           &  ao_legacy%wavenumber1_sw, ao_legacy%wavenumber2_sw, mapping_transp, &
407           &  use_bands=(.not. config%do_cloud_aerosol_per_sw_g_point))
408      if (allocated(mapping)) then
409        deallocate(mapping)
410      end if
411      allocate(mapping(config%n_bands_sw,ao_legacy%n_bands_sw))
412      mapping = transpose(mapping_transp)
413      ao%mass_ext_sw_phobic = matmul(mapping, ao_legacy%mass_ext_sw_phobic)
414      ao%ssa_sw_phobic = matmul(mapping, ao_legacy%mass_ext_sw_phobic*ao_legacy%ssa_sw_phobic) &
415           &           / ao%mass_ext_sw_phobic
416      ao%g_sw_phobic = matmul(mapping, ao_legacy%mass_ext_sw_phobic*ao_legacy%ssa_sw_phobic &
417           &                           *ao_legacy%g_sw_phobic) &
418           &         / (ao%mass_ext_sw_phobic*ao%ssa_sw_phobic)
419
420      if (ao%use_hydrophilic) then
421        do jtype = 1,ao%n_type_philic
422          ao%mass_ext_sw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_sw_philic(:,:,jtype))
423          ao%ssa_sw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_sw_philic(:,:,jtype) &
424               &                                        *ao_legacy%ssa_sw_philic(:,:,jtype)) &
425               &           / ao%mass_ext_sw_philic(:,:,jtype)
426          ao%g_sw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_sw_philic(:,:,jtype) &
427               &               *ao_legacy%ssa_sw_philic(:,:,jtype)*ao_legacy%g_sw_philic(:,:,jtype)) &
428               &         / (ao%mass_ext_sw_philic(:,:,jtype)*ao%ssa_sw_philic(:,:,jtype))
429        end do
430      end if
431    end if
432
433    if (config%do_lw) then
434      if (allocated(mapping_transp)) then
435        deallocate(mapping_transp)
436      end if
437      call config%gas_optics_lw%spectral_def%calc_mapping_from_wavenumber_bands( &
438           &  ao_legacy%wavenumber1_lw, ao_legacy%wavenumber2_lw, mapping_transp, &
439           &  use_bands=(.not. config%do_cloud_aerosol_per_lw_g_point))
440      if (allocated(mapping)) then
441        deallocate(mapping)
442      end if
443      allocate(mapping(config%n_bands_lw,ao_legacy%n_bands_lw))
444      mapping = transpose(mapping_transp)
445      ao%mass_ext_lw_phobic = matmul(mapping, ao_legacy%mass_ext_lw_phobic)
446
447      where (ao%mass_ext_lw_phobic /= 0)
448         ao%ssa_lw_phobic = matmul(mapping, ao_legacy%mass_ext_lw_phobic*ao_legacy%ssa_lw_phobic) &
449              &           / ao%mass_ext_lw_phobic
450         ao%g_lw_phobic = matmul(mapping, ao_legacy%mass_ext_lw_phobic*ao_legacy%ssa_lw_phobic &
451              &                           *ao_legacy%g_lw_phobic) &
452              &         / (ao%mass_ext_lw_phobic*ao%ssa_lw_phobic)
453      elsewhere
454         ao%ssa_lw_phobic = 1.
455         ao%g_lw_phobic = 0.
456      end where
457
458      if (ao%use_hydrophilic) then
459        do jtype = 1,ao%n_type_philic
460          ao%mass_ext_lw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_lw_philic(:,:,jtype))
461
462          where (ao%mass_ext_lw_philic(:,:,jtype) /= 0.)
463             ao%ssa_lw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_lw_philic(:,:,jtype) &
464                  &                                        *ao_legacy%ssa_lw_philic(:,:,jtype)) &
465                  &           / ao%mass_ext_lw_philic(:,:,jtype)
466             ao%g_lw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_lw_philic(:,:,jtype) &
467                  &               *ao_legacy%ssa_lw_philic(:,:,jtype)*ao_legacy%g_lw_philic(:,:,jtype)) &
468                  &         / (ao%mass_ext_lw_philic(:,:,jtype)*ao%ssa_lw_philic(:,:,jtype))
469          elsewhere
470             ao%ssa_lw_philic(:,:,jtype) = 1.
471             ao%g_lw_philic(:,:,jtype) = 0.
472          end where
473        end do
474      end if
475    end if
476
477    if (allocated(ao_legacy%wavelength_mono)) then
478      ao%wavelength_mono = ao_legacy%wavelength_mono
479      ao%mass_ext_mono_phobic = ao_legacy%mass_ext_mono_phobic
480      ao%ssa_mono_phobic = ao_legacy%ssa_mono_phobic
481      ao%g_mono_phobic = ao_legacy%g_mono_phobic
482      ao%lidar_ratio_mono_phobic = ao_legacy%lidar_ratio_mono_phobic
483      if (ao%use_hydrophilic) then
484        ao%mass_ext_mono_philic = ao_legacy%mass_ext_mono_philic
485        ao%ssa_mono_philic = ao_legacy%ssa_mono_philic
486        ao%g_mono_philic = ao_legacy%g_mono_philic
487        ao%lidar_ratio_mono_philic = ao_legacy%lidar_ratio_mono_philic
488      end if
489    end if
490
491    if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics_legacy',1,hook_handle)
492
493  end subroutine setup_general_aerosol_optics_legacy
494
495
496  !---------------------------------------------------------------------
497  ! Compute aerosol optical properties and add to existing gas optical
498  ! depth and scattering properties
499  subroutine add_aerosol_optics(nlev,istartcol,iendcol, &
500       &  config, thermodynamics, gas, aerosol, &
501       &  od_lw, ssa_lw, g_lw, od_sw, ssa_sw, g_sw)
502
503    use parkind1,                      only : jprb
504    use radiation_io,                  only : nulout, nulerr, radiation_abort
505    use yomhook,                       only : lhook, dr_hook, jphook
506    use radiation_config,              only : config_type
507    use radiation_thermodynamics,      only : thermodynamics_type
508    use radiation_gas,                 only : gas_type, IH2O, IMassMixingRatio
509    use radiation_aerosol,             only : aerosol_type
510    use radiation_constants,           only : AccelDueToGravity
511    use radiation_aerosol_optics_data, only : aerosol_optics_type, &
512         &  IAerosolClassUndefined,   IAerosolClassIgnored, &
513         &  IAerosolClassHydrophobic, IAerosolClassHydrophilic
514
515    real(jprb), parameter :: OneOverAccelDueToGravity = 1.0_jprb / AccelDueToGravity
516
517    integer, intent(in) :: nlev               ! number of model levels
518    integer, intent(in) :: istartcol, iendcol ! range of columns to process
519    type(config_type), intent(in), target :: config
520    type(thermodynamics_type),intent(in)  :: thermodynamics
521    type(gas_type),           intent(in)  :: gas
522    type(aerosol_type),       intent(in)  :: aerosol
523    ! Optical depth, single scattering albedo and asymmetry factor of
524    ! the atmosphere (gases on input, gases and aerosols on output)
525    ! for each g point. Note that longwave ssa and asymmetry and
526    ! shortwave asymmetry are all zero for gases, so are not yet
527    ! defined on input and are therefore intent(out).
528    real(jprb), dimension(config%n_g_lw,nlev,istartcol:iendcol), &
529         &   intent(inout) :: od_lw
530    real(jprb), dimension(config%n_g_lw_if_scattering,nlev,istartcol:iendcol), &
531         &   intent(out)   :: ssa_lw, g_lw
532    real(jprb), dimension(config%n_g_sw,nlev,istartcol:iendcol), &
533         &   intent(inout) :: od_sw, ssa_sw
534    real(jprb), dimension(config%n_g_sw,nlev,istartcol:iendcol), &
535         &   intent(out)   :: g_sw
536
537    ! Extinction optical depth, scattering optical depth and
538    ! asymmetry-times-scattering-optical-depth for all the aerosols in
539    ! a column for each spectral band of the shortwave and longwave
540    ! spectrum
541    real(jprb), dimension(config%n_bands_sw,nlev) &
542         &  :: od_sw_aerosol, scat_sw_aerosol, scat_g_sw_aerosol
543    real(jprb), dimension(config%n_bands_lw,nlev) &
544         &  :: od_lw_aerosol
545    real(jprb), dimension(config%n_bands_lw_if_scattering,nlev) &
546         &  :: scat_lw_aerosol, scat_g_lw_aerosol
547
548    real(jprb) :: local_od_sw, local_od_lw
549
550    real(jprb) :: h2o_mmr(istartcol:iendcol,nlev)
551
552    real(jprb) :: rh ! Relative humidity with respect to liquid water
553
554    ! Factor (kg m-2) to convert mixing ratio (kg kg-1) to mass in
555    ! path (kg m-2)
556    real(jprb) :: factor(nlev)
557
558    ! Temporary extinction and scattering optical depths of aerosol
559    ! plus gas
560    real(jprb) :: local_od, local_scat
561
562    ! Aerosol mixing ratio as a scalar
563    real(jprb) :: mixing_ratio
564
565    ! Loop indices for column, level, g point, band and aerosol type
566    integer :: jcol, jlev, jg, jtype, jband
567
568    ! Range of levels over which aerosols are present
569    integer :: istartlev, iendlev
570
571    ! Indices to spectral band and relative humidity look-up table
572    integer :: iband, irh, irhs(nlev)
573
574    ! Short cut for ao%itype(jtype)
575    integer :: itype
576
577    ! Pointer to the aerosol optics coefficients for brevity of access
578    type(aerosol_optics_type), pointer :: ao
579
580    real(jphook) :: hook_handle
581
582    if (lhook) call dr_hook('radiation_aerosol_optics:add_aerosol_optics',0,hook_handle)
583
584    if (aerosol%is_direct) then
585      ! Aerosol optical properties have been provided in each band
586      ! directly by the user
587      call add_aerosol_optics_direct(nlev,istartcol,iendcol, &
588           &  config, aerosol, &
589           &  od_lw, ssa_lw, g_lw, od_sw, ssa_sw, g_sw)
590    else
591      ! Aerosol mixing ratios have been provided
592
593      do jtype = 1,config%n_aerosol_types
594        if (config%aerosol_optics%iclass(jtype) == IAerosolClassUndefined) then
595          write(nulerr,'(a)') '*** Error: not all aerosol types are defined'
596          call radiation_abort()
597        end if
598      end do
599
600      if (config%iverbose >= 2) then
601        write(nulout,'(a)') 'Computing aerosol absorption/scattering properties'
602      end if
603
604      ao => config%aerosol_optics
605
606      istartlev = lbound(aerosol%mixing_ratio,2)
607      iendlev   = ubound(aerosol%mixing_ratio,2)
608
609      if (ubound(aerosol%mixing_ratio,3) /= config%n_aerosol_types) then
610        write(nulerr,'(a,i0,a,i0)') '*** Error: aerosol%mixing_ratio contains ', &
611             &  ubound(aerosol%mixing_ratio,3), ' aerosol types, expected ', &
612             &  config%n_aerosol_types
613        call radiation_abort()
614      end if
615
616      ! Set variables to zero that may not have been previously
617      g_sw(:,:,istartcol:iendcol) = 0.0_jprb
618      if (config%do_lw_aerosol_scattering) then
619        ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb
620        g_lw(:,:,istartcol:iendcol)   = 0.0_jprb
621      end if
622
623      call gas%get(IH2O, IMassMixingRatio, h2o_mmr, istartcol=istartcol)
624
625      ! Loop over column
626      do jcol = istartcol,iendcol
627
628        ! Reset temporary arrays
629        od_sw_aerosol     = 0.0_jprb
630        scat_sw_aerosol   = 0.0_jprb
631        scat_g_sw_aerosol = 0.0_jprb
632        od_lw_aerosol     = 0.0_jprb
633        scat_lw_aerosol   = 0.0_jprb
634        scat_g_lw_aerosol = 0.0_jprb
635
636        do jlev = istartlev,iendlev
637          ! Compute relative humidity with respect to liquid
638          ! saturation and the index to the relative-humidity index of
639          ! hydrophilic-aerosol data
640          rh  = h2o_mmr(jcol,jlev) / thermodynamics%h2o_sat_liq(jcol,jlev)
641          irhs(jlev) = ao%calc_rh_index(rh)
642
643          factor(jlev) = ( thermodynamics%pressure_hl(jcol,jlev+1) &
644               &    -thermodynamics%pressure_hl(jcol,jlev  )  ) &
645               &   * OneOverAccelDueToGravity
646        end do
647
648        do jtype = 1,config%n_aerosol_types
649          itype = ao%itype(jtype)
650
651          ! Add the optical depth, scattering optical depth and
652          ! scattering optical depth-weighted asymmetry factor for
653          ! this aerosol type to the total for all aerosols.  Note
654          ! that the following expressions are array-wise, the
655          ! dimension being spectral band.
656          if (ao%iclass(jtype) == IAerosolClassHydrophobic) then
657            do jlev = istartlev,iendlev
658              mixing_ratio = aerosol%mixing_ratio(jcol,jlev,jtype)
659              do jband = 1,config%n_bands_sw
660                local_od_sw = factor(jlev) * mixing_ratio &
661                     &  * ao%mass_ext_sw_phobic(jband,itype)
662                od_sw_aerosol(jband,jlev) = od_sw_aerosol(jband,jlev) + local_od_sw
663                scat_sw_aerosol(jband,jlev) = scat_sw_aerosol(jband,jlev) &
664                     &  + local_od_sw * ao%ssa_sw_phobic(jband,itype)
665                scat_g_sw_aerosol(jband,jlev) = scat_g_sw_aerosol(jband,jlev) &
666                     &  + local_od_sw * ao%ssa_sw_phobic(jband,itype) &
667                     &  * ao%g_sw_phobic(jband,itype)
668              end do
669              if (config%do_lw_aerosol_scattering) then
670                do jband = 1,config%n_bands_lw
671                  local_od_lw = factor(jlev) * mixing_ratio &
672                       &  * ao%mass_ext_lw_phobic(jband,itype)
673                  od_lw_aerosol(jband,jlev) = od_lw_aerosol(jband,jlev) + local_od_lw
674                  scat_lw_aerosol(jband,jlev) = scat_lw_aerosol(jband,jlev) &
675                       &  + local_od_lw * ao%ssa_lw_phobic(jband,itype)
676                  scat_g_lw_aerosol(jband,jlev) = scat_g_lw_aerosol(jband,jlev) &
677                       &  + local_od_lw * ao%ssa_lw_phobic(jband,itype) &
678                       &  * ao%g_lw_phobic(jband,itype)
679                end do
680              else
681                ! If aerosol longwave scattering is not included then we
682                ! weight the optical depth by the single scattering
683                ! co-albedo
684                do jband = 1,config%n_bands_lw
685                  od_lw_aerosol(jband,jlev) = od_lw_aerosol(jband,jlev) &
686                       &  + factor(jlev) * mixing_ratio &
687                       &  * ao%mass_ext_lw_phobic(jband,itype) &
688                       &  * (1.0_jprb - ao%ssa_lw_phobic(jband,itype))
689                end do
690              end if
691            end do
692
693          else if (ao%iclass(jtype) == IAerosolClassHydrophilic) then
694            ! Hydrophilic aerosols require the look-up tables to
695            ! be indexed with irh
696            do jlev = istartlev,iendlev
697              mixing_ratio = aerosol%mixing_ratio(jcol,jlev,jtype)
698              irh = irhs(jlev)
699              do jband = 1,config%n_bands_sw
700                local_od_sw = factor(jlev) * mixing_ratio &
701                     &  * ao%mass_ext_sw_philic(jband,irh,itype)
702                od_sw_aerosol(jband,jlev) = od_sw_aerosol(jband,jlev) + local_od_sw
703                scat_sw_aerosol(jband,jlev) = scat_sw_aerosol(jband,jlev) &
704                     &  + local_od_sw * ao%ssa_sw_philic(jband,irh,itype)
705                scat_g_sw_aerosol(jband,jlev) = scat_g_sw_aerosol(jband,jlev) &
706                     &  + local_od_sw * ao%ssa_sw_philic(jband,irh,itype) &
707                     &  * ao%g_sw_philic(jband,irh,itype)
708              end do
709              if (config%do_lw_aerosol_scattering) then
710                do jband = 1,config%n_bands_lw
711                  local_od_lw = factor(jlev) * mixing_ratio &
712                       &  * ao%mass_ext_lw_philic(jband,irh,itype)
713                  od_lw_aerosol(jband,jlev) = od_lw_aerosol(jband,jlev) + local_od_lw
714                  scat_lw_aerosol(jband,jlev) = scat_lw_aerosol(jband,jlev) &
715                       &  + local_od_lw * ao%ssa_lw_philic(jband,irh,itype)
716                  scat_g_lw_aerosol(jband,jlev) = scat_g_lw_aerosol(jband,jlev) &
717                       &  + local_od_lw * ao%ssa_lw_philic(jband,irh,itype) &
718                       &  * ao%g_lw_philic(jband,irh,itype)
719                end do
720              else
721                ! If aerosol longwave scattering is not included then we
722                ! weight the optical depth by the single scattering
723                ! co-albedo
724                do jband = 1,config%n_bands_lw
725                  od_lw_aerosol(jband,jlev) = od_lw_aerosol(jband,jlev) &
726                       &  + factor(jlev) * mixing_ratio &
727                       &  * ao%mass_ext_lw_philic(jband,irh,itype) &
728                       &  * (1.0_jprb - ao%ssa_lw_philic(jband,irh,itype))
729                end do
730              end if
731            end do
732
733            ! Implicitly, if ao%iclass(jtype) == IAerosolClassNone, then
734            ! no aerosol scattering properties are added
735          end if
736
737        end do ! Loop over aerosol type
738
739        if (.not. config%do_sw_delta_scaling_with_gases) then
740          ! Delta-Eddington scaling on aerosol only.  Note that if
741          ! do_sw_delta_scaling_with_gases==.true. then the delta
742          ! scaling is done to the cloud-aerosol-gas mixture inside
743          ! the solver
744          call delta_eddington_extensive_vec(config%n_bands_sw*nlev, od_sw_aerosol, &
745               &                             scat_sw_aerosol, scat_g_sw_aerosol)
746        end if
747
748        ! Combine aerosol shortwave scattering properties with gas
749        ! properties (noting that any gas scattering will have an
750        ! asymmetry factor of zero)
751        if (config%do_cloud_aerosol_per_sw_g_point) then
752
753          ! We can assume the band and g-point indices are the same
754          do jlev = 1,nlev
755            do jg = 1,config%n_g_sw
756              local_scat = ssa_sw(jg,jlev,jcol)*od_sw(jg,jlev,jcol) + scat_sw_aerosol(jg,jlev)
757              od_sw(jg,jlev,jcol) = od_sw(jg,jlev,jcol) + od_sw_aerosol(jg,jlev)
758              g_sw(jg,jlev,jcol) = scat_g_sw_aerosol(jg,jlev) / max(local_scat, 1.0e-24_jprb)
759              ssa_sw(jg,jlev,jcol) = min(local_scat / max(od_sw(jg,jlev,jcol), 1.0e-24_jprb), 1.0_jprb)
760            end do
761          end do
762
763        else
764
765          do jlev = 1,nlev
766            do jg = 1,config%n_g_sw
767              ! Need to map between bands and g-points
768              iband = config%i_band_from_reordered_g_sw(jg)
769              local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband,jlev)
770              if (local_od > 0.0_jprb .and. od_sw_aerosol(iband,jlev) > 0.0_jprb) then
771                local_scat = ssa_sw(jg,jlev,jcol) * od_sw(jg,jlev,jcol) &
772                     &  + scat_sw_aerosol(iband,jlev)
773                ! Note that asymmetry_sw of gases is zero so the following
774                ! simply weights the aerosol asymmetry by the scattering
775                ! optical depth
776                if (local_scat > 0.0_jprb) then
777                  g_sw(jg,jlev,jcol) = scat_g_sw_aerosol(iband,jlev) / local_scat
778                end if
779                ssa_sw(jg,jlev,jcol) = local_scat / local_od
780                od_sw (jg,jlev,jcol) = local_od
781              end if
782            end do
783          end do
784
785        end if
786
787        ! Combine aerosol longwave scattering properties with gas
788        ! properties, noting that in the longwave, gases do not
789        ! scatter at all
790        if (config%do_lw_aerosol_scattering) then
791
792          call delta_eddington_extensive_vec(config%n_bands_lw*nlev, od_lw_aerosol, &
793               &                             scat_lw_aerosol, scat_g_lw_aerosol)
794
795          do jlev = istartlev,iendlev
796            do jg = 1,config%n_g_lw
797              iband = config%i_band_from_reordered_g_lw(jg)
798              local_od = od_lw(jg,jlev,jcol) + od_lw_aerosol(iband,jlev)
799              if (local_od > 0.0_jprb .and. od_lw_aerosol(iband,jlev) > 0.0_jprb) then
800                ! All scattering is due to aerosols, therefore the
801                ! asymmetry factor is equal to the value for aerosols
802                if (scat_lw_aerosol(iband,jlev) > 0.0_jprb) then
803                  g_lw(jg,jlev,jcol) = scat_g_lw_aerosol(iband,jlev) &
804                       &  / scat_lw_aerosol(iband,jlev)
805                end if
806                ssa_lw(jg,jlev,jcol) = scat_lw_aerosol(iband,jlev) / local_od
807                od_lw (jg,jlev,jcol) = local_od
808              end if
809            end do
810          end do
811
812        else
813
814          if (config%do_cloud_aerosol_per_lw_g_point) then
815            ! We can assume band and g-point indices are the same
816            do jlev = istartlev,iendlev
817              do jg = 1,config%n_g_lw
818                od_lw(jg,jlev,jcol) = od_lw(jg,jlev,jcol) + od_lw_aerosol(jg,jlev)
819              end do
820            end do
821          else
822            do jlev = istartlev,iendlev
823              do jg = 1,config%n_g_lw
824                od_lw(jg,jlev,jcol) = od_lw(jg,jlev,jcol) &
825                     &  + od_lw_aerosol(config%i_band_from_reordered_g_lw(jg),jlev)
826              end do
827            end do
828          end if
829
830        end if
831
832      end do ! Loop over column
833
834    end if
835
836    if (lhook) call dr_hook('radiation_aerosol_optics:add_aerosol_optics',1,hook_handle)
837
838  end subroutine add_aerosol_optics
839
840
841  !---------------------------------------------------------------------
842  ! Add precomputed optical properties to gas optical depth and
843  ! scattering properties
844  subroutine add_aerosol_optics_direct(nlev,istartcol,iendcol, &
845       &  config, aerosol, &
846       &  od_lw, ssa_lw, g_lw, od_sw, ssa_sw, g_sw)
847
848    use parkind1,                      only : jprb
849    use radiation_io,                  only : nulerr, radiation_abort
850    use yomhook,                       only : lhook, dr_hook, jphook
851    use radiation_config,              only : config_type
852    use radiation_aerosol,             only : aerosol_type
853
854    integer, intent(in) :: nlev               ! number of model levels
855    integer, intent(in) :: istartcol, iendcol ! range of columns to process
856    type(config_type), intent(in), target :: config
857    type(aerosol_type),       intent(in)  :: aerosol
858    ! Optical depth, single scattering albedo and asymmetry factor of
859    ! the atmosphere (gases on input, gases and aerosols on output)
860    ! for each g point. Note that longwave ssa and asymmetry and
861    ! shortwave asymmetry are all zero for gases, so are not yet
862    ! defined on input and are therefore intent(out).
863    real(jprb), dimension(config%n_g_lw,nlev,istartcol:iendcol), &
864         &   intent(inout) :: od_lw
865    real(jprb), dimension(config%n_g_lw_if_scattering,nlev,istartcol:iendcol), &
866         &   intent(out)   :: ssa_lw, g_lw
867    real(jprb), dimension(config%n_g_sw,nlev,istartcol:iendcol), &
868         &   intent(inout) :: od_sw, ssa_sw
869    real(jprb), dimension(config%n_g_sw,nlev,istartcol:iendcol), &
870         &   intent(out)   :: g_sw
871
872    ! Temporary extinction and scattering optical depths of aerosol
873    ! plus gas
874    real(jprb) :: local_od, local_scat
875
876    ! Extinction optical depth, scattering optical depth and
877    ! asymmetry-times-scattering-optical-depth for all the aerosols at
878    ! a point in space for each spectral band of the shortwave and
879    ! longwave spectrum
880    real(jprb), dimension(config%n_bands_sw,nlev) &
881         & :: od_sw_aerosol, scat_sw_aerosol, scat_g_sw_aerosol
882    real(jprb), dimension(config%n_bands_lw,nlev) :: od_lw_aerosol
883    real(jprb), dimension(config%n_bands_lw_if_scattering,nlev) &
884         & :: scat_lw_aerosol, scat_g_lw_aerosol
885
886    ! Loop indices for column, level, g point and band
887    integer :: jcol, jlev, jg, jb
888
889    ! Range of levels over which aerosols are present
890    integer :: istartlev, iendlev
891
892    ! Indices to spectral band
893    integer :: iband
894
895    real(jphook) :: hook_handle
896
897    if (lhook) call dr_hook('radiation_aerosol_optics:add_aerosol_optics_direct',0,hook_handle)
898
899    if (config%do_sw) then
900      ! Check array dimensions
901      if (ubound(aerosol%od_sw,1) /= config%n_bands_sw) then
902        write(nulerr,'(a,i0,a,i0)') '*** Error: aerosol%od_sw contains ', &
903           &  ubound(aerosol%od_sw,1), ' band, expected ', &
904           &  config%n_bands_sw
905        call radiation_abort()
906      end if
907
908      istartlev = lbound(aerosol%od_sw,2)
909      iendlev   = ubound(aerosol%od_sw,2)
910
911      ! Set variables to zero that may not have been previously
912      g_sw(:,:,istartcol:iendcol) = 0.0_jprb
913
914      ! Loop over position
915      do jcol = istartcol,iendcol
916! Added for DWD (2020)
917!NEC$ forced_collapse
918        do jlev = istartlev,iendlev
919          do jb = 1,config%n_bands_sw
920            od_sw_aerosol(jb,jlev) = aerosol%od_sw(jb,jlev,jcol)
921            scat_sw_aerosol(jb,jlev) = aerosol%ssa_sw(jb,jlev,jcol) * od_sw_aerosol(jb,jlev)
922            scat_g_sw_aerosol(jb,jlev) = aerosol%g_sw(jb,jlev,jcol) * scat_sw_aerosol(jb,jlev)
923
924            if (.not. config%do_sw_delta_scaling_with_gases) then
925              ! Delta-Eddington scaling on aerosol only.  Note that if
926              ! do_sw_delta_scaling_with_gases==.true. then the delta
927              ! scaling is done to the cloud-aerosol-gas mixture
928              ! inside the solver
929              call delta_eddington_extensive(od_sw_aerosol(jb,jlev), scat_sw_aerosol(jb,jlev), &
930                   &                         scat_g_sw_aerosol(jb,jlev))
931            end if
932          end do
933        end do
934        ! Combine aerosol shortwave scattering properties with gas
935        ! properties (noting that any gas scattering will have an
936        ! asymmetry factor of zero)
937        do jlev = istartlev,iendlev
938          if (od_sw_aerosol(1,jlev) > 0.0_jprb) then
939            do jg = 1,config%n_g_sw
940              iband = config%i_band_from_reordered_g_sw(jg)
941              local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband,jlev)
942              local_scat = ssa_sw(jg,jlev,jcol) * od_sw(jg,jlev,jcol) &
943                   &  + scat_sw_aerosol(iband,jlev)
944              ! Note that asymmetry_sw of gases is zero so the following
945              ! simply weights the aerosol asymmetry by the scattering
946              ! optical depth
947              g_sw(jg,jlev,jcol) = scat_g_sw_aerosol(iband,jlev) / local_scat
948              local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband,jlev)
949              ssa_sw(jg,jlev,jcol) = local_scat / local_od
950              od_sw (jg,jlev,jcol) = local_od
951            end do
952          end if
953        end do
954      end do
955
956    end if
957
958    if (config%do_lw) then
959
960      if (ubound(aerosol%od_lw,1) /= config%n_bands_lw) then
961        write(nulerr,'(a,i0,a,i0)') '*** Error: aerosol%od_lw contains ', &
962           &  ubound(aerosol%od_lw,1), ' band, expected ', &
963           &  config%n_bands_lw
964        call radiation_abort()
965      end if
966
967      istartlev = lbound(aerosol%od_lw,2)
968      iendlev   = ubound(aerosol%od_lw,2)
969
970      if (config%do_lw_aerosol_scattering) then
971        ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb
972        g_lw(:,:,istartcol:iendcol)   = 0.0_jprb
973
974        ! Loop over position
975        do jcol = istartcol,iendcol
976! Added for DWD (2020)
977!NEC$ forced_collapse
978          do jlev = istartlev,iendlev
979            do jb = 1,config%n_bands_lw
980              od_lw_aerosol(jb,jlev) = aerosol%od_lw(jb,jlev,jcol)
981              scat_lw_aerosol(jb,jlev) = aerosol%ssa_lw(jb,jlev,jcol) * od_lw_aerosol(jb,jlev)
982              scat_g_lw_aerosol(jb,jlev) = aerosol%g_lw(jb,jlev,jcol) * scat_lw_aerosol(jb,jlev)
983
984              call delta_eddington_extensive(od_lw_aerosol(jb,jlev), scat_lw_aerosol(jb,jlev), &
985                   &                         scat_g_lw_aerosol(jb,jlev))
986            end do
987          end do
988          do jlev = istartlev,iendlev
989            do jg = 1,config%n_g_lw
990              iband = config%i_band_from_reordered_g_lw(jg)
991              if (od_lw_aerosol(iband,jlev) > 0.0_jprb) then
992                ! All scattering is due to aerosols, therefore the
993                ! asymmetry factor is equal to the value for aerosols
994                if (scat_lw_aerosol(iband,jlev) > 0.0_jprb) then
995                  g_lw(jg,jlev,jcol) = scat_g_lw_aerosol(iband,jlev) &
996                       &  / scat_lw_aerosol(iband,jlev)
997                end if
998                local_od = od_lw(jg,jlev,jcol) + od_lw_aerosol(iband,jlev)
999                ssa_lw(jg,jlev,jcol) = scat_lw_aerosol(iband,jlev) / local_od
1000                od_lw (jg,jlev,jcol) = local_od
1001              end if
1002            end do
1003          end do
1004        end do
1005
1006      else ! No longwave scattering
1007
1008        ! Loop over position
1009        do jcol = istartcol,iendcol
1010! Added for DWD (2020)
1011!NEC$ forced_collapse
1012          do jlev = istartlev,iendlev
1013            ! If aerosol longwave scattering is not included then we
1014            ! weight the optical depth by the single scattering
1015            ! co-albedo
1016            do jb = 1, config%n_bands_lw
1017              od_lw_aerosol(jb,jlev) = aerosol%od_lw(jb,jlev,jcol) &
1018                 &  * (1.0_jprb - aerosol%ssa_lw(jb,jlev,jcol))
1019            end do
1020          end do
1021          do jlev = istartlev,iendlev
1022            do jg = 1,config%n_g_lw
1023              od_lw(jg,jlev,jcol) = od_lw(jg,jlev,jcol) &
1024                   &  + od_lw_aerosol(config%i_band_from_reordered_g_lw(jg),jlev)
1025            end do
1026          end do
1027        end do
1028
1029      end if
1030    end if
1031
1032
1033    if (lhook) call dr_hook('radiation_aerosol_optics:add_aerosol_optics_direct',1,hook_handle)
1034
1035  end subroutine add_aerosol_optics_direct
1036
1037
1038  !---------------------------------------------------------------------
1039  ! Sometimes it is useful to specify aerosol in terms of its optical
1040  ! depth at a particular wavelength.  This function returns the dry
1041  ! mass-extinction coefficient, i.e. the extinction cross section per
1042  ! unit mass, for aerosol of type "itype" at the specified wavelength
1043  ! (m). For hydrophilic types, the value at the first relative
1044  ! humidity bin is taken.
1045  function dry_aerosol_mass_extinction(config, itype, wavelength)
1046
1047    use parkind1,                      only : jprb
1048    use radiation_io,                  only : nulerr, radiation_abort
1049    use radiation_config,              only : config_type
1050    use radiation_aerosol_optics_data, only : aerosol_optics_type, &
1051         &  IAerosolClassUndefined,   IAerosolClassIgnored, &
1052         &  IAerosolClassHydrophobic, IAerosolClassHydrophilic
1053
1054    type(config_type), intent(in), target :: config
1055
1056    ! Aerosol type
1057    integer, intent(in) :: itype
1058
1059    ! Wavelength (m)
1060    real(jprb), intent(in) :: wavelength
1061
1062    real(jprb) :: dry_aerosol_mass_extinction
1063
1064    ! Index to the monochromatic wavelength requested
1065    integer :: imono
1066
1067    ! Pointer to the aerosol optics coefficients for brevity of access
1068    type(aerosol_optics_type), pointer :: ao
1069
1070    ao => config%aerosol_optics
1071
1072    imono = minloc(abs(wavelength - ao%wavelength_mono), 1)
1073
1074    if (abs(wavelength - ao%wavelength_mono(imono))/wavelength > 0.02_jprb) then
1075      write(nulerr,'(a,e11.4,a)') '*** Error: requested wavelength ', &
1076           &  wavelength, ' not within 2% of stored wavelengths'
1077      call radiation_abort()
1078     end if
1079
1080    if (ao%iclass(itype) == IAerosolClassHydrophobic) then
1081      dry_aerosol_mass_extinction = ao%mass_ext_mono_phobic(imono,ao%itype(itype))
1082    else if (ao%iclass(itype) == IAerosolClassHydrophilic) then
1083      ! Take the value at the first relative-humidity bin for the
1084      ! "dry" aerosol value
1085      dry_aerosol_mass_extinction = ao%mass_ext_mono_philic(imono,1,ao%itype(itype))
1086    else
1087      dry_aerosol_mass_extinction = 0.0_jprb
1088    end if
1089
1090  end function dry_aerosol_mass_extinction
1091
1092
1093  !---------------------------------------------------------------------
1094  ! Compute aerosol extinction coefficient at a particular wavelength
1095  ! and a single height - this is useful for visibility diagnostics
1096  subroutine aerosol_extinction(ncol,istartcol,iendcol, &
1097       &  config, wavelength, mixing_ratio, relative_humidity, extinction)
1098
1099    use parkind1,                      only : jprb
1100    use yomhook,                       only : lhook, dr_hook, jphook
1101    use radiation_io,                  only : nulerr, radiation_abort
1102    use radiation_config,              only : config_type
1103    use radiation_aerosol_optics_data, only : aerosol_optics_type, &
1104         &  IAerosolClassUndefined,   IAerosolClassIgnored, &
1105         &  IAerosolClassHydrophobic, IAerosolClassHydrophilic
1106
1107    integer, intent(in) :: ncol               ! number of columns
1108    integer, intent(in) :: istartcol, iendcol ! range of columns to process
1109    type(config_type), intent(in), target :: config
1110    real(jprb), intent(in)  :: wavelength ! Requested wavelength (m)
1111    real(jprb), intent(in)  :: mixing_ratio(ncol,config%n_aerosol_types)
1112    real(jprb), intent(in)  :: relative_humidity(ncol)
1113    real(jprb), intent(out) :: extinction(ncol)
1114
1115    ! Local aerosol extinction
1116    real(jprb) :: ext
1117
1118    ! Index to the monochromatic wavelength requested
1119    integer :: imono
1120
1121    ! Pointer to the aerosol optics coefficients for brevity of access
1122    type(aerosol_optics_type), pointer :: ao
1123
1124    ! Loop indices for column and aerosol type
1125    integer :: jcol, jtype
1126
1127    ! Relative humidity index
1128    integer :: irh
1129
1130    real(jphook) :: hook_handle
1131
1132    if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_extinction',0,hook_handle)
1133
1134    do jtype = 1,config%n_aerosol_types
1135      if (config%aerosol_optics%iclass(jtype) == IAerosolClassUndefined) then
1136        write(nulerr,'(a)') '*** Error: not all aerosol types are defined'
1137        call radiation_abort()
1138      end if
1139    end do
1140
1141    ao => config%aerosol_optics
1142
1143    imono = minloc(abs(wavelength - ao%wavelength_mono), 1)
1144
1145    if (abs(wavelength - ao%wavelength_mono(imono))/wavelength > 0.02_jprb) then
1146      write(nulerr,'(a,e11.4,a)') '*** Error: requested wavelength ', &
1147           &  wavelength, ' not within 2% of stored wavelengths'
1148      call radiation_abort()
1149     end if
1150
1151    ! Loop over position
1152    do jcol = istartcol,iendcol
1153      ext = 0.0_jprb
1154      ! Get relative-humidity index
1155      irh = ao%calc_rh_index(relative_humidity(jcol))
1156      ! Add extinction coefficients from each aerosol type
1157      do jtype = 1,config%n_aerosol_types
1158        if (ao%iclass(jtype) == IAerosolClassHydrophobic) then
1159          ext = ext + mixing_ratio(jcol,jtype) &
1160               &    * ao%mass_ext_mono_phobic(imono,ao%itype(jtype))
1161        else if (ao%iclass(jtype) == IAerosolClassHydrophilic) then
1162          ext = ext + mixing_ratio(jcol,jtype) &
1163               &    * ao%mass_ext_mono_philic(imono,irh,ao%itype(jtype))
1164        end if
1165      end do
1166
1167      extinction(jcol) = ext
1168    end do
1169
1170    if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_extinction',1,hook_handle)
1171
1172  end subroutine aerosol_extinction
1173
1174end module radiation_aerosol_optics
Note: See TracBrowser for help on using the repository browser.