[3880] | 1 | ! radiation_spartacus_sw.F90 - SPARTACUS shortwave solver |
---|
| 2 | ! |
---|
| 3 | ! (C) Copyright 2014- 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 | ! 2017-04-11 R. Hogan Receive albedos at g-points |
---|
| 17 | ! 2017-04-22 R. Hogan Store surface fluxes at all g-points |
---|
| 18 | ! 2017-06-30 R. Hogan Reformulate to use total_albedo_direct not total_source |
---|
| 19 | ! 2017-07-03 R. Hogan Explicit calculation of encroachment |
---|
| 20 | ! 2017-10-23 R. Hogan Renamed single-character variables |
---|
| 21 | ! 2018-02-20 R. Hogan Corrected "computed" encroachment |
---|
| 22 | ! 2018-03-09 R. Hogan Security on computed encroachment, transmittance and reflectance |
---|
| 23 | ! 2018-08-29 R. Hogan Reformulate horizontal migration distances in step_migrations |
---|
| 24 | ! 2018-09-02 R. Hogan Bug fix in x_direct in step_migrations |
---|
| 25 | ! 2018-09-03 R. Hogan Security via min_cloud_effective_size |
---|
| 26 | ! 2018-09-04 R. Hogan Use encroachment_scaling and read encroachment edge_length from upper layer |
---|
| 27 | ! 2018-09-13 R. Hogan Added "Fractal" encroachment option |
---|
| 28 | ! 2018-09-14 R. Hogan Added "Zero" encroachment option |
---|
| 29 | ! 2018-10-08 R. Hogan Call calc_region_properties |
---|
| 30 | ! 2018-10-15 R. Hogan Added call to fast_expm_exchange instead of expm |
---|
| 31 | ! 2019-01-12 R. Hogan Use inv_inhom_effective_size if allocated |
---|
| 32 | ! 2019-02-10 R. Hogan Renamed "encroachment" to "entrapment" |
---|
| 33 | |
---|
| 34 | module radiation_spartacus_sw |
---|
| 35 | |
---|
| 36 | public |
---|
| 37 | |
---|
| 38 | contains |
---|
| 39 | |
---|
| 40 | ! Small routine for scaling cloud optical depth in the cloudy |
---|
| 41 | ! regions |
---|
| 42 | #include "radiation_optical_depth_scaling.h" |
---|
| 43 | |
---|
| 44 | ! This module contains just one exported subroutine, the shortwave |
---|
| 45 | ! solver using the Speedy Algorithm for Radiative Transfer through |
---|
| 46 | ! Cloud Sides (SPARTACUS), which can represent 3D effects using a |
---|
| 47 | ! matrix form of the two-stream equations. |
---|
| 48 | ! |
---|
| 49 | ! Sections: |
---|
| 50 | ! 1: Prepare general variables and arrays |
---|
| 51 | ! 2: Prepare column-specific variables and arrays |
---|
| 52 | ! 3: First loop over layers |
---|
| 53 | ! 3.1: Layer-specific initialization |
---|
| 54 | ! 3.2: Compute gamma variables |
---|
| 55 | ! 3.2a: Clear-sky case |
---|
| 56 | ! 3.2b: Cloudy case |
---|
| 57 | ! 3.3: Compute reflection, transmission and sources |
---|
| 58 | ! 3.3a: g-points with 3D effects |
---|
| 59 | ! 3.3b: g-points without 3D effects |
---|
| 60 | ! 4: Compute total albedos |
---|
| 61 | ! 4.1: Adding method |
---|
| 62 | ! 4.2: Overlap and entrapment |
---|
| 63 | ! 5: Compute fluxes |
---|
| 64 | subroutine solver_spartacus_sw(nlev,istartcol,iendcol, & |
---|
| 65 | & config, single_level, thermodynamics, cloud, & |
---|
| 66 | & od, ssa, g, od_cloud, ssa_cloud, g_cloud, & |
---|
| 67 | & albedo_direct, albedo_diffuse, incoming_sw, & |
---|
| 68 | & flux) |
---|
| 69 | |
---|
| 70 | use parkind1, only : jprb |
---|
| 71 | use yomhook, only : lhook, dr_hook |
---|
| 72 | |
---|
| 73 | use radiation_io, only : nulout |
---|
| 74 | use radiation_config, only : config_type, IPdfShapeGamma, & |
---|
| 75 | & IEntrapmentZero, IEntrapmentEdgeOnly, IEntrapmentExplicit, & |
---|
| 76 | & IEntrapmentExplicitNonFractal, IEntrapmentMaximum |
---|
| 77 | use radiation_single_level, only : single_level_type |
---|
| 78 | use radiation_thermodynamics, only : thermodynamics_type |
---|
| 79 | use radiation_cloud, only : cloud_type |
---|
| 80 | use radiation_regions, only : calc_region_properties |
---|
| 81 | use radiation_overlap, only : calc_overlap_matrices |
---|
| 82 | use radiation_flux, only : flux_type, & |
---|
| 83 | & indexed_sum, add_indexed_sum |
---|
| 84 | use radiation_matrix |
---|
| 85 | use radiation_two_stream, only : calc_two_stream_gammas_sw, & |
---|
| 86 | & calc_reflectance_transmittance_sw, calc_frac_scattered_diffuse_sw, & |
---|
| 87 | & SwDiffusivity |
---|
| 88 | use radiation_constants, only : Pi, GasConstantDryAir, & |
---|
| 89 | & AccelDueToGravity |
---|
| 90 | |
---|
| 91 | implicit none |
---|
| 92 | |
---|
| 93 | ! Inputs |
---|
| 94 | integer, intent(in) :: nlev ! number of model levels |
---|
| 95 | integer, intent(in) :: istartcol, iendcol ! range of columns to process |
---|
| 96 | type(config_type), intent(in) :: config |
---|
| 97 | type(single_level_type), intent(in) :: single_level |
---|
| 98 | type(thermodynamics_type),intent(in) :: thermodynamics |
---|
| 99 | type(cloud_type), intent(in) :: cloud |
---|
| 100 | |
---|
| 101 | ! Gas and aerosol optical depth, single-scattering albedo and |
---|
| 102 | ! asymmetry factor at each shortwave g-point |
---|
| 103 | real(jprb), intent(in), dimension(config%n_g_sw,nlev,istartcol:iendcol) :: & |
---|
| 104 | & od, ssa, g |
---|
| 105 | |
---|
| 106 | ! Cloud and precipitation optical depth, single-scattering albedo and |
---|
| 107 | ! asymmetry factor in each shortwave band |
---|
| 108 | real(jprb), intent(in), dimension(config%n_bands_sw,nlev,istartcol:iendcol) :: & |
---|
| 109 | & od_cloud, ssa_cloud, g_cloud |
---|
| 110 | |
---|
| 111 | ! Direct and diffuse surface albedos, and the incoming shortwave |
---|
| 112 | ! flux into a plane perpendicular to the incoming radiation at |
---|
| 113 | ! top-of-atmosphere in each of the shortwave g points |
---|
| 114 | real(jprb), intent(in), dimension(config%n_g_sw,istartcol:iendcol) :: & |
---|
| 115 | & albedo_direct, albedo_diffuse, incoming_sw |
---|
| 116 | |
---|
| 117 | ! Output |
---|
| 118 | type(flux_type), intent(inout):: flux |
---|
| 119 | |
---|
| 120 | integer :: nreg, ng |
---|
| 121 | integer :: nregactive ! =1 in clear layer, =nreg in a cloudy layer |
---|
| 122 | integer :: jcol, jlev, jg, jreg, iband, jreg2,jreg3 |
---|
| 123 | #ifdef EXPLICIT_EDGE_ENTRAPMENT |
---|
| 124 | integer :: jreg4 |
---|
| 125 | #endif |
---|
| 126 | integer :: ng3D ! Number of g-points with small enough gas optical |
---|
| 127 | ! depth that 3D effects need to be represented |
---|
| 128 | |
---|
| 129 | ! Ratio of gas constant for dry air to acceleration due to gravity |
---|
| 130 | real(jprb), parameter :: R_over_g = GasConstantDryAir / AccelDueToGravity |
---|
| 131 | |
---|
| 132 | real(jprb) :: mu0, one_over_mu0, tan_sza, transfer_scaling |
---|
| 133 | |
---|
| 134 | ! The tangent of the effective zenith angle for diffuse radiation |
---|
| 135 | ! that is appropriate for 3D transport |
---|
| 136 | real(jprb), parameter :: tan_diffuse_angle_3d = Pi * 0.5_jprb |
---|
| 137 | |
---|
| 138 | ! The minimum cosine of solar zenith angle to consider for 3D |
---|
| 139 | ! effects, equivalent to one solar radius (0.2615 degrees) |
---|
| 140 | real(jprb), parameter :: min_mu0_3d = 0.004625_jprb |
---|
| 141 | |
---|
| 142 | ! Optical depth, single scattering albedo and asymmetry factor in |
---|
| 143 | ! each region and (except for asymmetry) at each g-point |
---|
| 144 | real(jprb), dimension(config%n_g_sw, config%nregions) & |
---|
| 145 | & :: od_region, ssa_region |
---|
| 146 | real(jprb), dimension(config%nregions) :: g_region |
---|
| 147 | |
---|
| 148 | ! Scattering optical depths of gases and clouds |
---|
| 149 | real(jprb) :: scat_od, scat_od_cloud |
---|
| 150 | |
---|
| 151 | ! The area fractions of each region |
---|
| 152 | real(jprb) :: region_fracs(1:config%nregions,nlev,istartcol:iendcol) |
---|
| 153 | |
---|
| 154 | ! The scaling used for the optical depth in the cloudy regions |
---|
| 155 | real(jprb) :: od_scaling(2:config%nregions,nlev,istartcol:iendcol) |
---|
| 156 | |
---|
| 157 | ! The length of the interface between regions jreg and jreg+1 per |
---|
| 158 | ! unit area of gridbox, equal to L_diff^ab in Hogan and Shonk |
---|
| 159 | ! (2013). When the first index is 3, this is the length of the |
---|
| 160 | ! interface between regions 3 and 1. This is actually the |
---|
| 161 | ! effective length oriented to a photon with random azimuth angle, |
---|
| 162 | ! so is the true edge length divided by pi. |
---|
| 163 | real(jprb) :: edge_length(3,nlev) |
---|
| 164 | |
---|
| 165 | ! Element i,j gives the rate of 3D transfer of diffuse/direct |
---|
| 166 | ! radiation from region i to region j, multiplied by the thickness |
---|
| 167 | ! of the layer in m |
---|
| 168 | real(jprb) :: transfer_rate_diffuse(config%nregions,config%nregions) |
---|
| 169 | real(jprb) :: transfer_rate_direct(config%nregions,config%nregions) |
---|
| 170 | |
---|
| 171 | ! Directional overlap matrices defined at all layer interfaces |
---|
| 172 | ! including top-of-atmosphere and the surface |
---|
| 173 | real(jprb), dimension(config%nregions,config%nregions,nlev+1, & |
---|
| 174 | & istartcol:iendcol) :: u_matrix, v_matrix |
---|
| 175 | |
---|
| 176 | ! Two-stream variables |
---|
| 177 | real(jprb), dimension(config%n_g_sw, config%nregions) & |
---|
| 178 | & :: gamma1, gamma2, gamma3 |
---|
| 179 | |
---|
| 180 | ! Matrix Gamma multiplied by the layer thickness z1, so units |
---|
| 181 | ! metres. After calling expm, this array contains the matrix |
---|
| 182 | ! exponential of the original. |
---|
| 183 | real(jprb) :: Gamma_z1(config%n_g_sw,3*config%nregions,3*config%nregions) |
---|
| 184 | |
---|
| 185 | ! Diffuse reflection and transmission matrices of each layer |
---|
| 186 | real(jprb), dimension(config%n_g_sw, config%nregions, & |
---|
| 187 | & config%nregions, nlev) :: reflectance, transmittance |
---|
| 188 | |
---|
| 189 | ! Clear-sky diffuse reflection and transmission matrices of each |
---|
| 190 | ! layer |
---|
| 191 | real(jprb), dimension(config%n_g_sw, nlev) :: ref_clear, trans_clear |
---|
| 192 | |
---|
| 193 | ! Matrices translating the direct flux entering the layer from |
---|
| 194 | ! above to the reflected radiation exiting upwards (ref_dir) and |
---|
| 195 | ! the scattered radiation exiting downwards (trans_dir_diff), |
---|
| 196 | ! along with the direct unscattered transmission matrix |
---|
| 197 | ! (trans_dir_dir). |
---|
| 198 | real(jprb), dimension(config%n_g_sw, config%nregions, config%nregions, nlev) & |
---|
| 199 | & :: ref_dir, trans_dir_diff, trans_dir_dir |
---|
| 200 | ! ...clear-sky equivalents |
---|
| 201 | real(jprb), dimension(config%n_g_sw, nlev) & |
---|
| 202 | & :: ref_dir_clear, trans_dir_diff_clear, trans_dir_dir_clear |
---|
| 203 | |
---|
| 204 | ! The fluxes downwelling from the bottom of the layer due to |
---|
| 205 | ! scattering by the direct beam within the layer |
---|
| 206 | real(jprb), dimension(config%n_g_sw, config%nregions) :: source_dn |
---|
| 207 | ! ...clear-sky equivalent |
---|
| 208 | real(jprb), dimension(config%n_g_sw) :: source_dn_clear |
---|
| 209 | |
---|
| 210 | ! The fluxes upwelling just above the base of a layer due to |
---|
| 211 | ! reflection of the direct downwelling beam; this is just used as |
---|
| 212 | ! a temporary variable |
---|
| 213 | real(jprb), dimension(config%n_g_sw, config%nregions) :: total_source |
---|
| 214 | |
---|
| 215 | ! Direct downwelling flux below and above an interface between |
---|
| 216 | ! layers into a plane perpendicular to the direction of the sun |
---|
| 217 | real(jprb), dimension(config%n_g_sw, config%nregions) & |
---|
| 218 | & :: direct_dn_below, direct_dn_above |
---|
| 219 | ! ...clear-sky equivalent (no distinction between "above/below") |
---|
| 220 | real(jprb), dimension(config%n_g_sw) :: direct_dn_clear |
---|
| 221 | |
---|
| 222 | ! Total albedo of the atmosphere/surface just above a layer |
---|
| 223 | ! interface with respect to downwelling diffuse and direct |
---|
| 224 | ! radiation at that interface, where level index = 1 corresponds |
---|
| 225 | ! to the top-of-atmosphere |
---|
| 226 | real(jprb), dimension(config%n_g_sw, config%nregions, & |
---|
| 227 | & config%nregions, nlev+1) :: total_albedo, total_albedo_direct |
---|
| 228 | ! ...clear-sky equivalent |
---|
| 229 | real(jprb), dimension(config%n_g_sw, nlev+1) & |
---|
| 230 | & :: total_albedo_clear, total_albedo_clear_direct |
---|
| 231 | |
---|
| 232 | ! As total_albedo, but just below a layer interface |
---|
| 233 | real(jprb), dimension(config%n_g_sw, config%nregions, config%nregions) & |
---|
| 234 | & :: total_albedo_below, total_albedo_below_direct |
---|
| 235 | |
---|
| 236 | ! Temporary array for applying adding method with entrapment to |
---|
| 237 | ! albedo matrices |
---|
| 238 | real(jprb), dimension(config%n_g_sw, config%nregions, config%nregions) & |
---|
| 239 | & :: albedo_part |
---|
| 240 | |
---|
| 241 | ! Horizontal migration distance (m) of reflected light |
---|
| 242 | real(jprb), dimension(config%n_g_sw, config%nregions) & |
---|
| 243 | & :: x_diffuse, x_direct |
---|
| 244 | ! Temporary variables when applying overlap rules |
---|
| 245 | real(jprb), dimension(config%n_g_sw, config%nregions) & |
---|
| 246 | & :: x_diffuse_above, x_direct_above |
---|
| 247 | |
---|
| 248 | real(jprb), dimension(config%n_g_sw, config%nregions, config%nregions) & |
---|
| 249 | & :: entrapment |
---|
| 250 | |
---|
| 251 | ! The following is used to store matrices of the form I-A*B that |
---|
| 252 | ! are used on the denominator of some expressions |
---|
| 253 | real(jprb) :: denominator(config%n_g_sw,config%nregions,config%nregions) |
---|
| 254 | |
---|
| 255 | ! Clear-sky equivalent, but actually its reciprocal to replace |
---|
| 256 | ! some divisions by multiplications |
---|
| 257 | real(jprb), dimension(config%n_g_sw) :: inv_denom_scalar |
---|
| 258 | |
---|
| 259 | ! Final step in working out how much transport between regions |
---|
| 260 | ! above occurs |
---|
| 261 | real(jprb), dimension(config%n_g_sw) :: fractal_factor |
---|
| 262 | |
---|
| 263 | ! Inverse of cloud effective size (m^-1) |
---|
| 264 | real(jprb) :: inv_effective_size |
---|
| 265 | |
---|
| 266 | ! Layer depth (m) |
---|
| 267 | real(jprb) :: dz, layer_depth(nlev) |
---|
| 268 | |
---|
| 269 | ! Upwelling and downwelling fluxes above/below layer interfaces |
---|
| 270 | real(jprb), dimension(config%n_g_sw, config%nregions) & |
---|
| 271 | & :: flux_up_above, flux_dn_above, flux_dn_below |
---|
| 272 | ! Clear-sky upwelling and downwelling fluxes (which don't |
---|
| 273 | ! distinguish between whether they are above/below a layer |
---|
| 274 | ! interface) |
---|
| 275 | real(jprb), dimension(config%n_g_sw) :: flux_up_clear, flux_dn_clear |
---|
| 276 | |
---|
| 277 | ! Index of top-most cloudy layer, or nlev+1 if no cloud |
---|
| 278 | integer :: i_cloud_top |
---|
| 279 | |
---|
| 280 | ! Keep a count of the number of calls to the two ways of computing |
---|
| 281 | ! reflectance/transmittance matrices |
---|
| 282 | integer :: n_calls_expm, n_calls_meador_weaver |
---|
| 283 | |
---|
| 284 | ! Identify clear-sky layers, with pseudo layers for outer space |
---|
| 285 | ! and below the ground, both treated as single-region clear skies |
---|
| 286 | logical :: is_clear_sky_layer(0:nlev+1) |
---|
| 287 | |
---|
| 288 | ! Used in computing rates of lateral radiation transfer |
---|
| 289 | real(jprb), parameter :: four_over_pi = 4.0_jprb / Pi |
---|
| 290 | |
---|
| 291 | ! Maximum entrapment coefficient |
---|
| 292 | real(jprb) :: max_entr |
---|
| 293 | |
---|
| 294 | real(jprb) :: hook_handle |
---|
| 295 | |
---|
| 296 | if (lhook) call dr_hook('radiation_spartacus_sw:solver_spartacus_sw',0,hook_handle) |
---|
| 297 | |
---|
| 298 | ! -------------------------------------------------------- |
---|
| 299 | ! Section 1: Prepare general variables and arrays |
---|
| 300 | ! -------------------------------------------------------- |
---|
| 301 | |
---|
| 302 | ! Copy array dimensions to local variables for convenience |
---|
| 303 | nreg = config%nregions |
---|
| 304 | ng = config%n_g_sw |
---|
| 305 | |
---|
| 306 | ! Reset count of number of calls to the two ways to compute |
---|
| 307 | ! reflectance/transmission matrices |
---|
| 308 | n_calls_expm = 0 |
---|
| 309 | n_calls_meador_weaver = 0 |
---|
| 310 | |
---|
| 311 | ! Compute the wavelength-independent region fractions and |
---|
| 312 | ! optical-depth scalings |
---|
| 313 | call calc_region_properties(nlev,nreg,istartcol,iendcol, & |
---|
| 314 | & config%i_cloud_pdf_shape == IPdfShapeGamma, & |
---|
| 315 | & cloud%fraction, cloud%fractional_std, region_fracs, & |
---|
| 316 | & od_scaling, config%cloud_fraction_threshold) |
---|
| 317 | |
---|
| 318 | ! Compute wavelength-independent overlap matrices u_matrix and v_matrix |
---|
| 319 | call calc_overlap_matrices(nlev,nreg,istartcol,iendcol, & |
---|
| 320 | & region_fracs, cloud%overlap_param, & |
---|
| 321 | & u_matrix, v_matrix, decorrelation_scaling=config%cloud_inhom_decorr_scaling, & |
---|
| 322 | & cloud_fraction_threshold=config%cloud_fraction_threshold, & |
---|
| 323 | & use_beta_overlap=config%use_beta_overlap, & |
---|
| 324 | & cloud_cover=flux%cloud_cover_sw) |
---|
| 325 | |
---|
| 326 | if (config%iverbose >= 3) then |
---|
| 327 | write(nulout,'(a)',advance='no') ' Processing columns' |
---|
| 328 | end if |
---|
| 329 | |
---|
| 330 | ! Main loop over columns |
---|
| 331 | do jcol = istartcol, iendcol |
---|
| 332 | ! -------------------------------------------------------- |
---|
| 333 | ! Section 2: Prepare column-specific variables and arrays |
---|
| 334 | ! -------------------------------------------------------- |
---|
| 335 | |
---|
| 336 | if (config%iverbose >= 3) then |
---|
| 337 | write(nulout,'(a)',advance='no') '.' |
---|
| 338 | end if |
---|
| 339 | |
---|
| 340 | ! Copy local cosine of the solar zenith angle |
---|
| 341 | mu0 = single_level%cos_sza(jcol) |
---|
| 342 | |
---|
| 343 | ! Skip profile if sun is too low in the sky |
---|
| 344 | if (mu0 < 1.0e-10_jprb) then |
---|
| 345 | flux%sw_dn(jcol,:) = 0.0_jprb |
---|
| 346 | flux%sw_up(jcol,:) = 0.0_jprb |
---|
| 347 | if (allocated(flux%sw_dn_direct)) then |
---|
| 348 | flux%sw_dn_direct(jcol,:) = 0.0_jprb |
---|
| 349 | end if |
---|
| 350 | if (config%do_clear) then |
---|
| 351 | flux%sw_dn_clear(jcol,:) = 0.0_jprb |
---|
| 352 | flux%sw_up_clear(jcol,:) = 0.0_jprb |
---|
| 353 | if (allocated(flux%sw_dn_direct_clear)) then |
---|
| 354 | flux%sw_dn_direct_clear(jcol,:) = 0.0_jprb |
---|
| 355 | end if |
---|
| 356 | end if |
---|
| 357 | |
---|
| 358 | if (config%do_save_spectral_flux) then |
---|
| 359 | flux%sw_dn_band(:,jcol,:) = 0.0_jprb |
---|
| 360 | flux%sw_up_band(:,jcol,:) = 0.0_jprb |
---|
| 361 | if (allocated(flux%sw_dn_direct_band)) then |
---|
| 362 | flux%sw_dn_direct_band(:,jcol,:) = 0.0_jprb |
---|
| 363 | end if |
---|
| 364 | if (config%do_clear) then |
---|
| 365 | flux%sw_dn_clear_band(:,jcol,:) = 0.0_jprb |
---|
| 366 | flux%sw_up_clear_band(:,jcol,:) = 0.0_jprb |
---|
| 367 | if (allocated(flux%sw_dn_direct_clear_band)) then |
---|
| 368 | flux%sw_dn_direct_clear_band(:,jcol,:) = 0.0_jprb |
---|
| 369 | end if |
---|
| 370 | end if |
---|
| 371 | end if |
---|
| 372 | |
---|
| 373 | flux%sw_dn_diffuse_surf_g(:,jcol) = 0.0_jprb |
---|
| 374 | flux%sw_dn_direct_surf_g(:,jcol) = 0.0_jprb |
---|
| 375 | if (config%do_clear) then |
---|
| 376 | flux%sw_dn_diffuse_surf_clear_g(:,jcol) = 0.0_jprb |
---|
| 377 | flux%sw_dn_direct_surf_clear_g(:,jcol) = 0.0_jprb |
---|
| 378 | end if |
---|
| 379 | |
---|
| 380 | cycle |
---|
| 381 | end if ! sun is below the horizon |
---|
| 382 | |
---|
| 383 | ! At this point mu0 >= 1.0e-10 |
---|
| 384 | |
---|
| 385 | ! Used to compute rate of attenuation of direct solar beam |
---|
| 386 | ! through the atmosphere |
---|
| 387 | one_over_mu0 = 1.0_jprb / mu0 |
---|
| 388 | |
---|
| 389 | ! The rate at which direct radiation enters cloud sides is |
---|
| 390 | ! proportional to the tangent of the solar zenith angle, but |
---|
| 391 | ! this gets very large when the sun is low in the sky, in which |
---|
| 392 | ! case we limit it to one solar radius above the horizon |
---|
| 393 | if (mu0 < min_mu0_3d) then |
---|
| 394 | tan_sza = sqrt(1.0_jprb/(min_mu0_3d*min_mu0_3d) - 1.0_jprb) |
---|
| 395 | else if (one_over_mu0 > 1.0_jprb) then |
---|
| 396 | tan_sza = sqrt(one_over_mu0*one_over_mu0 - 1.0_jprb & |
---|
| 397 | & + config%overhead_sun_factor) |
---|
| 398 | else |
---|
| 399 | ! Just in case we get mu0 > 1... |
---|
| 400 | tan_sza = sqrt(config%overhead_sun_factor) |
---|
| 401 | end if |
---|
| 402 | |
---|
| 403 | ! Define which layers contain cloud; assume that |
---|
| 404 | ! cloud%crop_cloud_fraction has already been called |
---|
| 405 | is_clear_sky_layer = .true. |
---|
| 406 | i_cloud_top = nlev+1 |
---|
| 407 | do jlev = nlev,1,-1 |
---|
| 408 | if (cloud%fraction(jcol,jlev) > 0.0_jprb) then |
---|
| 409 | is_clear_sky_layer(jlev) = .false. |
---|
| 410 | i_cloud_top = jlev |
---|
| 411 | end if |
---|
| 412 | end do |
---|
| 413 | |
---|
| 414 | ! -------------------------------------------------------- |
---|
| 415 | ! Section 3: First loop over layers |
---|
| 416 | ! -------------------------------------------------------- |
---|
| 417 | ! In this section the reflectance, transmittance and sources |
---|
| 418 | ! are computed for each layer |
---|
| 419 | do jlev = 1,nlev ! Start at top-of-atmosphere |
---|
| 420 | ! -------------------------------------------------------- |
---|
| 421 | ! Section 3.1: Layer-specific initialization |
---|
| 422 | ! -------------------------------------------------------- |
---|
| 423 | |
---|
| 424 | ! Array-wise assignments |
---|
| 425 | gamma1 = 0.0_jprb |
---|
| 426 | gamma2 = 0.0_jprb |
---|
| 427 | gamma3 = 0.0_jprb |
---|
| 428 | Gamma_z1= 0.0_jprb |
---|
| 429 | transfer_rate_direct(:,:) = 0.0_jprb |
---|
| 430 | transfer_rate_diffuse(:,:) = 0.0_jprb |
---|
| 431 | edge_length(:,jlev) = 0.0_jprb |
---|
| 432 | |
---|
| 433 | ! The following is from the hydrostatic equation |
---|
| 434 | ! and ideal gas law: dz = dp * R * T / (p * g) |
---|
| 435 | layer_depth(jlev) = R_over_g & |
---|
| 436 | & * (thermodynamics%pressure_hl(jcol,jlev+1) & |
---|
| 437 | & - thermodynamics%pressure_hl(jcol,jlev)) & |
---|
| 438 | & * (thermodynamics%temperature_hl(jcol,jlev) & |
---|
| 439 | & + thermodynamics%temperature_hl(jcol,jlev+1)) & |
---|
| 440 | & / (thermodynamics%pressure_hl(jcol,jlev) & |
---|
| 441 | & + thermodynamics%pressure_hl(jcol,jlev+1)) |
---|
| 442 | |
---|
| 443 | ! -------------------------------------------------------- |
---|
| 444 | ! Section 3.2: Compute gamma variables |
---|
| 445 | ! -------------------------------------------------------- |
---|
| 446 | if (is_clear_sky_layer(jlev)) then |
---|
| 447 | ! --- Section 3.2a: Clear-sky case -------------------- |
---|
| 448 | |
---|
| 449 | nregactive = 1 ! Only region 1 (clear-sky) is active |
---|
| 450 | |
---|
| 451 | ! Copy optical depth and single-scattering albedo of |
---|
| 452 | ! clear-sky region |
---|
| 453 | od_region(1:ng,1) = od(1:ng,jlev,jcol) |
---|
| 454 | ssa_region(1:ng,1) = ssa(1:ng,jlev,jcol) |
---|
| 455 | |
---|
| 456 | ! Compute two-stream variables gamma1-gamma3 (gamma4=1-gamma3) |
---|
| 457 | call calc_two_stream_gammas_sw(ng, & |
---|
| 458 | & mu0, ssa(1:ng,jlev,jcol), g(1:ng,jlev,jcol), & |
---|
| 459 | & gamma1(1:ng,1), gamma2(1:ng,1), gamma3(1:ng,1)) |
---|
| 460 | |
---|
| 461 | if (config%use_expm_everywhere) then |
---|
| 462 | ! Treat cloud-free layer as 3D: the matrix exponential |
---|
| 463 | ! "expm" is used as much as possible (provided the |
---|
| 464 | ! optical depth is not too high). ng3D is initially |
---|
| 465 | ! set to the total number of g-points, then the |
---|
| 466 | ! clear-sky optical depths are searched until a value |
---|
| 467 | ! exceeds the threshold for treating 3D effects, and |
---|
| 468 | ! if found it is reset to that. Note that we are |
---|
| 469 | ! assuming that the g-points have been reordered in |
---|
| 470 | ! approximate order of gas optical depth. |
---|
| 471 | ng3D = ng |
---|
| 472 | do jg = 1, ng |
---|
| 473 | if (od_region(jg,1) > config%max_gas_od_3D) then |
---|
| 474 | ng3D = jg-1 |
---|
| 475 | exit |
---|
| 476 | end if |
---|
| 477 | end do |
---|
| 478 | else |
---|
| 479 | ! Otherwise treat cloud-free layer using the classical |
---|
| 480 | ! Meador & Weaver formulae for all g-points |
---|
| 481 | ng3D = 0 |
---|
| 482 | end if |
---|
| 483 | |
---|
| 484 | |
---|
| 485 | else |
---|
| 486 | ! --- Section 3.2b: Cloudy case ----------------------- |
---|
| 487 | |
---|
| 488 | ! Default number of g-points to treat with |
---|
| 489 | ! matrix-exponential scheme |
---|
| 490 | if (config%use_expm_everywhere) then |
---|
| 491 | ng3D = ng ! All g-points |
---|
| 492 | else |
---|
| 493 | ng3D = 0 ! No g-points |
---|
| 494 | end if |
---|
| 495 | |
---|
| 496 | if (config%do_3d_effects .and. & |
---|
| 497 | & allocated(cloud%inv_cloud_effective_size) .and. & |
---|
| 498 | & .not. (nreg == 2 .and. cloud%fraction(jcol,jlev) & |
---|
| 499 | & > 1.0-config%cloud_fraction_threshold)) then |
---|
| 500 | if (cloud%inv_cloud_effective_size(jcol,jlev) > 0.0_jprb) then |
---|
| 501 | ! 3D effects are only simulated if |
---|
| 502 | ! inv_cloud_effective_size is defined and greater |
---|
| 503 | ! than zero |
---|
| 504 | ng3D = ng |
---|
| 505 | |
---|
| 506 | ! Depth of current layer |
---|
| 507 | dz = layer_depth(jlev) |
---|
| 508 | |
---|
| 509 | ! Compute cloud edge length per unit area of gridbox |
---|
| 510 | ! from rearranging Hogan & Shonk (2013) Eq. 45, but |
---|
| 511 | ! adding a factor of (1-frac) so that a region that |
---|
| 512 | ! fully occupies the gridbox (frac=1) has an edge of |
---|
| 513 | ! zero. We can therefore use the fraction of clear sky, |
---|
| 514 | ! region_fracs(1,jlev,jcol) for convenience instead. The |
---|
| 515 | ! pi on the denominator means that this is actually edge |
---|
| 516 | ! length with respect to a light ray with a random |
---|
| 517 | ! azimuthal direction. |
---|
| 518 | edge_length(1,jlev) = four_over_pi & |
---|
| 519 | & * region_fracs(1,jlev,jcol)*(1.0_jprb-region_fracs(1,jlev,jcol)) & |
---|
| 520 | & * min(cloud%inv_cloud_effective_size(jcol,jlev), & |
---|
| 521 | & 1.0_jprb / config%min_cloud_effective_size) |
---|
| 522 | if (nreg > 2) then |
---|
| 523 | ! The corresponding edge length between the two cloudy |
---|
| 524 | ! regions is computed in the same way but treating the |
---|
| 525 | ! optically denser of the two regions (region 3) as |
---|
| 526 | ! the cloud; note that the fraction of this region may |
---|
| 527 | ! be less than that of the optically less dense of the |
---|
| 528 | ! two regions (region 2). For increased flexibility, |
---|
| 529 | ! the user may specify the effective size of |
---|
| 530 | ! inhomogeneities separately from the cloud effective |
---|
| 531 | ! size. |
---|
| 532 | if (allocated(cloud%inv_inhom_effective_size)) then |
---|
| 533 | edge_length(2,jlev) = four_over_pi & |
---|
| 534 | & * region_fracs(3,jlev,jcol)*(1.0_jprb-region_fracs(3,jlev,jcol)) & |
---|
| 535 | & * min(cloud%inv_inhom_effective_size(jcol,jlev), & |
---|
| 536 | & 1.0_jprb / config%min_cloud_effective_size) |
---|
| 537 | else |
---|
| 538 | edge_length(2,jlev) = four_over_pi & |
---|
| 539 | & * region_fracs(3,jlev,jcol)*(1.0_jprb-region_fracs(3,jlev,jcol)) & |
---|
| 540 | & * min(cloud%inv_cloud_effective_size(jcol,jlev), & |
---|
| 541 | & 1.0_jprb / config%min_cloud_effective_size) |
---|
| 542 | end if |
---|
| 543 | |
---|
| 544 | ! In the case of three regions, some of the cloud |
---|
| 545 | ! boundary may go directly to the "thick" region |
---|
| 546 | if (config%clear_to_thick_fraction > 0.0_jprb) then |
---|
| 547 | edge_length(3,jlev) = config%clear_to_thick_fraction & |
---|
| 548 | & * min(edge_length(1,jlev), edge_length(2,jlev)) |
---|
| 549 | edge_length(1,jlev) = edge_length(1,jlev) - edge_length(3,jlev) |
---|
| 550 | edge_length(2,jlev) = edge_length(2,jlev) - edge_length(3,jlev) |
---|
| 551 | else |
---|
| 552 | edge_length(3,jlev) = 0.0_jprb |
---|
| 553 | end if |
---|
| 554 | end if |
---|
| 555 | |
---|
| 556 | do jreg = 1, nreg-1 |
---|
| 557 | ! Compute lateral transfer rates from region jreg to |
---|
| 558 | ! jreg+1 following Hogan & Shonk (2013) Eq. 47, but |
---|
| 559 | ! multiplied by dz because the transfer rate is |
---|
| 560 | ! vertically integrated across the depth of the layer |
---|
| 561 | if (region_fracs(jreg,jlev,jcol) > epsilon(1.0_jprb)) then |
---|
| 562 | transfer_rate_direct(jreg,jreg+1) = dz & |
---|
| 563 | & * edge_length(jreg,jlev) * tan_sza / region_fracs(jreg,jlev,jcol) |
---|
| 564 | transfer_rate_diffuse(jreg,jreg+1) = dz & |
---|
| 565 | & * edge_length(jreg,jlev) & |
---|
| 566 | & * tan_diffuse_angle_3d / region_fracs(jreg,jlev,jcol) |
---|
| 567 | end if |
---|
| 568 | ! Compute transfer rates from region jreg+1 to |
---|
| 569 | ! jreg |
---|
| 570 | if (region_fracs(jreg+1,jlev,jcol) > epsilon(1.0_jprb)) then |
---|
| 571 | transfer_rate_direct(jreg+1,jreg) = dz & |
---|
| 572 | & * edge_length(jreg,jlev) & |
---|
| 573 | & * tan_sza / region_fracs(jreg+1,jlev,jcol) |
---|
| 574 | transfer_rate_diffuse(jreg+1,jreg) = dz & |
---|
| 575 | & * edge_length(jreg,jlev) & |
---|
| 576 | & * tan_diffuse_angle_3d / region_fracs(jreg+1,jlev,jcol) |
---|
| 577 | end if |
---|
| 578 | end do |
---|
| 579 | |
---|
| 580 | ! Compute transfer rates directly between regions 1 and |
---|
| 581 | ! 3 |
---|
| 582 | if (edge_length(3,jlev) > 0.0_jprb) then |
---|
| 583 | if (region_fracs(1,jlev,jcol) > epsilon(1.0_jprb)) then |
---|
| 584 | transfer_rate_direct(1,3) = dz & |
---|
| 585 | & * edge_length(3,jlev) * tan_sza / region_fracs(1,jlev,jcol) |
---|
| 586 | transfer_rate_diffuse(1,3) = dz & |
---|
| 587 | & * edge_length(3,jlev) & |
---|
| 588 | & * tan_diffuse_angle_3d / region_fracs(1,jlev,jcol) |
---|
| 589 | end if |
---|
| 590 | if (region_fracs(3,jlev,jcol) > epsilon(1.0_jprb)) then |
---|
| 591 | transfer_rate_direct(3,1) = dz & |
---|
| 592 | & * edge_length(3,jlev) * tan_sza / region_fracs(3,jlev,jcol) |
---|
| 593 | transfer_rate_diffuse(3,1) = dz & |
---|
| 594 | & * edge_length(3,jlev) & |
---|
| 595 | & * tan_diffuse_angle_3d / region_fracs(3,jlev,jcol) |
---|
| 596 | end if |
---|
| 597 | end if |
---|
| 598 | |
---|
| 599 | ! Don't allow the transfer rate out of a region to be |
---|
| 600 | ! equivalent to a loss of exp(-10) through the layer |
---|
| 601 | where (transfer_rate_direct > config%max_3d_transfer_rate) |
---|
| 602 | transfer_rate_direct = config%max_3d_transfer_rate |
---|
| 603 | end where |
---|
| 604 | where (transfer_rate_diffuse > config%max_3d_transfer_rate) |
---|
| 605 | transfer_rate_diffuse = config%max_3d_transfer_rate |
---|
| 606 | end where |
---|
| 607 | |
---|
| 608 | end if ! Cloud has edge length required for 3D effects |
---|
| 609 | end if ! Include 3D effects |
---|
| 610 | |
---|
| 611 | ! In a cloudy layer the number of active regions equals |
---|
| 612 | ! the number of regions |
---|
| 613 | nregactive = nreg |
---|
| 614 | |
---|
| 615 | ! Compute scattering properties of the regions at each |
---|
| 616 | ! g-point, mapping from the cloud properties |
---|
| 617 | ! defined in each band. |
---|
| 618 | do jg = 1,ng |
---|
| 619 | ! Mapping from g-point to band |
---|
| 620 | iband = config%i_band_from_reordered_g_sw(jg) |
---|
| 621 | |
---|
| 622 | ! Scattering optical depth of clear-sky region |
---|
| 623 | scat_od = od(jg,jlev,jcol)*ssa(jg,jlev,jcol) |
---|
| 624 | |
---|
| 625 | ! Scattering properties of clear-sky regions copied |
---|
| 626 | ! over |
---|
| 627 | od_region(jg,1) = od(jg, jlev, jcol) |
---|
| 628 | ssa_region(jg,1) = ssa(jg, jlev, jcol) |
---|
| 629 | g_region(1) = g(jg, jlev, jcol) |
---|
| 630 | |
---|
| 631 | ! Loop over cloudy regions |
---|
| 632 | do jreg = 2,nreg |
---|
| 633 | scat_od_cloud = od_cloud(iband,jlev,jcol) & |
---|
| 634 | & * ssa_cloud(iband,jlev,jcol)*od_scaling(jreg,jlev,jcol) |
---|
| 635 | ! Add scaled cloud optical depth to clear-sky value |
---|
| 636 | od_region(jg,jreg) = od(jg,jlev,jcol) & |
---|
| 637 | & + od_cloud(iband,jlev,jcol)*od_scaling(jreg,jlev,jcol) |
---|
| 638 | ! Compute single-scattering albedo and asymmetry |
---|
| 639 | ! factor of gas-cloud combination |
---|
| 640 | ssa_region(jg,jreg) = (scat_od+scat_od_cloud) & |
---|
| 641 | & / od_region(jg,jreg) |
---|
| 642 | g_region(jreg) = (scat_od*g(jg,jlev,jcol) & |
---|
| 643 | & + scat_od_cloud * g_cloud(iband,jlev,jcol)) & |
---|
| 644 | & / (scat_od + scat_od_cloud) |
---|
| 645 | |
---|
| 646 | ! Apply maximum cloud optical depth for stability in the |
---|
| 647 | ! 3D case |
---|
| 648 | if (od_region(jg,jreg) > config%max_cloud_od) then |
---|
| 649 | od_region(jg,jreg) = config%max_cloud_od |
---|
| 650 | end if |
---|
| 651 | |
---|
| 652 | end do |
---|
| 653 | |
---|
| 654 | ! Calculate two-stream variables gamma1-gamma3 of all |
---|
| 655 | ! regions at once |
---|
| 656 | call calc_two_stream_gammas_sw(nreg, & |
---|
| 657 | & mu0, ssa_region(jg,:), g_region, & |
---|
| 658 | & gamma1(jg,:), gamma2(jg,:), gamma3(jg,:)) |
---|
| 659 | |
---|
| 660 | ! Loop is in order of g-points with typically |
---|
| 661 | ! increasing optical depth: if optical depth of |
---|
| 662 | ! clear-sky region exceeds a threshold then turn off |
---|
| 663 | ! 3D effects for any further g-points |
---|
| 664 | if (ng3D == ng & |
---|
| 665 | & .and. od_region(jg,1) > config%max_gas_od_3D) then |
---|
| 666 | ng3D = jg-1 |
---|
| 667 | end if |
---|
| 668 | end do ! Loop over g points |
---|
| 669 | end if ! Cloudy level |
---|
| 670 | |
---|
| 671 | ! -------------------------------------------------------- |
---|
| 672 | ! Section 3.3: Compute reflection, transmission and emission |
---|
| 673 | ! -------------------------------------------------------- |
---|
| 674 | if (ng3D > 0) then |
---|
| 675 | ! --- Section 3.3a: g-points with 3D effects ---------- |
---|
| 676 | |
---|
| 677 | ! 3D effects need to be represented in "ng3D" of the g |
---|
| 678 | ! points. This is done by creating ng3D square matrices |
---|
| 679 | ! each of dimension 3*nreg by 3*nreg, computing the matrix |
---|
| 680 | ! exponential, then computing the various |
---|
| 681 | ! transmission/reflectance matrices from that. |
---|
| 682 | do jreg = 1,nregactive |
---|
| 683 | ! Write the diagonal elements of -Gamma1*z1 |
---|
| 684 | Gamma_z1(1:ng3D,jreg,jreg) & |
---|
| 685 | & = od_region(1:ng3D,jreg)*gamma1(1:ng3D,jreg) |
---|
| 686 | ! Write the diagonal elements of +Gamma2*z1 |
---|
| 687 | Gamma_z1(1:ng3D,jreg+nreg,jreg) & |
---|
| 688 | & = od_region(1:ng3D,jreg)*gamma2(1:ng3D,jreg) |
---|
| 689 | ! Write the diagonal elements of -Gamma3*z1 |
---|
| 690 | Gamma_z1(1:ng3D,jreg,jreg+2*nreg) & |
---|
| 691 | & = -od_region(1:ng3D,jreg)*ssa_region(1:ng3D,jreg) & |
---|
| 692 | & * gamma3(1:ng3D,jreg) |
---|
| 693 | |
---|
| 694 | ! Write the diagonal elements of +Gamma4*z1 |
---|
| 695 | Gamma_z1(1:ng3D,jreg+nreg,jreg+2*nreg) & |
---|
| 696 | & = od_region(1:ng3D,jreg)*ssa_region(1:ng3D,jreg) & |
---|
| 697 | & * (1.0_jprb - gamma3(1:ng3D,jreg)) |
---|
| 698 | |
---|
| 699 | ! Write the diagonal elements of +Gamma0*z1 |
---|
| 700 | Gamma_z1(1:ng3D,jreg+2*nreg,jreg+2*nreg) & |
---|
| 701 | & = -od_region(1:ng3D,jreg)*one_over_mu0 |
---|
| 702 | end do |
---|
| 703 | |
---|
| 704 | do jreg = 1,nregactive-1 |
---|
| 705 | ! Write the elements of -Gamma1*z1 concerned with 3D |
---|
| 706 | ! transport |
---|
| 707 | Gamma_z1(1:ng3D,jreg,jreg) = Gamma_z1(1:ng3D,jreg,jreg) & |
---|
| 708 | & + transfer_rate_diffuse(jreg,jreg+1) |
---|
| 709 | Gamma_z1(1:ng3D,jreg+1,jreg+1) = Gamma_z1(1:ng3D,jreg+1,jreg+1) & |
---|
| 710 | & + transfer_rate_diffuse(jreg+1,jreg) |
---|
| 711 | Gamma_z1(1:ng3D,jreg+1,jreg) = -transfer_rate_diffuse(jreg,jreg+1) |
---|
| 712 | Gamma_z1(1:ng3D,jreg,jreg+1) = -transfer_rate_diffuse(jreg+1,jreg) |
---|
| 713 | ! Write the elements of +Gamma0*z1 concerned with 3D |
---|
| 714 | ! transport |
---|
| 715 | Gamma_z1(1:ng3D,jreg+2*nreg,jreg+2*nreg) & |
---|
| 716 | & = Gamma_z1(1:ng3D,jreg+2*nreg,jreg+2*nreg) & |
---|
| 717 | & - transfer_rate_direct(jreg,jreg+1) |
---|
| 718 | Gamma_z1(1:ng3D,jreg+2*nreg+1,jreg+2*nreg+1) & |
---|
| 719 | & = Gamma_z1(1:ng3D,jreg+2*nreg+1,jreg+2*nreg+1) & |
---|
| 720 | & - transfer_rate_direct(jreg+1,jreg) |
---|
| 721 | Gamma_z1(1:ng3D,jreg+2*nreg+1,jreg+2*nreg) & |
---|
| 722 | & = transfer_rate_direct(jreg,jreg+1) |
---|
| 723 | Gamma_z1(1:ng3D,jreg+2*nreg,jreg+2*nreg+1) & |
---|
| 724 | & = transfer_rate_direct(jreg+1,jreg) |
---|
| 725 | end do |
---|
| 726 | |
---|
| 727 | ! Possible flow between regions a and c |
---|
| 728 | if (edge_length(3,jlev) > 0.0_jprb) then |
---|
| 729 | ! Diffuse transport |
---|
| 730 | Gamma_z1(1:ng3D,1,1) = Gamma_z1(1:ng3D,1,1) & |
---|
| 731 | & + transfer_rate_diffuse(1,3) |
---|
| 732 | Gamma_z1(1:ng3D,3,3) = Gamma_z1(1:ng3D,3,3) & |
---|
| 733 | & + transfer_rate_diffuse(3,1) |
---|
| 734 | Gamma_z1(1:ng3D,3,1) = -transfer_rate_diffuse(1,3) |
---|
| 735 | Gamma_z1(1:ng3D,1,3) = -transfer_rate_diffuse(3,1) |
---|
| 736 | ! Direct transport |
---|
| 737 | Gamma_z1(1:ng3D,1+2*nreg,1+2*nreg) = Gamma_z1(1:ng3D,1+2*nreg,1+2*nreg) & |
---|
| 738 | & - transfer_rate_direct(1,3) |
---|
| 739 | Gamma_z1(1:ng3D,3+2*nreg,3+2*nreg) = Gamma_z1(1:ng3D,3+2*nreg,3+2*nreg) & |
---|
| 740 | & - transfer_rate_direct(3,1) |
---|
| 741 | Gamma_z1(1:ng3D,3+2*nreg,1+2*nreg) = transfer_rate_direct(1,3) |
---|
| 742 | Gamma_z1(1:ng3D,1+2*nreg,3+2*nreg) = transfer_rate_direct(3,1) |
---|
| 743 | end if |
---|
| 744 | |
---|
| 745 | ! Copy Gamma1*z1 |
---|
| 746 | Gamma_z1(1:ng3D,nreg+1:nreg+nregactive,nreg+1:nreg+nregactive) & |
---|
| 747 | & = -Gamma_z1(1:ng3D,1:nregactive,1:nregactive) |
---|
| 748 | ! Copy Gamma2*z1 |
---|
| 749 | Gamma_z1(1:ng3D,1:nregactive,nreg+1:nreg+nregactive) & |
---|
| 750 | & = -Gamma_z1(1:ng3D,nreg+1:nreg+nregactive,1:nregactive) |
---|
| 751 | |
---|
| 752 | ! Compute the matrix exponential of Gamma_z1, returning the |
---|
| 753 | ! result in-place |
---|
| 754 | call expm(ng, ng3D, 3*nreg, Gamma_z1, IMatrixPatternShortwave) |
---|
| 755 | |
---|
| 756 | ! Update count of expm calls |
---|
| 757 | n_calls_expm = n_calls_expm + ng3D |
---|
| 758 | |
---|
| 759 | ! Direct transmission matrix |
---|
| 760 | trans_dir_dir(1:ng3D,:,:,jlev) = min(1.0_jprb,max(0.0_jprb, & |
---|
| 761 | & Gamma_z1(1:ng3D,2*nreg+1:3*nreg, 2*nreg+1:3*nreg))) |
---|
| 762 | ! Diffuse reflectance matrix; security on negative values |
---|
| 763 | ! necessary occasionally for very low cloud fraction and very high |
---|
| 764 | ! in-cloud optical depth |
---|
| 765 | reflectance(1:ng3D,:,:,jlev) = min(1.0_jprb,max(0.0_jprb, & |
---|
| 766 | & -solve_mat(ng,ng3D,nreg,Gamma_z1(1:ng3D,1:nreg,1:nreg), & |
---|
| 767 | & Gamma_z1(1:ng3D,1:nreg,nreg+1:2*nreg)))) |
---|
| 768 | ! Diffuse transmission matrix |
---|
| 769 | transmittance(1:ng3D,:,:,jlev) = min(1.0_jprb,max(0.0_jprb, & |
---|
| 770 | & mat_x_mat(ng,ng3D,nreg,Gamma_z1(1:ng3D,nreg+1:2*nreg,1:nreg), & |
---|
| 771 | & reflectance(1:ng3D,:,:,jlev)) & |
---|
| 772 | & + Gamma_z1(1:ng3D,nreg+1:2*nreg,nreg+1:2*nreg))) |
---|
| 773 | ! Transfer matrix between downward direct and upward |
---|
| 774 | ! diffuse |
---|
| 775 | ref_dir(1:ng3D,:,:,jlev) = min(mu0,max(0.0_jprb, & |
---|
| 776 | & -solve_mat(ng,ng3D,nreg,Gamma_z1(1:ng3D,1:nreg,1:nreg), & |
---|
| 777 | & Gamma_z1(1:ng3D,1:nreg,2*nreg+1:3*nreg)))) |
---|
| 778 | ! Transfer matrix between downward direct and downward |
---|
| 779 | ! diffuse in layer interface below. Include correction for |
---|
| 780 | ! trans_dir_diff out of plausible bounds (note that Meador & |
---|
| 781 | ! Weaver has the same correction in radiation_two_stream.F90 |
---|
| 782 | ! - this is not just an expm thing) |
---|
| 783 | trans_dir_diff(1:ng3D,:,:,jlev) = min(mu0,max(0.0_jprb, & |
---|
| 784 | & mat_x_mat(ng,ng3D,nreg,Gamma_z1(1:ng3D,nreg+1:2*nreg,1:nreg), & |
---|
| 785 | & ref_dir(1:ng3D,:,:,jlev)) & |
---|
| 786 | & + Gamma_z1(1:ng3D,nreg+1:2*nreg,2*nreg+1:3*nreg))) |
---|
| 787 | |
---|
| 788 | end if ! we are treating 3D effects for some g points |
---|
| 789 | |
---|
| 790 | ! --- Section 3.3b: g-points without 3D effects ---------- |
---|
| 791 | |
---|
| 792 | ! Compute reflectance, transmittance and associated terms for |
---|
| 793 | ! clear skies, using the Meador-Weaver formulas |
---|
| 794 | call calc_reflectance_transmittance_sw(ng, & |
---|
| 795 | & mu0, od_region(1:ng,1), ssa_region(1:ng,1), & |
---|
| 796 | & gamma1(1:ng,1), gamma2(1:ng,1), gamma3(1:ng,1), & |
---|
| 797 | & ref_clear(1:ng,jlev), trans_clear(1:ng,jlev), & |
---|
| 798 | & ref_dir_clear(1:ng,jlev), trans_dir_diff_clear(1:ng,jlev), & |
---|
| 799 | & trans_dir_dir_clear(1:ng,jlev) ) |
---|
| 800 | |
---|
| 801 | n_calls_meador_weaver = n_calls_meador_weaver + ng |
---|
| 802 | |
---|
| 803 | if (ng3D < ng) then |
---|
| 804 | ! Some of the g points are to be treated using the |
---|
| 805 | ! conventional plane-parallel method. First zero the |
---|
| 806 | ! relevant parts of the matrices |
---|
| 807 | trans_dir_dir (ng3D+1:ng,:,:,jlev) = 0.0_jprb |
---|
| 808 | reflectance (ng3D+1:ng,:,:,jlev) = 0.0_jprb |
---|
| 809 | transmittance (ng3D+1:ng,:,:,jlev) = 0.0_jprb |
---|
| 810 | ref_dir (ng3D+1:ng,:,:,jlev) = 0.0_jprb |
---|
| 811 | trans_dir_diff(ng3D+1:ng,:,:,jlev) = 0.0_jprb |
---|
| 812 | |
---|
| 813 | ! Since there is no lateral transport, the clear-sky parts |
---|
| 814 | ! of the arrays can be copied from the clear-sky arrays |
---|
| 815 | trans_dir_dir (ng3D+1:ng,1,1,jlev) = trans_dir_dir_clear (ng3D+1:ng,jlev) |
---|
| 816 | reflectance (ng3D+1:ng,1,1,jlev) = ref_clear (ng3D+1:ng,jlev) |
---|
| 817 | transmittance (ng3D+1:ng,1,1,jlev) = trans_clear (ng3D+1:ng,jlev) |
---|
| 818 | ref_dir (ng3D+1:ng,1,1,jlev) = ref_dir_clear (ng3D+1:ng,jlev) |
---|
| 819 | trans_dir_diff(ng3D+1:ng,1,1,jlev) = trans_dir_diff_clear(ng3D+1:ng,jlev) |
---|
| 820 | |
---|
| 821 | ! Compute reflectance, transmittance and associated terms |
---|
| 822 | ! for each cloudy region, using the Meador-Weaver formulas |
---|
| 823 | do jreg = 2, nregactive |
---|
| 824 | call calc_reflectance_transmittance_sw(ng-ng3D, & |
---|
| 825 | & mu0, & |
---|
| 826 | & od_region(ng3D+1:ng,jreg), ssa_region(ng3D+1:ng,jreg), & |
---|
| 827 | & gamma1(ng3D+1:ng,jreg), gamma2(ng3D+1:ng,jreg), & |
---|
| 828 | & gamma3(ng3D+1:ng,jreg), & |
---|
| 829 | & reflectance(ng3D+1:ng,jreg,jreg,jlev), & |
---|
| 830 | & transmittance(ng3D+1:ng,jreg,jreg,jlev), & |
---|
| 831 | & ref_dir(ng3D+1:ng,jreg,jreg,jlev), & |
---|
| 832 | & trans_dir_diff(ng3D+1:ng,jreg,jreg,jlev), & |
---|
| 833 | & trans_dir_dir(ng3D+1:ng,jreg,jreg,jlev) ) |
---|
| 834 | end do |
---|
| 835 | n_calls_meador_weaver & |
---|
| 836 | & = n_calls_meador_weaver + (ng-ng3D)*(nregactive-1) |
---|
| 837 | end if |
---|
| 838 | |
---|
| 839 | end do ! Loop over levels |
---|
| 840 | |
---|
| 841 | ! -------------------------------------------------------- |
---|
| 842 | ! Section 4: Compute total albedos |
---|
| 843 | ! -------------------------------------------------------- |
---|
| 844 | |
---|
| 845 | total_albedo(:,:,:,:) = 0.0_jprb |
---|
| 846 | total_albedo_direct(:,:,:,:) = 0.0_jprb |
---|
| 847 | |
---|
| 848 | if (config%do_clear) then |
---|
| 849 | total_albedo_clear(:,:) = 0.0_jprb |
---|
| 850 | total_albedo_clear_direct(:,:) = 0.0_jprb |
---|
| 851 | end if |
---|
| 852 | |
---|
| 853 | ! Calculate the upwelling radiation scattered from the direct |
---|
| 854 | ! beam incident on the surface, and copy the surface albedo |
---|
| 855 | ! into total_albedo |
---|
| 856 | do jreg = 1,nreg |
---|
| 857 | do jg = 1,ng |
---|
| 858 | total_albedo(jg,jreg,jreg,nlev+1) = albedo_diffuse(jg,jcol) |
---|
| 859 | total_albedo_direct(jg,jreg,jreg,nlev+1) & |
---|
| 860 | & = mu0 * albedo_direct(jg,jcol) |
---|
| 861 | end do |
---|
| 862 | end do |
---|
| 863 | |
---|
| 864 | if (config%do_clear) then |
---|
| 865 | ! Surface albedo is the same |
---|
| 866 | total_albedo_clear(1:ng,nlev+1) = total_albedo(1:ng,1,1,nlev+1) |
---|
| 867 | total_albedo_clear_direct(1:ng,nlev+1) & |
---|
| 868 | & = total_albedo_direct(1:ng,1,1,nlev+1) |
---|
| 869 | end if |
---|
| 870 | |
---|
| 871 | ! Horizontal migration distances of reflected radiation at the |
---|
| 872 | ! surface are zero |
---|
| 873 | x_diffuse = 0.0_jprb |
---|
| 874 | x_direct = 0.0_jprb |
---|
| 875 | |
---|
| 876 | ! Work back up through the atmosphere computing the total albedo |
---|
| 877 | ! of the atmosphere below that point using the adding method |
---|
| 878 | do jlev = nlev,1,-1 |
---|
| 879 | |
---|
| 880 | ! -------------------------------------------------------- |
---|
| 881 | ! Section 4.1: Adding method |
---|
| 882 | ! -------------------------------------------------------- |
---|
| 883 | |
---|
| 884 | if (config%do_clear) then |
---|
| 885 | ! Use adding method for clear-sky arrays; note that there |
---|
| 886 | ! is no need to consider "above" and "below" quantities |
---|
| 887 | ! since with no cloud overlap to worry about, these are |
---|
| 888 | ! the same |
---|
| 889 | inv_denom_scalar(:) = 1.0_jprb & |
---|
| 890 | & / (1.0_jprb - total_albedo_clear(:,jlev+1)*ref_clear(:,jlev)) |
---|
| 891 | total_albedo_clear(:,jlev) = ref_clear(:,jlev) & |
---|
| 892 | & + trans_clear(:,jlev)*trans_clear(:,jlev)*total_albedo_clear(:,jlev+1) & |
---|
| 893 | & * inv_denom_scalar(:) |
---|
| 894 | total_albedo_clear_direct(:,jlev) = ref_dir_clear(:,jlev) & |
---|
| 895 | & + (trans_dir_dir_clear(:,jlev) * total_albedo_clear_direct(:,jlev+1) & |
---|
| 896 | & +trans_dir_diff_clear(:,jlev) * total_albedo_clear(:,jlev+1)) & |
---|
| 897 | & * trans_clear(:,jlev) * inv_denom_scalar(:) |
---|
| 898 | end if |
---|
| 899 | |
---|
| 900 | if (is_clear_sky_layer(jlev)) then |
---|
| 901 | ! Clear-sky layer: use scalar adding method |
---|
| 902 | inv_denom_scalar(:) = 1.0_jprb & |
---|
| 903 | & / (1.0_jprb - total_albedo(:,1,1,jlev+1)*reflectance(:,1,1,jlev)) |
---|
| 904 | total_albedo_below = 0.0_jprb |
---|
| 905 | total_albedo_below(:,1,1) = reflectance(:,1,1,jlev) & |
---|
| 906 | & + transmittance(:,1,1,jlev) * transmittance(:,1,1,jlev) & |
---|
| 907 | & * total_albedo(:,1,1,jlev+1) * inv_denom_scalar(:) |
---|
| 908 | total_albedo_below_direct = 0.0_jprb |
---|
| 909 | total_albedo_below_direct(:,1,1) = ref_dir(:,1,1,jlev) & |
---|
| 910 | & + (trans_dir_dir(:,1,1,jlev)*total_albedo_direct(:,1,1,jlev+1) & |
---|
| 911 | & +trans_dir_diff(:,1,1,jlev)*total_albedo(:,1,1,jlev+1)) & |
---|
| 912 | & * transmittance(:,1,1,jlev) * inv_denom_scalar(:) |
---|
| 913 | else |
---|
| 914 | ! Cloudy layer: use matrix adding method |
---|
| 915 | denominator = identity_minus_mat_x_mat(ng,ng,nreg, & |
---|
| 916 | & total_albedo(:,:,:,jlev+1), reflectance(:,:,:,jlev)) |
---|
| 917 | total_albedo_below = reflectance(:,:,:,jlev) & |
---|
| 918 | & + mat_x_mat(ng,ng,nreg,transmittance(:,:,:,jlev), & |
---|
| 919 | & solve_mat(ng,ng,nreg,denominator, & |
---|
| 920 | & mat_x_mat(ng,ng,nreg,total_albedo(:,:,:,jlev+1), & |
---|
| 921 | & transmittance(:,:,:,jlev)))) |
---|
| 922 | total_albedo_below_direct = ref_dir(:,:,:,jlev) & |
---|
| 923 | & + mat_x_mat(ng,ng,nreg,transmittance(:,:,:,jlev), & |
---|
| 924 | & solve_mat(ng,ng,nreg,denominator, & |
---|
| 925 | & mat_x_mat(ng,ng,nreg,total_albedo_direct(:,:,:,jlev+1), & |
---|
| 926 | & trans_dir_dir(:,:,:,jlev)) & |
---|
| 927 | & +mat_x_mat(ng,ng,nreg,total_albedo(:,:,:,jlev+1), & |
---|
| 928 | & trans_dir_diff(:,:,:,jlev)))) |
---|
| 929 | end if |
---|
| 930 | |
---|
| 931 | ! -------------------------------------------------------- |
---|
| 932 | ! Section 4.2: Overlap and entrapment |
---|
| 933 | ! -------------------------------------------------------- |
---|
| 934 | |
---|
| 935 | #ifndef PRINT_ENTRAPMENT_DATA |
---|
| 936 | if ((config%i_3d_sw_entrapment == IEntrapmentExplicitNonFractal & |
---|
| 937 | & .or. config%i_3d_sw_entrapment == IEntrapmentExplicit) & |
---|
| 938 | & .and. jlev >= i_cloud_top) then |
---|
| 939 | #else |
---|
| 940 | if (config%i_3d_sw_entrapment == IEntrapmentExplicitNonFractal & |
---|
| 941 | & .or. config%i_3d_sw_entrapment == IEntrapmentExplicit) then |
---|
| 942 | #endif |
---|
| 943 | ! "Explicit entrapment": we have the horizontal migration |
---|
| 944 | ! distances just above the base of the layer, and need to |
---|
| 945 | ! step them to just below the top of the same layer |
---|
| 946 | call step_migrations(ng, nreg, cloud%fraction(jcol,jlev), & |
---|
| 947 | & layer_depth(jlev), tan_diffuse_angle_3d, tan_sza, & |
---|
| 948 | & reflectance(:,:,:,jlev), transmittance(:,:,:,jlev), & |
---|
| 949 | & ref_dir(:,:,:,jlev), trans_dir_dir(:,:,:,jlev), & |
---|
| 950 | & trans_dir_diff(:,:,:,jlev), total_albedo(:,:,:,jlev+1), & |
---|
| 951 | & total_albedo_direct(:,:,:,jlev+1), & |
---|
| 952 | & x_diffuse, x_direct) |
---|
| 953 | |
---|
| 954 | #ifdef PRINT_ENTRAPMENT_DATA |
---|
| 955 | ! Write out for later analysis: these are the entrapment |
---|
| 956 | ! statistics at the top of layer "jlev" |
---|
| 957 | ! Note that number of scattering events is now not computed, |
---|
| 958 | ! so print "1.0" |
---|
| 959 | if (nreg == 2) then |
---|
| 960 | write(101,'(i4,i4,6e14.6)') jcol, jlev, & |
---|
| 961 | & x_direct(1,:), x_diffuse(1,:), x_direct(1,:)*0.0_jprb+1.0_jprb |
---|
| 962 | else |
---|
| 963 | write(101,'(i4,i4,9e14.6)') jcol, jlev, & |
---|
| 964 | & x_direct(1,1:3), x_diffuse(1,1:3), 1.0_jprb,1.0_jprb,1.0_jprb |
---|
| 965 | end if |
---|
| 966 | #endif |
---|
| 967 | |
---|
| 968 | end if |
---|
| 969 | |
---|
| 970 | ! Account for cloud overlap when converting albedo and source |
---|
| 971 | ! below a layer interface to the equivalent values just above |
---|
| 972 | if (is_clear_sky_layer(jlev) .and. is_clear_sky_layer(jlev-1)) then |
---|
| 973 | ! If both layers are cloud free, this is trivial... |
---|
| 974 | total_albedo(:,:,:,jlev) = 0.0_jprb |
---|
| 975 | total_albedo(:,1,1,jlev) = total_albedo_below(:,1,1) |
---|
| 976 | total_albedo_direct(:,:,:,jlev) = 0.0_jprb |
---|
| 977 | total_albedo_direct(:,1,1,jlev) = total_albedo_below_direct(:,1,1) |
---|
| 978 | |
---|
| 979 | else if (config%i_3d_sw_entrapment == IEntrapmentMaximum & |
---|
| 980 | & .or. is_clear_sky_layer(jlev-1)) then |
---|
| 981 | ! "Maximum entrapment": use the overlap matrices u_matrix and v_matrix |
---|
| 982 | ! (this is the original SPARTACUS method) |
---|
| 983 | total_albedo(:,:,:,jlev) = singlemat_x_mat(ng,ng,nreg,& |
---|
| 984 | & u_matrix(:,:,jlev,jcol), & |
---|
| 985 | & mat_x_singlemat(ng,ng,nreg,total_albedo_below,& |
---|
| 986 | & v_matrix(:,:,jlev,jcol))) |
---|
| 987 | total_albedo_direct(:,:,:,jlev) = singlemat_x_mat(ng,ng,nreg,& |
---|
| 988 | & u_matrix(:,:,jlev,jcol), & |
---|
| 989 | & mat_x_singlemat(ng,ng,nreg,total_albedo_below_direct,& |
---|
| 990 | & v_matrix(:,:,jlev,jcol))) |
---|
| 991 | |
---|
| 992 | else if (config%i_3d_sw_entrapment == IEntrapmentZero) then |
---|
| 993 | ! "Zero entrapment": even radiation transported |
---|
| 994 | ! laterally between regions in the layers below is |
---|
| 995 | ! reflected back up into the same region. First diffuse |
---|
| 996 | ! radiation: |
---|
| 997 | total_albedo(:,:,:,jlev) = 0.0_jprb |
---|
| 998 | do jreg = 1,nreg ! Target layer (jlev-1) |
---|
| 999 | do jreg2 = 1,nreg ! Current layer (jlev) |
---|
| 1000 | total_albedo(:,jreg,jreg,jlev) = total_albedo(:,jreg,jreg,jlev) & |
---|
| 1001 | & + sum(total_albedo_below(:,:,jreg2),2) & |
---|
| 1002 | & * v_matrix(jreg2,jreg,jlev,jcol) |
---|
| 1003 | end do |
---|
| 1004 | end do |
---|
| 1005 | ! ...then direct radiation: |
---|
| 1006 | total_albedo_direct(:,:,:,jlev) = 0.0_jprb |
---|
| 1007 | do jreg = 1,nreg ! Target layer (jlev-1) |
---|
| 1008 | do jreg2 = 1,nreg ! Current layer (jlev) |
---|
| 1009 | total_albedo_direct(:,jreg,jreg,jlev) = total_albedo_direct(:,jreg,jreg,jlev) & |
---|
| 1010 | & + sum(total_albedo_below_direct(:,:,jreg2),2) & |
---|
| 1011 | & * v_matrix(jreg2,jreg,jlev,jcol) |
---|
| 1012 | end do |
---|
| 1013 | end do |
---|
| 1014 | |
---|
| 1015 | else |
---|
| 1016 | ! Controlled entrapment |
---|
| 1017 | |
---|
| 1018 | #ifdef EXPLICIT_EDGE_ENTRAPMENT |
---|
| 1019 | ! If "EXPLICIT_EDGE_ENTRAPMENT" is defined then we use the |
---|
| 1020 | ! explicit entrapment approach for both horizontal transport |
---|
| 1021 | ! within regions, and horizontal transport between regions |
---|
| 1022 | ! (otherwise, horizontal transport between regions is |
---|
| 1023 | ! automatically treated using maximum entrapment). This is |
---|
| 1024 | ! experimental, which is why it is not a run-time option. |
---|
| 1025 | |
---|
| 1026 | if (config%i_3d_sw_entrapment == IEntrapmentEdgeOnly) then |
---|
| 1027 | #endif |
---|
| 1028 | ! Add the contribution from off-diagonal elements of the |
---|
| 1029 | ! albedo matrix in the lower layer, i.e. radiation that |
---|
| 1030 | ! flows between regions... |
---|
| 1031 | |
---|
| 1032 | ! First diffuse radiation: |
---|
| 1033 | albedo_part = total_albedo_below |
---|
| 1034 | do jreg = 1,nreg |
---|
| 1035 | albedo_part(:,jreg,jreg) = 0.0_jprb |
---|
| 1036 | end do |
---|
| 1037 | total_albedo(:,:,:,jlev) = singlemat_x_mat(ng,ng,nreg,& |
---|
| 1038 | & u_matrix(:,:,jlev,jcol), & |
---|
| 1039 | & mat_x_singlemat(ng,ng,nreg,albedo_part,& |
---|
| 1040 | & v_matrix(:,:,jlev,jcol))) |
---|
| 1041 | ! ...then direct radiation: |
---|
| 1042 | albedo_part = total_albedo_below_direct |
---|
| 1043 | do jreg = 1,nreg |
---|
| 1044 | albedo_part(:,jreg,jreg) = 0.0_jprb |
---|
| 1045 | end do |
---|
| 1046 | total_albedo_direct(:,:,:,jlev) = singlemat_x_mat(ng,ng,nreg,& |
---|
| 1047 | & u_matrix(:,:,jlev,jcol), & |
---|
| 1048 | & mat_x_singlemat(ng,ng,nreg,albedo_part,& |
---|
| 1049 | & v_matrix(:,:,jlev,jcol))) |
---|
| 1050 | |
---|
| 1051 | #ifdef EXPLICIT_EDGE_ENTRAPMENT |
---|
| 1052 | end if |
---|
| 1053 | #endif |
---|
| 1054 | |
---|
| 1055 | ! Now the contribution from the diagonals of the albedo |
---|
| 1056 | ! matrix in the lower layer |
---|
| 1057 | if (config%i_3d_sw_entrapment == IEntrapmentEdgeOnly & |
---|
| 1058 | & .or. (.not. config%do_3d_effects)) then |
---|
| 1059 | ! "Edge-only entrapment": the operation we perform is |
---|
| 1060 | ! essentially diag(total_albedo) += matmul(transpose(v_matrix), |
---|
| 1061 | ! diag(total_albedo_below)). |
---|
| 1062 | do jreg = 1,nreg |
---|
| 1063 | do jreg2 = 1,nreg |
---|
| 1064 | total_albedo(:,jreg,jreg,jlev) & |
---|
| 1065 | & = total_albedo(:,jreg,jreg,jlev) & |
---|
| 1066 | & + total_albedo_below(:,jreg2,jreg2) & |
---|
| 1067 | & * v_matrix(jreg2,jreg,jlev,jcol) |
---|
| 1068 | total_albedo_direct(:,jreg,jreg,jlev) & |
---|
| 1069 | & = total_albedo_direct(:,jreg,jreg,jlev) & |
---|
| 1070 | & + total_albedo_below_direct(:,jreg2,jreg2) & |
---|
| 1071 | & * v_matrix(jreg2,jreg,jlev,jcol) |
---|
| 1072 | end do |
---|
| 1073 | end do |
---|
| 1074 | |
---|
| 1075 | else |
---|
| 1076 | ! "Explicit entrapment" |
---|
| 1077 | |
---|
| 1078 | do jreg2 = 1,nreg |
---|
| 1079 | ! Loop through each region in the lower layer. For one |
---|
| 1080 | ! of the regions in the lower layer, we are imagining it |
---|
| 1081 | ! to be divided into "nreg" subregions that map onto the |
---|
| 1082 | ! regions in the upper layer. The rate of exchange |
---|
| 1083 | ! between these subregions is computed via a coupled |
---|
| 1084 | ! differential equation written in terms of a singular |
---|
| 1085 | ! exchange matrix (there are only terms for the exchange |
---|
| 1086 | ! between subregions, but no propagation effects since |
---|
| 1087 | ! we already know the albedo of this region). This is |
---|
| 1088 | ! solved using the matrix-exponential method. |
---|
| 1089 | |
---|
| 1090 | ! Use the following array for the transfer of either |
---|
| 1091 | ! diffuse or direct radiation (despite the name), per |
---|
| 1092 | ! unit horizontal distance travelled |
---|
| 1093 | transfer_rate_diffuse = 0.0_jprb |
---|
| 1094 | |
---|
| 1095 | ! As we need to reference the layer above the interface, |
---|
| 1096 | ! don't do the following on the highest layer |
---|
| 1097 | if (jlev > 1) then |
---|
| 1098 | |
---|
| 1099 | ! Given a horizontal migration distance, there is |
---|
| 1100 | ! still uncertainty about how much entrapment occurs |
---|
| 1101 | ! associated with how one assumes cloud boundaries |
---|
| 1102 | ! line up in adjacent layers. "overhang_factor" |
---|
| 1103 | ! can be varied between 0.0 (the boundaries line up to |
---|
| 1104 | ! the greatest extent possible given the overlap |
---|
| 1105 | ! parameter) and 1.0 (the boundaries line up to the |
---|
| 1106 | ! minimum extent possible); here this is used to |
---|
| 1107 | ! produce a scaling factor for the transfer rate. |
---|
| 1108 | transfer_scaling = 1.0_jprb - (1.0_jprb - config%overhang_factor) & |
---|
| 1109 | & * cloud%overlap_param(jcol,jlev-1) & |
---|
| 1110 | & * min(region_fracs(jreg2,jlev,jcol),region_fracs(jreg2,jlev-1,jcol)) & |
---|
| 1111 | & / max(config%cloud_fraction_threshold, region_fracs(jreg2,jlev,jcol)) |
---|
| 1112 | |
---|
| 1113 | do jreg = 1, nreg-1 |
---|
| 1114 | ! Compute lateral transfer rates from region jreg to |
---|
| 1115 | ! jreg+1 as before, but without length scale which |
---|
| 1116 | ! is wavelength dependent. |
---|
| 1117 | |
---|
| 1118 | ! Recall that overlap indexing is |
---|
| 1119 | ! u_matrix(upper_region, lower_region, level, |
---|
| 1120 | ! column). |
---|
| 1121 | transfer_rate_diffuse(jreg,jreg+1) = transfer_scaling & |
---|
| 1122 | & * edge_length(jreg,jlev-1) / max(u_matrix(jreg,jreg2,jlev,jcol),1.0e-5_jprb) |
---|
| 1123 | ! Compute transfer rates from region jreg+1 to jreg |
---|
| 1124 | transfer_rate_diffuse(jreg+1,jreg) = transfer_scaling & |
---|
| 1125 | & * edge_length(jreg,jlev-1) / max(u_matrix(jreg+1,jreg2,jlev,jcol),1.0e-5_jprb) |
---|
| 1126 | end do |
---|
| 1127 | |
---|
| 1128 | ! Compute transfer rates directly between regions 1 |
---|
| 1129 | ! and 3 (not used below) |
---|
| 1130 | if (edge_length(3,jlev) > 0.0_jprb) then |
---|
| 1131 | transfer_rate_diffuse(1,3) = transfer_scaling & |
---|
| 1132 | & * edge_length(3,jlev-1) / max(u_matrix(1,jreg2,jlev,jcol),1.0e-5_jprb) |
---|
| 1133 | transfer_rate_diffuse(3,1) = transfer_scaling & |
---|
| 1134 | & * edge_length(3,jlev-1) / max(u_matrix(3,jreg2,jlev,jcol),1.0e-5_jprb) |
---|
| 1135 | end if |
---|
| 1136 | end if |
---|
| 1137 | |
---|
| 1138 | ! Compute matrix of exchange coefficients |
---|
| 1139 | entrapment = 0.0_jprb |
---|
| 1140 | inv_effective_size = min(cloud%inv_cloud_effective_size(jcol,jlev-1), & |
---|
| 1141 | & 1.0_jprb/config%min_cloud_effective_size) |
---|
| 1142 | do jreg = 1,nreg-1 |
---|
| 1143 | ! Diffuse transport down and up with one random |
---|
| 1144 | ! scattering event |
---|
| 1145 | if (config%i_3d_sw_entrapment == IEntrapmentExplicit) then |
---|
| 1146 | fractal_factor = 1.0_jprb / sqrt(max(1.0_jprb, 2.5_jprb*x_diffuse(:,jreg2) & |
---|
| 1147 | & * inv_effective_size)) |
---|
| 1148 | entrapment(:,jreg+1,jreg) = entrapment(:,jreg+1,jreg) & |
---|
| 1149 | & + transfer_rate_diffuse(jreg,jreg+1)*x_diffuse(:,jreg2) & |
---|
| 1150 | & * fractal_factor |
---|
| 1151 | entrapment(:,jreg,jreg+1) = entrapment(:,jreg,jreg+1) & |
---|
| 1152 | & + transfer_rate_diffuse(jreg+1,jreg)*x_diffuse(:,jreg2) & |
---|
| 1153 | & * fractal_factor |
---|
| 1154 | else |
---|
| 1155 | entrapment(:,jreg+1,jreg) = entrapment(:,jreg+1,jreg) & |
---|
| 1156 | & + transfer_rate_diffuse(jreg,jreg+1)*x_diffuse(:,jreg2) |
---|
| 1157 | entrapment(:,jreg,jreg+1) = entrapment(:,jreg,jreg+1) & |
---|
| 1158 | & + transfer_rate_diffuse(jreg+1,jreg)*x_diffuse(:,jreg2) |
---|
| 1159 | end if |
---|
| 1160 | entrapment(:,jreg,jreg) = entrapment(:,jreg,jreg) & |
---|
| 1161 | & - entrapment(:,jreg+1,jreg) |
---|
| 1162 | entrapment(:,jreg+1,jreg+1) = entrapment(:,jreg+1,jreg+1) & |
---|
| 1163 | & - entrapment(:,jreg,jreg+1) |
---|
| 1164 | end do |
---|
| 1165 | |
---|
| 1166 | ! If rate of exchange is excessive the expm can throw a |
---|
| 1167 | ! floating point exception, even if it tends towards a |
---|
| 1168 | ! trival limit, so we cap the maximum input to expm by |
---|
| 1169 | ! scaling down if necessary |
---|
| 1170 | do jg = 1,ng |
---|
| 1171 | max_entr = -min(entrapment(jg,1,1),entrapment(jg,2,2)) |
---|
| 1172 | if (max_entr > config%max_cloud_od) then |
---|
| 1173 | ! Scale down all inputs for this g point |
---|
| 1174 | entrapment(jg,:,:) = entrapment(jg,:,:) * (config%max_cloud_od/max_entr) |
---|
| 1175 | end if |
---|
| 1176 | end do |
---|
| 1177 | |
---|
| 1178 | ! Since the matrix to be exponentiated has a simple |
---|
| 1179 | ! structure we may use a faster method described in the |
---|
| 1180 | ! appendix of Hogan et al. (GMD 2018) |
---|
| 1181 | #define USE_FAST_EXPM_EXCHANGE 1 |
---|
| 1182 | #ifdef USE_FAST_EXPM_EXCHANGE |
---|
| 1183 | if (nreg == 2) then |
---|
| 1184 | call fast_expm_exchange(ng, ng, entrapment(:,2,1), entrapment(:,1,2), & |
---|
| 1185 | & albedo_part) |
---|
| 1186 | else |
---|
| 1187 | call fast_expm_exchange(ng, ng, entrapment(:,2,1), entrapment(:,1,2), & |
---|
| 1188 | & entrapment(:,3,2), entrapment(:,2,3), & |
---|
| 1189 | & albedo_part) |
---|
| 1190 | end if |
---|
| 1191 | #else |
---|
| 1192 | ! Use matrix exponential to compute rate of exchange |
---|
| 1193 | albedo_part = entrapment |
---|
| 1194 | call expm(ng, ng, nreg, albedo_part, IMatrixPatternDense) |
---|
| 1195 | n_calls_expm = n_calls_expm + ng |
---|
| 1196 | #endif |
---|
| 1197 | |
---|
| 1198 | #ifndef EXPLICIT_EDGE_ENTRAPMENT |
---|
| 1199 | ! Scale to get the contribution to the diffuse albedo |
---|
| 1200 | do jreg3 = 1,nreg |
---|
| 1201 | do jreg = 1,nreg |
---|
| 1202 | albedo_part(:,jreg3,jreg) = albedo_part(:,jreg3,jreg) & |
---|
| 1203 | & * v_matrix(jreg2,jreg,jlev,jcol) * total_albedo_below(:,jreg2,jreg2) |
---|
| 1204 | end do |
---|
| 1205 | end do |
---|
| 1206 | #else |
---|
| 1207 | ! The following is an experimental treatment that tries |
---|
| 1208 | ! to explicitly account for the horizontal distance |
---|
| 1209 | ! traveled by radiation that passes through cloud sides |
---|
| 1210 | entrapment = albedo_part |
---|
| 1211 | albedo_part = 0.0_jprb |
---|
| 1212 | ! Scale to get the contribution to the diffuse albedo |
---|
| 1213 | do jreg3 = 1,nreg ! TO upper region |
---|
| 1214 | do jreg = 1,nreg ! FROM upper region |
---|
| 1215 | transfer_scaling = 1.0_jprb - (1.0_jprb - config%overhang_factor) & |
---|
| 1216 | & * cloud%overlap_param(jcol,jlev-1) & |
---|
| 1217 | & * min(region_fracs(jreg,jlev,jcol), region_fracs(jreg,jlev,jcol)) & |
---|
| 1218 | & / max(config%cloud_fraction_threshold, region_fracs(jreg,jlev,jcol)) |
---|
| 1219 | do jreg4 = 1,nreg ! VIA first lower region (jreg2 is second lower region) |
---|
| 1220 | if (.not. (jreg4 == jreg .and. jreg4 /= jreg2)) then |
---|
| 1221 | albedo_part(:,jreg3,jreg) = albedo_part(:,jreg3,jreg) + entrapment(:,jreg3,jreg) & |
---|
| 1222 | & * v_matrix(jreg4,jreg,jlev,jcol) * total_albedo_below(:,jreg2,jreg4) |
---|
| 1223 | else |
---|
| 1224 | albedo_part(:,jreg3,jreg) = albedo_part(:,jreg3,jreg) & |
---|
| 1225 | & + v_matrix(jreg4,jreg,jlev,jcol) * total_albedo_below(:,jreg2,jreg4) & |
---|
| 1226 | & * (transfer_scaling * entrapment(:,jreg3,jreg) & |
---|
| 1227 | & +((1.0_jprb-transfer_scaling) * entrapment(:,jreg3,jreg2))) |
---|
| 1228 | end if |
---|
| 1229 | end do |
---|
| 1230 | end do |
---|
| 1231 | end do |
---|
| 1232 | #endif |
---|
| 1233 | |
---|
| 1234 | ! Increment diffuse albedo |
---|
| 1235 | total_albedo(:,:,:,jlev) = total_albedo(:,:,:,jlev) + albedo_part |
---|
| 1236 | |
---|
| 1237 | ! Now do the same for the direct albedo |
---|
| 1238 | entrapment = 0.0_jprb |
---|
| 1239 | do jreg = 1,nreg-1 |
---|
| 1240 | ! Direct transport down and diffuse up with one random |
---|
| 1241 | ! scattering event |
---|
| 1242 | if (config%i_3d_sw_entrapment == IEntrapmentExplicit) then |
---|
| 1243 | fractal_factor = 1.0_jprb / sqrt(max(1.0_jprb, 2.5_jprb*x_direct(:,jreg2) & |
---|
| 1244 | & * inv_effective_size)) |
---|
| 1245 | entrapment(:,jreg+1,jreg) = entrapment(:,jreg+1,jreg) & |
---|
| 1246 | & + transfer_rate_diffuse(jreg,jreg+1)*x_direct(:,jreg2) & |
---|
| 1247 | & * fractal_factor |
---|
| 1248 | entrapment(:,jreg,jreg+1) = entrapment(:,jreg,jreg+1) & |
---|
| 1249 | & + transfer_rate_diffuse(jreg+1,jreg)*x_direct(:,jreg2) & |
---|
| 1250 | & * fractal_factor |
---|
| 1251 | else |
---|
| 1252 | entrapment(:,jreg+1,jreg) = entrapment(:,jreg+1,jreg) & |
---|
| 1253 | & + transfer_rate_diffuse(jreg,jreg+1)*x_direct(:,jreg2) |
---|
| 1254 | entrapment(:,jreg,jreg+1) = entrapment(:,jreg,jreg+1) & |
---|
| 1255 | & + transfer_rate_diffuse(jreg+1,jreg)*x_direct(:,jreg2) |
---|
| 1256 | end if |
---|
| 1257 | entrapment(:,jreg,jreg) = entrapment(:,jreg,jreg) & |
---|
| 1258 | & - entrapment(:,jreg+1,jreg) |
---|
| 1259 | entrapment(:,jreg+1,jreg+1) = entrapment(:,jreg+1,jreg+1) & |
---|
| 1260 | & - entrapment(:,jreg,jreg+1) |
---|
| 1261 | end do |
---|
| 1262 | |
---|
| 1263 | ! If rate of exchange is excessive the expm can throw a |
---|
| 1264 | ! floating point exception, even if it tends towards a |
---|
| 1265 | ! trival limit, so we cap the maximum input to expm by |
---|
| 1266 | ! scaling down if necessary |
---|
| 1267 | do jg = 1,ng |
---|
| 1268 | max_entr = -min(entrapment(jg,1,1),entrapment(jg,2,2)) |
---|
| 1269 | if (max_entr > config%max_cloud_od) then |
---|
| 1270 | ! Scale down all inputs for this g point |
---|
| 1271 | entrapment(jg,:,:) = entrapment(jg,:,:) * (config%max_cloud_od/max_entr) |
---|
| 1272 | end if |
---|
| 1273 | end do |
---|
| 1274 | |
---|
| 1275 | |
---|
| 1276 | #ifdef USE_FAST_EXPM_EXCHANGE |
---|
| 1277 | if (nreg == 2) then |
---|
| 1278 | call fast_expm_exchange(ng, ng, entrapment(:,2,1), entrapment(:,1,2), & |
---|
| 1279 | & albedo_part) |
---|
| 1280 | else |
---|
| 1281 | call fast_expm_exchange(ng, ng, entrapment(:,2,1), entrapment(:,1,2), & |
---|
| 1282 | & entrapment(:,3,2), entrapment(:,2,3), & |
---|
| 1283 | & albedo_part) |
---|
| 1284 | end if |
---|
| 1285 | #else |
---|
| 1286 | albedo_part = entrapment |
---|
| 1287 | call expm(ng, ng, nreg, albedo_part, IMatrixPatternDense) |
---|
| 1288 | n_calls_expm = n_calls_expm + ng |
---|
| 1289 | #endif |
---|
| 1290 | |
---|
| 1291 | #ifndef EXPLICIT_EDGE_ENTRAPMENT |
---|
| 1292 | do jreg3 = 1,nreg |
---|
| 1293 | do jreg = 1,nreg |
---|
| 1294 | albedo_part(:,jreg3,jreg) = albedo_part(:,jreg3,jreg) & |
---|
| 1295 | & * v_matrix(jreg2,jreg,jlev,jcol) * total_albedo_below_direct(:,jreg2,jreg2) |
---|
| 1296 | end do |
---|
| 1297 | end do |
---|
| 1298 | #else |
---|
| 1299 | entrapment = albedo_part |
---|
| 1300 | albedo_part = 0.0_jprb |
---|
| 1301 | do jreg3 = 1,nreg |
---|
| 1302 | do jreg = 1,nreg |
---|
| 1303 | transfer_scaling = 1.0_jprb - (1.0_jprb - config%overhang_factor) & |
---|
| 1304 | & * cloud%overlap_param(jcol,jlev-1) & |
---|
| 1305 | & * min(region_fracs(jreg,jlev,jcol), region_fracs(jreg,jlev-1,jcol)) |
---|
| 1306 | & / max(config%cloud_fraction_threshold, region_fracs(jreg,jlev,jcol)) |
---|
| 1307 | do jreg4 = 1,nreg |
---|
| 1308 | if (.not. (jreg4 == jreg .and. jreg4 /= jreg2)) then |
---|
| 1309 | albedo_part(:,jreg3,jreg) = albedo_part(:,jreg3,jreg) + entrapment(:,jreg3,jreg) & |
---|
| 1310 | & * v_matrix(jreg4,jreg,jlev,jcol) * total_albedo_below_direct(:,jreg2,jreg4) |
---|
| 1311 | else |
---|
| 1312 | albedo_part(:,jreg3,jreg) = albedo_part(:,jreg3,jreg) & |
---|
| 1313 | & + v_matrix(jreg4,jreg,jlev,jcol) * total_albedo_below_direct(:,jreg2,jreg4) & |
---|
| 1314 | & * (transfer_scaling * entrapment(:,jreg3,jreg) & |
---|
| 1315 | & +((1.0_jprb-transfer_scaling) * entrapment(:,jreg3,jreg2))) |
---|
| 1316 | end if |
---|
| 1317 | end do |
---|
| 1318 | end do |
---|
| 1319 | end do |
---|
| 1320 | |
---|
| 1321 | #endif |
---|
| 1322 | ! Increment direct albedo |
---|
| 1323 | total_albedo_direct(:,:,:,jlev) = total_albedo_direct(:,:,:,jlev) + albedo_part |
---|
| 1324 | |
---|
| 1325 | end do |
---|
| 1326 | |
---|
| 1327 | end if |
---|
| 1328 | end if |
---|
| 1329 | |
---|
| 1330 | if ((config%i_3d_sw_entrapment == IEntrapmentExplicitNonFractal & |
---|
| 1331 | & .or. config%i_3d_sw_entrapment == IEntrapmentExplicit) & |
---|
| 1332 | & .and. .not. (is_clear_sky_layer(jlev) .and. is_clear_sky_layer(jlev-1))) then |
---|
| 1333 | ! Horizontal migration distances are averaged when |
---|
| 1334 | ! applying overlap rules, so equation is |
---|
| 1335 | ! x_above=matmul(transpose(v_matrix),x_below) |
---|
| 1336 | |
---|
| 1337 | ! We do this into temporary arrays... |
---|
| 1338 | x_direct_above = 0.0_jprb |
---|
| 1339 | x_diffuse_above = 0.0_jprb |
---|
| 1340 | |
---|
| 1341 | nregactive = nreg |
---|
| 1342 | if (is_clear_sky_layer(jlev)) then |
---|
| 1343 | nregactive = 1 |
---|
| 1344 | end if |
---|
| 1345 | |
---|
| 1346 | do jreg = 1,nreg ! Target layer (jlev-1) |
---|
| 1347 | do jreg2 = 1,nregactive ! Current layer (jlev) |
---|
| 1348 | x_direct_above(:,jreg) = x_direct_above(:,jreg) & |
---|
| 1349 | & + x_direct(:,jreg2) * v_matrix(jreg2,jreg,jlev,jcol) |
---|
| 1350 | x_diffuse_above(:,jreg) = x_diffuse_above(:,jreg) & |
---|
| 1351 | & + x_diffuse(:,jreg2) * v_matrix(jreg2,jreg,jlev,jcol) |
---|
| 1352 | end do |
---|
| 1353 | end do |
---|
| 1354 | |
---|
| 1355 | !... then copy out of the temporary arrays |
---|
| 1356 | x_direct = x_direct_above |
---|
| 1357 | x_diffuse = x_diffuse_above |
---|
| 1358 | end if |
---|
| 1359 | |
---|
| 1360 | end do ! Reverse loop over levels |
---|
| 1361 | |
---|
| 1362 | ! -------------------------------------------------------- |
---|
| 1363 | ! Section 5: Compute fluxes |
---|
| 1364 | ! -------------------------------------------------------- |
---|
| 1365 | |
---|
| 1366 | ! Top-of-atmosphere fluxes into the regions of the top-most |
---|
| 1367 | ! layer, zero since we assume no diffuse downwelling |
---|
| 1368 | flux_dn_below = 0.0_jprb |
---|
| 1369 | ! Direct downwelling flux (into a plane perpendicular to the |
---|
| 1370 | ! sun) entering the top of each region in the top-most layer |
---|
| 1371 | do jreg = 1,nreg |
---|
| 1372 | direct_dn_below(:,jreg) = incoming_sw(:,jcol)*region_fracs(jreg,1,jcol) |
---|
| 1373 | end do |
---|
| 1374 | ! We're using flux_up_above as a container; actually its |
---|
| 1375 | ! interpretation at top of atmosphere here is just 'below' the |
---|
| 1376 | ! TOA interface, so using the regions of the first model layer |
---|
| 1377 | flux_up_above = mat_x_vec(ng,ng,nreg,total_albedo_direct(:,:,:,1),direct_dn_below) |
---|
| 1378 | |
---|
| 1379 | if (config%do_clear) then |
---|
| 1380 | flux_dn_clear = 0.0_jprb |
---|
| 1381 | direct_dn_clear(:) = incoming_sw(:,jcol) |
---|
| 1382 | flux_up_clear = direct_dn_clear*total_albedo_clear_direct(:,1) |
---|
| 1383 | end if |
---|
| 1384 | |
---|
| 1385 | ! Store the TOA broadband fluxes |
---|
| 1386 | flux%sw_up(jcol,1) = sum(sum(flux_up_above,1)) |
---|
| 1387 | flux%sw_dn(jcol,1) = mu0 * sum(direct_dn_clear(:)) |
---|
| 1388 | if (allocated(flux%sw_dn_direct)) then |
---|
| 1389 | flux%sw_dn_direct(jcol,1) = flux%sw_dn(jcol,1) |
---|
| 1390 | end if |
---|
| 1391 | if (config%do_clear) then |
---|
| 1392 | flux%sw_up_clear(jcol,1) = sum(flux_up_clear) |
---|
| 1393 | flux%sw_dn_clear(jcol,1) = flux%sw_dn(jcol,1) |
---|
| 1394 | if (allocated(flux%sw_dn_direct_clear)) then |
---|
| 1395 | flux%sw_dn_direct_clear(jcol,1) = flux%sw_dn_clear(jcol,1) |
---|
| 1396 | end if |
---|
| 1397 | end if |
---|
| 1398 | |
---|
| 1399 | ! Save the spectral fluxes if required |
---|
| 1400 | if (config%do_save_spectral_flux) then |
---|
| 1401 | call indexed_sum(sum(flux_up_above(:,:),2), & |
---|
| 1402 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1403 | & flux%sw_up_band(:,jcol,1)) |
---|
| 1404 | call indexed_sum(sum(direct_dn_below(:,:),2), & |
---|
| 1405 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1406 | & flux%sw_dn_band(:,jcol,1)) |
---|
| 1407 | flux%sw_dn_band(:,jcol,1) = mu0 * flux%sw_dn_band(:,jcol,1) |
---|
| 1408 | if (allocated(flux%sw_dn_direct_band)) then |
---|
| 1409 | flux%sw_dn_direct_band(:,jcol,1) = flux%sw_dn_band(:,jcol,1) |
---|
| 1410 | end if |
---|
| 1411 | if (config%do_clear) then |
---|
| 1412 | flux%sw_dn_clear_band(:,jcol,1) = flux%sw_dn_band(:,jcol,1) |
---|
| 1413 | call indexed_sum(flux_up_clear, & |
---|
| 1414 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1415 | & flux%sw_up_clear_band(:,jcol,1)) |
---|
| 1416 | if (allocated(flux%sw_dn_direct_clear_band)) then |
---|
| 1417 | flux%sw_dn_direct_clear_band(:,jcol,1) & |
---|
| 1418 | & = flux%sw_dn_clear_band(:,jcol,1) |
---|
| 1419 | end if |
---|
| 1420 | end if |
---|
| 1421 | end if |
---|
| 1422 | |
---|
| 1423 | ! Final loop back down through the atmosphere to compute fluxes |
---|
| 1424 | do jlev = 1,nlev |
---|
| 1425 | |
---|
| 1426 | #ifdef PRINT_ENTRAPMENT_DATA |
---|
| 1427 | if (config%i_3d_sw_entrapment == IEntrapmentExplicitNonFractal & |
---|
| 1428 | & .or. config%i_3d_sw_entrapment == IEntrapmentExplicit) then |
---|
| 1429 | ! Save downwelling direct and diffuse fluxes at the top of |
---|
| 1430 | ! layer "jlev" in each of the regions of layer "jlev" |
---|
| 1431 | if (nreg == 2) then |
---|
| 1432 | write(102,'(i4,i4,4e14.6)') jcol, jlev, direct_dn_below(1,:), flux_dn_below(1,:) |
---|
| 1433 | else |
---|
| 1434 | write(102,'(i4,i4,6e14.6)') jcol, jlev, direct_dn_below(1,1:3), flux_dn_below(1,1:3) |
---|
| 1435 | end if |
---|
| 1436 | end if |
---|
| 1437 | #endif |
---|
| 1438 | |
---|
| 1439 | ! Compute the solar downwelling "source" at the base of the |
---|
| 1440 | ! layer due to scattering of the direct beam within it |
---|
| 1441 | if (config%do_clear) then |
---|
| 1442 | source_dn_clear = trans_dir_diff_clear(:,jlev)*direct_dn_clear |
---|
| 1443 | end if |
---|
| 1444 | source_dn(:,:) = mat_x_vec(ng,ng,nreg,trans_dir_diff(:,:,:,jlev),direct_dn_below, & |
---|
| 1445 | & is_clear_sky_layer(jlev)) |
---|
| 1446 | |
---|
| 1447 | ! Compute direct downwelling flux in each region at base of |
---|
| 1448 | ! current layer |
---|
| 1449 | if (config%do_clear) then |
---|
| 1450 | direct_dn_clear = trans_dir_dir_clear(:,jlev)*direct_dn_clear |
---|
| 1451 | end if |
---|
| 1452 | direct_dn_above = mat_x_vec(ng,ng,nreg,trans_dir_dir(:,:,:,jlev),direct_dn_below, & |
---|
| 1453 | & is_clear_sky_layer(jlev)) |
---|
| 1454 | |
---|
| 1455 | ! Integrate downwelling direct flux across spectrum and |
---|
| 1456 | ! regions, and store (the diffuse part will be added later) |
---|
| 1457 | flux%sw_dn(jcol,jlev+1) = mu0 * sum(sum(direct_dn_above,1)) |
---|
| 1458 | if (allocated(flux%sw_dn_direct)) then |
---|
| 1459 | flux%sw_dn_direct(jcol,jlev+1) = flux%sw_dn(jcol,jlev+1) |
---|
| 1460 | end if |
---|
| 1461 | if (config%do_clear) then |
---|
| 1462 | flux%sw_dn_clear(jcol,jlev+1) = mu0 * sum(direct_dn_clear) |
---|
| 1463 | if (allocated(flux%sw_dn_direct_clear)) then |
---|
| 1464 | flux%sw_dn_direct_clear(jcol,jlev+1) & |
---|
| 1465 | & = flux%sw_dn_clear(jcol,jlev+1) |
---|
| 1466 | end if |
---|
| 1467 | end if |
---|
| 1468 | |
---|
| 1469 | if (config%do_save_spectral_flux) then |
---|
| 1470 | call indexed_sum(sum(direct_dn_above,2), & |
---|
| 1471 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1472 | & flux%sw_dn_band(:,jcol,jlev+1)) |
---|
| 1473 | flux%sw_dn_band(:,jcol,jlev+1) = mu0 * flux%sw_dn_band(:,jcol,jlev+1) |
---|
| 1474 | |
---|
| 1475 | if (allocated(flux%sw_dn_direct_band)) then |
---|
| 1476 | flux%sw_dn_direct_band(:,jcol,jlev+1) & |
---|
| 1477 | & = flux%sw_dn_band(:,jcol,jlev+1) |
---|
| 1478 | end if |
---|
| 1479 | if (config%do_clear) then |
---|
| 1480 | call indexed_sum(direct_dn_clear, & |
---|
| 1481 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1482 | & flux%sw_dn_clear_band(:,jcol,jlev+1)) |
---|
| 1483 | flux%sw_dn_clear_band(:,jcol,jlev+1) = mu0 & |
---|
| 1484 | & * flux%sw_dn_clear_band(:,jcol,jlev+1) |
---|
| 1485 | if (allocated(flux%sw_dn_direct_clear_band)) then |
---|
| 1486 | flux%sw_dn_direct_clear_band(:,jcol,jlev+1) & |
---|
| 1487 | & = flux%sw_dn_clear_band(:,jcol,jlev+1) |
---|
| 1488 | end if |
---|
| 1489 | end if |
---|
| 1490 | end if |
---|
| 1491 | |
---|
| 1492 | if (config%do_clear) then |
---|
| 1493 | ! Scalar operations for clear-sky fluxes |
---|
| 1494 | flux_dn_clear(:) = (trans_clear(:,jlev)*flux_dn_clear(:) & |
---|
| 1495 | & + ref_clear(:,jlev)*total_albedo_clear_direct(:,jlev+1)*direct_dn_clear & |
---|
| 1496 | & + source_dn_clear) & |
---|
| 1497 | & / (1.0_jprb - ref_clear(:,jlev)*total_albedo_clear(:,jlev+1)) |
---|
| 1498 | flux_up_clear(:) = total_albedo_clear_direct(:,jlev+1)*direct_dn_clear & |
---|
| 1499 | & + total_albedo_clear(:,jlev+1)*flux_dn_clear |
---|
| 1500 | end if |
---|
| 1501 | |
---|
| 1502 | if (is_clear_sky_layer(jlev)) then |
---|
| 1503 | ! Scalar operations for clear-sky layer |
---|
| 1504 | flux_dn_above(:,1) = (transmittance(:,1,1,jlev)*flux_dn_below(:,1) & |
---|
| 1505 | & + reflectance(:,1,1,jlev)*total_albedo_direct(:,1,1,jlev+1)*direct_dn_above(:,1) & |
---|
| 1506 | & + source_dn(:,1)) & |
---|
| 1507 | & / (1.0_jprb - reflectance(:,1,1,jlev)*total_albedo(:,1,1,jlev+1)) |
---|
| 1508 | flux_dn_above(:,2:nreg) = 0.0_jprb |
---|
| 1509 | flux_up_above(:,1) = total_albedo_direct(:,1,1,jlev+1)*direct_dn_above(:,1) & |
---|
| 1510 | & + total_albedo(:,1,1,jlev+1)*flux_dn_above(:,1) |
---|
| 1511 | flux_up_above(:,2:nreg) = 0.0_jprb |
---|
| 1512 | else |
---|
| 1513 | ! Matrix operations for cloudy layer |
---|
| 1514 | denominator = identity_minus_mat_x_mat(ng,ng,nreg,reflectance(:,:,:,jlev), & |
---|
| 1515 | & total_albedo(:,:,:,jlev+1)) |
---|
| 1516 | total_source = mat_x_vec(ng,ng,nreg,total_albedo_direct(:,:,:,jlev+1),direct_dn_above) |
---|
| 1517 | |
---|
| 1518 | flux_dn_above = solve_vec(ng,ng,nreg,denominator, & |
---|
| 1519 | & mat_x_vec(ng,ng,nreg,transmittance(:,:,:,jlev),flux_dn_below) & |
---|
| 1520 | & + mat_x_vec(ng,ng,nreg,reflectance(:,:,:,jlev), total_source(:,:)) & |
---|
| 1521 | & + source_dn(:,:)) |
---|
| 1522 | flux_up_above = mat_x_vec(ng,ng,nreg,total_albedo(:,:,:,jlev+1), & |
---|
| 1523 | & flux_dn_above) + total_source(:,:) |
---|
| 1524 | end if |
---|
| 1525 | |
---|
| 1526 | ! Account for overlap rules in translating fluxes just above |
---|
| 1527 | ! a layer interface to the values just below |
---|
| 1528 | if (is_clear_sky_layer(jlev) .and. is_clear_sky_layer(jlev+1)) then |
---|
| 1529 | ! Regions in current layer map directly on to regions in |
---|
| 1530 | ! layer below |
---|
| 1531 | flux_dn_below = flux_dn_above |
---|
| 1532 | direct_dn_below = direct_dn_above |
---|
| 1533 | else |
---|
| 1534 | ! Apply downward overlap matrix to compute direct |
---|
| 1535 | ! downwelling flux entering the top of each region in the |
---|
| 1536 | ! layer below |
---|
| 1537 | flux_dn_below = singlemat_x_vec(ng,ng,nreg,v_matrix(:,:,jlev+1,jcol), & |
---|
| 1538 | & flux_dn_above) |
---|
| 1539 | direct_dn_below = singlemat_x_vec(ng,ng,nreg,v_matrix(:,:,jlev+1,jcol), & |
---|
| 1540 | & direct_dn_above) |
---|
| 1541 | end if |
---|
| 1542 | |
---|
| 1543 | ! Store the broadband fluxes |
---|
| 1544 | flux%sw_up(jcol,jlev+1) = sum(sum(flux_up_above,1)) |
---|
| 1545 | flux%sw_dn(jcol,jlev+1) & |
---|
| 1546 | & = flux%sw_dn(jcol,jlev+1) + sum(sum(flux_dn_above,1)) |
---|
| 1547 | if (config%do_clear) then |
---|
| 1548 | flux%sw_up_clear(jcol,jlev+1) = sum(flux_up_clear) |
---|
| 1549 | flux%sw_dn_clear(jcol,jlev+1) & |
---|
| 1550 | & = flux%sw_dn_clear(jcol,jlev+1) + sum(flux_dn_clear) |
---|
| 1551 | end if |
---|
| 1552 | |
---|
| 1553 | ! Save the spectral fluxes if required |
---|
| 1554 | if (config%do_save_spectral_flux) then |
---|
| 1555 | call indexed_sum(sum(flux_up_above,2), & |
---|
| 1556 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1557 | & flux%sw_up_band(:,jcol,jlev+1)) |
---|
| 1558 | call add_indexed_sum(sum(flux_dn_above,2), & |
---|
| 1559 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1560 | & flux%sw_dn_band(:,jcol,jlev+1)) |
---|
| 1561 | if (config%do_clear) then |
---|
| 1562 | call indexed_sum(flux_up_clear, & |
---|
| 1563 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1564 | & flux%sw_up_clear_band(:,jcol,jlev+1)) |
---|
| 1565 | call add_indexed_sum(flux_dn_clear, & |
---|
| 1566 | & config%i_spec_from_reordered_g_sw, & |
---|
| 1567 | & flux%sw_dn_clear_band(:,jcol,jlev+1)) |
---|
| 1568 | end if |
---|
| 1569 | end if |
---|
| 1570 | |
---|
| 1571 | end do ! Final loop over levels |
---|
| 1572 | |
---|
| 1573 | ! Store surface spectral fluxes, if required (after the end of |
---|
| 1574 | ! the final loop over levels, the current values of these arrays |
---|
| 1575 | ! will be the surface values) |
---|
| 1576 | flux%sw_dn_diffuse_surf_g(:,jcol) = sum(flux_dn_above,2) |
---|
| 1577 | flux%sw_dn_direct_surf_g(:,jcol) = mu0 * sum(direct_dn_above,2) |
---|
| 1578 | if (config%do_clear) then |
---|
| 1579 | flux%sw_dn_diffuse_surf_clear_g(:,jcol) = flux_dn_clear |
---|
| 1580 | flux%sw_dn_direct_surf_clear_g(:,jcol) = mu0 * direct_dn_clear |
---|
| 1581 | end if |
---|
| 1582 | |
---|
| 1583 | end do ! Loop over columns |
---|
| 1584 | if (config%iverbose >= 3) then |
---|
| 1585 | write(nulout,*) |
---|
| 1586 | end if |
---|
| 1587 | |
---|
| 1588 | ! Report number of calls to each method of solving single-layer |
---|
| 1589 | ! two-stream equations |
---|
| 1590 | if (config%iverbose >= 4) then |
---|
| 1591 | write(nulout,'(a,i0)') ' Matrix-exponential calls: ', n_calls_expm |
---|
| 1592 | write(nulout,'(a,i0)') ' Meador-Weaver calls: ', n_calls_meador_weaver |
---|
| 1593 | end if |
---|
| 1594 | |
---|
| 1595 | if (lhook) call dr_hook('radiation_spartacus_sw:solver_spartacus_sw',1,hook_handle) |
---|
| 1596 | |
---|
| 1597 | end subroutine solver_spartacus_sw |
---|
| 1598 | |
---|
| 1599 | |
---|
| 1600 | ! Step the horizontal migration distances from the base of a layer |
---|
| 1601 | ! to the top, accounting for the extra distance travelled within the |
---|
| 1602 | ! layer |
---|
| 1603 | subroutine step_migrations(ng, nreg, cloud_frac, & |
---|
| 1604 | & layer_depth, tan_diffuse_angle_3d, tan_sza, & |
---|
| 1605 | & reflectance, transmittance, ref_dir, trans_dir_dir, & |
---|
| 1606 | & trans_dir_diff, total_albedo_diff, total_albedo_dir, & |
---|
| 1607 | & x_diffuse, x_direct) |
---|
| 1608 | |
---|
| 1609 | use parkind1, only : jprb |
---|
| 1610 | |
---|
| 1611 | implicit none |
---|
| 1612 | |
---|
| 1613 | ! Inputs |
---|
| 1614 | |
---|
| 1615 | ! Number of g points and regions |
---|
| 1616 | integer, intent(in) :: ng, nreg |
---|
| 1617 | ! Cloud fraction |
---|
| 1618 | real(jprb), intent(in) :: cloud_frac |
---|
| 1619 | ! Layer depth (m), tangent of diffuse zenith angle and tangent of |
---|
| 1620 | ! solar zenith angle |
---|
| 1621 | real(jprb), intent(in) :: layer_depth, tan_diffuse_angle_3d, tan_sza |
---|
| 1622 | ! Reflectance and transmittance to diffuse downwelling radiation |
---|
| 1623 | real(jprb), intent(in), dimension(ng, nreg, nreg) :: reflectance, transmittance |
---|
| 1624 | ! Reflectance and transmittance to direct downwelling radiation |
---|
| 1625 | real(jprb), intent(in), dimension(ng, nreg, nreg) :: ref_dir, trans_dir_dir |
---|
| 1626 | ! Transmittance involving direct entering a layer from the top and |
---|
| 1627 | ! diffuse leaving from the bottom |
---|
| 1628 | real(jprb), intent(in), dimension(ng, nreg, nreg) :: trans_dir_diff |
---|
| 1629 | |
---|
| 1630 | ! Total albedo of direct and diffuse radiation of the atmosphere |
---|
| 1631 | ! below the layer in question |
---|
| 1632 | real(jprb), intent(in), dimension(ng, nreg, nreg) & |
---|
| 1633 | & :: total_albedo_diff, total_albedo_dir |
---|
| 1634 | |
---|
| 1635 | ! Inputs/outputs |
---|
| 1636 | |
---|
| 1637 | ! Horizontal migration distance (m) of reflected light |
---|
| 1638 | real(jprb), intent(inout), dimension(ng, nreg) :: x_diffuse, x_direct |
---|
| 1639 | |
---|
| 1640 | ! Local variables |
---|
| 1641 | |
---|
| 1642 | ! Top albedo, i.e. the albedo of the top of the layer assuming no |
---|
| 1643 | ! lateral transport |
---|
| 1644 | real(jprb), dimension(ng) :: top_albedo |
---|
| 1645 | |
---|
| 1646 | ! Multiple-scattering amplitude enhancement |
---|
| 1647 | real(jprb), dimension(ng) :: ms_enhancement |
---|
| 1648 | |
---|
| 1649 | ! Multiple-scattering distance enhancement |
---|
| 1650 | real(jprb), dimension(ng) :: x_enhancement |
---|
| 1651 | |
---|
| 1652 | |
---|
| 1653 | real(jprb) :: x_layer_diffuse, x_layer_direct |
---|
| 1654 | integer :: jreg, istartreg, iendreg |
---|
| 1655 | |
---|
| 1656 | istartreg = 1 |
---|
| 1657 | iendreg = nreg |
---|
| 1658 | |
---|
| 1659 | if (cloud_frac <= 0.0_jprb) then |
---|
| 1660 | ! Clear-sky layer: don't waste time on cloudy regions |
---|
| 1661 | iendreg = 1 |
---|
| 1662 | else if (cloud_frac >= 1.0_jprb) then |
---|
| 1663 | ! Overcast layer: don't waste time on clear region |
---|
| 1664 | istartreg = 2 |
---|
| 1665 | end if |
---|
| 1666 | |
---|
| 1667 | ! This is the mean horizontal distance travelled by diffuse |
---|
| 1668 | ! radiation that travels from the top of a layer to the centre and |
---|
| 1669 | ! is then scattered back up and out |
---|
| 1670 | x_layer_diffuse = layer_depth * tan_diffuse_angle_3d/sqrt(2.0_jprb) |
---|
| 1671 | |
---|
| 1672 | ! This is the mean horizontal distance travelled by direct |
---|
| 1673 | ! radiation that travels from the top of a layer to the centre and |
---|
| 1674 | ! is then scattered back up and out |
---|
| 1675 | x_layer_direct = layer_depth * sqrt(tan_sza*tan_sza & |
---|
| 1676 | & + tan_diffuse_angle_3d*tan_diffuse_angle_3d) * 0.5_jprb |
---|
| 1677 | |
---|
| 1678 | do jreg = istartreg,iendreg |
---|
| 1679 | ! Geometric series enhancement due to multiple scattering: the |
---|
| 1680 | ! amplitude enhancement is equal to the limit of |
---|
| 1681 | ! T*[1+RA+(RA)^2+(RA)^3+...] |
---|
| 1682 | ms_enhancement = transmittance(:,jreg,jreg) & |
---|
| 1683 | & / (1.0_jprb - reflectance(:,jreg,jreg)*total_albedo_diff(:,jreg,jreg)) |
---|
| 1684 | ! ...and the distance enhancement is approximately equal to the |
---|
| 1685 | ! limit of T*[1+sqrt(2)*RA+sqrt(3)*(RA)^2+sqrt(4)*(RA)^3+...] |
---|
| 1686 | x_enhancement = (1.0_jprb - reflectance(:,jreg,jreg)*total_albedo_diff(:,jreg,jreg))**(-1.5_jprb) |
---|
| 1687 | |
---|
| 1688 | ! Horizontal migration of direct downwelling radiation |
---|
| 1689 | top_albedo = max(1.0e-8_jprb, ref_dir(:,jreg,jreg) + ms_enhancement & |
---|
| 1690 | & * (trans_dir_diff(:,jreg,jreg)*total_albedo_diff(:,jreg,jreg) & |
---|
| 1691 | & +trans_dir_dir(:,jreg,jreg)*total_albedo_dir(:,jreg,jreg))) |
---|
| 1692 | ! The following is approximate and has been found to |
---|
| 1693 | ! occasionally go negative |
---|
| 1694 | x_direct(:,jreg) = max(0.0_jprb, x_layer_direct & |
---|
| 1695 | & + ((trans_dir_diff(:,jreg,jreg)*total_albedo_diff(:,jreg,jreg)*x_enhancement & |
---|
| 1696 | & +trans_dir_dir(:,jreg,jreg)*total_albedo_dir(:,jreg,jreg)*(x_enhancement-1.0_jprb)) & |
---|
| 1697 | & *(x_diffuse(:,jreg)+x_layer_diffuse) & |
---|
| 1698 | & +trans_dir_dir(:,jreg,jreg)*total_albedo_dir(:,jreg,jreg) & |
---|
| 1699 | & *(x_direct(:,jreg)+x_layer_direct)) & |
---|
| 1700 | & * transmittance(:,jreg,jreg) / top_albedo) |
---|
| 1701 | |
---|
| 1702 | ! Horizontal migration of diffuse downwelling radiation |
---|
| 1703 | top_albedo = max(1.0e-8_jprb, reflectance(:,jreg,jreg) & |
---|
| 1704 | & + ms_enhancement*transmittance(:,jreg,jreg)*total_albedo_diff(:,jreg,jreg)) |
---|
| 1705 | x_diffuse(:,jreg) = x_layer_diffuse + x_enhancement*total_albedo_diff(:,jreg,jreg) & |
---|
| 1706 | & *(transmittance(:,jreg,jreg)*transmittance(:,jreg,jreg)) & |
---|
| 1707 | & * (x_diffuse(:,jreg) + x_layer_diffuse) / top_albedo |
---|
| 1708 | |
---|
| 1709 | end do |
---|
| 1710 | if (iendreg < nreg) then |
---|
| 1711 | x_diffuse(:,iendreg+1:nreg) = 0.0_jprb |
---|
| 1712 | x_direct(:,iendreg+1:nreg) = 0.0_jprb |
---|
| 1713 | else if (istartreg == 2) then |
---|
| 1714 | x_diffuse(:,1) = 0.0_jprb |
---|
| 1715 | x_direct(:,1) = 0.0_jprb |
---|
| 1716 | end if |
---|
| 1717 | |
---|
| 1718 | end subroutine step_migrations |
---|
| 1719 | |
---|
| 1720 | end module radiation_spartacus_sw |
---|