!> @file radiation_model_mod.f90
!--------------------------------------------------------------------------------------------------!
! This file is part of the PALM model system.
!
! PALM is free software: you can redistribute it and/or modify it under the terms of the GNU General
! Public License as published by the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! PALM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
! implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
! Public License for more details.
!
! You should have received a copy of the GNU General Public License along with PALM. If not, see
! .
!
! Copyright 2015-2021 Institute of Computer Science of the Czech Academy of Sciences, Prague
! Copyright 2015-2021 Czech Technical University in Prague
! Copyright 1997-2021 Leibniz Universitaet Hannover
!--------------------------------------------------------------------------------------------------!
!
!
! Description:
! ------------
!> Radiation models and interfaces:
!> Constant, simple and RRTMG models, interface to external radiation model
!> Radiative Transfer Model (RTM) version 3.0 for modelling of radiation
!> Interactions within urban canopy or other surface layer in complex terrain
!> Integrations of RTM with other PALM-4U modules:
!> Integration with RRTMG, USM, LSM, PCM, BIO modules
!>
!> @todo Move variable definitions used in radiation_init only to the subroutine as they are no
!> longer required after initialization.
!> @todo Output of full column vertical profiles used in RRTMG
!> @todo Output of other rrtm arrays (such as volume mixing ratios)
!> @todo Optimize radiation_tendency routines
!>
!> @note Many variables have a leading dummy dimension (0:0) in order to match the assume-size shape
!> expected by the RRTMG model.
!--------------------------------------------------------------------------------------------------!
MODULE radiation_model_mod
#if defined( __parallel )
USE MPI
#endif
USE arrays_3d, &
ONLY: dzw, &
d_exner, &
exner, &
hyp, &
nc, &
pt, &
p, &
q, &
ql, &
u, &
v, &
w, &
zu, &
zw
USE basic_constants_and_equations_mod, &
ONLY: barometric_formula, &
c_p, &
g, &
lv_d_cp, &
l_v, &
pi, &
r_d, &
rho_l, &
solar_constant, &
sigma_sb
USE calc_mean_profile_mod, &
ONLY: calc_mean_profile
USE control_parameters, &
ONLY: biometeorology, &
cloud_droplets, &
coupling_char, &
debug_output, &
debug_output_timestep, &
debug_string, &
dt_3d, &
dz, &
dt_spinup, &
end_time, &
humidity, &
include_total_domain_boundaries, &
initializing_actions, &
io_blocks, &
io_group, &
land_surface, &
large_scale_forcing, &
latitude, &
longitude, &
lsf_surf, &
message_string, &
plant_canopy, &
pt_surface, &
read_svf, &
restart_data_format_input, &
restart_data_format_output, &
rho_surface, &
simulated_time, &
spinup_time, &
surface_pressure, &
time_since_reference_point, &
urban_surface, &
varnamelength, &
write_svf
USE cpulog, &
ONLY: cpu_log, &
log_point, &
log_point_s
USE grid_variables, &
ONLY: ddx, &
ddy, &
dx, &
dy
USE indices, &
ONLY: nnx, &
nny, &
nx, &
nxl, &
nxl_pe, &
nxlg, &
nxr, &
nxr_pe, &
nxrg, &
nx_on_file, &
ny, &
nyn, &
nyn_pe, &
nyng, &
nys, &
nys_pe, &
nysg, &
ny_on_file, &
nzb, &
nzt, &
topo_top_ind, &
topo_flags
USE, INTRINSIC :: iso_c_binding
USE kinds
USE bulk_cloud_model_mod, &
ONLY: bulk_cloud_model, &
microphysics_morrison, &
na_init, &
nc_const, &
sigma_gc
#if defined ( __netcdf )
USE NETCDF
#endif
USE netcdf_data_input_mod, &
ONLY: albedo_type_f, &
albedo_pars_f, &
building_type_f, &
building_surface_pars_f, &
char_fill, &
char_lod, &
check_existence, &
close_input_file, &
get_attribute, &
get_dimension_length, &
get_variable, &
inquire_num_variables, &
inquire_variable_names, &
input_file_dynamic, &
input_pids_dynamic, &
num_var_pids, &
pavement_type_f, &
pids_id, &
open_read_file, &
real_1d_3d, &
vars_pids, &
vegetation_type_f, &
water_type_f
USE palm_date_time_mod, &
ONLY: date_time_str_len, &
get_date_time, &
hours_per_day, &
seconds_per_hour
USE plant_canopy_model_mod, &
ONLY: lad_s, &
pcm_heating_rate, &
pcm_transpiration_rate, &
pcm_latent_rate, &
plant_canopy_transpiration, &
pcm_calc_transpiration_rate
USE pegrid
#if defined ( __rrtmg )
USE parrrsw, &
ONLY: naerec, &
nbndsw
USE parrrtm, &
ONLY: nbndlw
USE rrtmg_lw_init, &
ONLY: rrtmg_lw_ini
USE rrtmg_sw_init, &
ONLY: rrtmg_sw_ini
USE rrtmg_lw_rad, &
ONLY: rrtmg_lw
USE rrtmg_sw_rad, &
ONLY: rrtmg_sw
#endif
USE restart_data_mpi_io_mod, &
ONLY: rd_mpi_io_check_array, &
rrd_mpi_io, &
wrd_mpi_io, &
rd_mpi_io_open, &
rd_mpi_io_surface_filetypes, &
rrd_mpi_io_surface, &
wrd_mpi_io_surface, &
rd_mpi_io_close, &
tgh
USE statistics, &
ONLY: hom
USE surface_mod, &
ONLY: ind_pav_green, &
ind_veg_wall, &
ind_wat_win, &
surf_def_h, &
surf_lsm_h, &
surf_lsm_v, &
surf_type, &
surf_usm_h, &
surf_usm_v, &
vertical_surfaces_exist
IMPLICIT NONE
CHARACTER(10) :: radiation_scheme = 'clear-sky' !< 'constant', 'clear-sky', or 'rrtmg'
!
!-- Predefined Land surface classes (albedo_type) after Briegleb (1992)
CHARACTER(37), DIMENSION(0:42), PARAMETER :: albedo_type_name = (/ &
'user defined ', & ! 0
'ocean ', & ! 1
'mixed farming, tall grassland ', & ! 2
'tall/medium grassland ', & ! 3
'evergreen shrubland ', & ! 4
'short grassland/meadow/shrubland ', & ! 5
'evergreen needleleaf forest ', & ! 6
'mixed deciduous evergreen forest ', & ! 7
'deciduous forest ', & ! 8
'tropical evergreen broadleaved forest', & ! 9
'medium/tall grassland/woodland ', & ! 10
'desert, sandy ', & ! 11
'desert, rocky ', & ! 12
'tundra ', & ! 13
'land ice ', & ! 14
'sea ice ', & ! 15
'snow ', & ! 16
'bare soil ', & ! 17
'asphalt/concrete mix ', & ! 18
'asphalt (asphalt concrete) ', & ! 19
'concrete (Portland concrete) ', & ! 20
'sett ', & ! 21
'paving stones ', & ! 22
'cobblestone ', & ! 23
'metal ', & ! 24
'wood ', & ! 25
'gravel ', & ! 26
'fine gravel ', & ! 27
'pebblestone ', & ! 28
'woodchips ', & ! 29
'tartan (sports) ', & ! 30
'artifical turf (sports) ', & ! 31
'clay (sports) ', & ! 32
'building (dummy) ', & ! 33
'building wall - reflecting facade ', & ! 34
'building wall - bright facade ', & ! 35
'building wall - other materials ', & ! 36
'building window - double glazing ', & ! 37
'building window - double glazing ', & ! 38
'building window - reflecting ', & ! 39
'building roof - reflecting ', & ! 40
'building roof - bright ', & ! 41
'building roof - other materials ' & ! 42
/)
!
!-- Indices of radiation-related input attributes in building_surface_pars
!-- (other are in urban_surface_mod)
INTEGER(iwp), PARAMETER :: ind_s_alb_b_wall = 19 !< index for Broadband albedo of wall fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_l_wall = 20 !< index for Longwave albedo of wall fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_s_wall = 21 !< index for Shortwave albedo of wall fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_b_win = 22 !< index for Broadband albedo of window fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_l_win = 23 !< index for Longwave albedo of window fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_s_win = 24 !< index for Shortwave albedo of window fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_b_green = 24 !< index for Broadband albedo of green fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_l_green = 25 !< index for Longwave albedo of green fraction
INTEGER(iwp), PARAMETER :: ind_s_alb_s_green = 26 !< index for Shortwave albedo of green fraction
INTEGER(iwp) :: albedo_type = 9999999_iwp, & !< Albedo surface type
dots_rad = 0_iwp !< starting index for timeseries output
INTEGER(iwp) :: day_of_year !< day of the current year
LOGICAL :: unscheduled_radiation_calls = .FALSE., & !< flag parameter indicating whether additional calls
!< of the radiation code are allowed
constant_albedo = .FALSE., & !< flag parameter indicating whether the albedo may
!< change depending on zenith
force_radiation_call = .FALSE., & !< flag parameter for unscheduled radiation calls
lw_radiation = .TRUE., & !< flag parameter indicating whether longwave radiation shall be calculated
radiation = .FALSE., & !< flag parameter indicating whether the radiation model is used
sun_up = .TRUE., & !< flag parameter indicating whether the sun is up or down
sw_radiation = .TRUE., & !< flag parameter indicating whether shortwave
!< radiation shall be calculated
sun_direction = .FALSE., & !< flag parameter indicating whether solar direction shall be calculated
average_radiation = .FALSE., & !< flag to set the calculation of radiation averaging for the domain
radiation_interactions = .FALSE., & !< flag to activiate RTM (TRUE only if vertical
!< urban/land surface and trees exist)
surface_reflections = .TRUE., & !< flag to switch the calculation of radiation
! This subroutine controls the calls of the radiation schemes
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_control
IMPLICIT NONE
IF ( debug_output_timestep ) CALL debug_message( 'radiation_control', 'start' )
SELECT CASE ( TRIM( radiation_scheme ) )
CASE ( 'constant' )
CALL radiation_constant
CASE ( 'clear-sky' )
CALL radiation_clearsky
CASE ( 'rrtmg' )
CALL radiation_rrtmg
CASE ( 'external' )
!
!-- During spinup apply clear-sky model
IF ( time_since_reference_point < 0.0_wp ) THEN
CALL radiation_clearsky
ELSE
CALL radiation_external
ENDIF
CASE DEFAULT
END SELECT
IF ( debug_output_timestep ) CALL debug_message( 'radiation_control', 'end' )
END SUBROUTINE radiation_control
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Check data output for radiation model
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_check_data_output( variable, unit, i, ilen, k )
USE control_parameters, &
ONLY: data_output, &
message_string
IMPLICIT NONE
CHARACTER(LEN=*) :: unit !<
CHARACTER(LEN=*) :: variable !<
CHARACTER(LEN=varnamelength) :: var !< TRIM(variable)
INTEGER(iwp) :: i, k !<
INTEGER(iwp) :: ilast_word !<
INTEGER(iwp) :: ilen !<
INTEGER(iwp) :: id !<
LOGICAL :: directional !<
var = TRIM( variable )
!
!-- Identify directional variables
ilast_word = SCAN( var, '_', back = .TRUE. )
directional = .FALSE.
IF ( ilast_word > 0 ) THEN
DO id = 0, nd-1
IF ( TRIM( var(ilast_word:) ) == TRIM( dirname(id) ) ) THEN
directional = .TRUE.
var = var(1:ilast_word-1)
EXIT
ENDIF
ENDDO
ENDIF
IF ( directional ) THEN
IF ( var(1:8) == 'rtm_svf_' .OR. var(1:8) == 'rtm_dif_' ) THEN
IF ( .NOT. radiation ) THEN
message_string = 'output of "' // var // '" requires radiation = .TRUE.'
CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 )
ENDIF
unit = '1'
ELSE
SELECT CASE ( TRIM( var ) )
CASE ( 'rtm_rad_net', 'rtm_rad_insw', 'rtm_rad_inlw', 'rtm_rad_inswdir', &
'rtm_rad_inswdif', 'rtm_rad_inswref', 'rtm_rad_inlwdif', 'rtm_rad_inlwref', &
'rtm_rad_outsw', 'rtm_rad_outlw', 'rtm_rad_ressw', 'rtm_rad_reslw' )
IF ( .NOT. radiation ) THEN
message_string = 'output of "' // var // '" requires radiation = .TRUE.'
CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 )
ENDIF
unit = 'W/m2'
CASE ( 'rtm_skyvf', 'rtm_skyvft', 'rtm_surfalb', 'rtm_surfemis' )
IF ( .NOT. radiation ) THEN
message_string = 'output of "' // var // '" requires radiation = .TRUE.'
CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 )
ENDIF
unit = '1'
CASE DEFAULT
unit = 'illegal'
END SELECT
ENDIF
ELSE
SELECT CASE ( var )
CASE ( 'rad_lw_cs_hr', 'rad_lw_hr', 'rad_sw_cs_hr', 'rad_sw_hr' )
IF ( .NOT. radiation .OR. radiation_scheme /= 'rrtmg' ) THEN
message_string = '"output of "' // var // '" requires radiation = .TRUE. and ' // &
'radiation_scheme = "rrtmg"'
CALL message( 'check_parameters', 'PA0406', 1, 2, 0, 6, 0 )
ENDIF
unit = 'K/h'
CASE ( 'rad_lw_in', 'rad_lw_out', 'rad_sw_in', 'rad_sw_out' )
IF ( .NOT. radiation .OR. radiation_scheme /= 'rrtmg' ) THEN
message_string = '"output of "' // var // '" requires radiation = .TRUE. and ' // &
'radiation_scheme = "rrtmg"'
CALL message( 'check_parameters', 'PA0406', 1, 2, 0, 6, 0 )
ENDIF
unit = 'W/m2'
CASE ( 'rad_net*', 'rad_lw_in*', 'rad_lw_out*', 'rad_sw_in*', 'rad_sw_out*' )
IF ( k == 0 .OR. data_output(i)(ilen-2:ilen) /= '_xy' ) THEN
message_string = 'illegal value for data_output: "' // var // &
'" & only 2d-horizontal cross sections are allowed for this value'
CALL message( 'check_parameters', 'PA0111', 1, 2, 0, 6, 0 )
ENDIF
unit = 'W/m2'
CASE ( 'rrtm_aldif*', 'rrtm_aldir*', 'rrtm_asdif*', 'rrtm_asdir*' )
IF ( k == 0 .OR. data_output(i)(ilen-2:ilen) /= '_xy' ) THEN
message_string = 'illegal value for data_output: "' // var // &
'" & only 2d-horizontal cross sections are allowed for this value'
CALL message( 'check_parameters', 'PA0111', 1, 2, 0, 6, 0 )
ENDIF
IF ( .NOT. radiation .OR. radiation_scheme /= "rrtmg" ) THEN
message_string = 'output of "' // var // '" requires radiation = .TRUE. and ' // &
'radiation_scheme = "rrtmg"'
CALL message( 'check_parameters', 'PA0409', 1, 2, 0, 6, 0 )
ENDIF
unit = ''
CASE ( 'rtm_rad_pc_inlw', 'rtm_rad_pc_insw', 'rtm_rad_pc_inswdir', 'rtm_rad_pc_inswdif', &
'rtm_rad_pc_inswref' )
IF ( .NOT. radiation ) THEN
message_string = 'output of "' // var // '" requires radiation = .TRUE.'
CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 )
ENDIF
unit = 'W'
CASE ( 'rtm_mrt', 'rtm_mrt_sw', 'rtm_mrt_lw' )
IF ( .NOT. radiation ) THEN
message_string = 'output of "' // var // '" requires radiation = .TRUE.'
CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 )
ENDIF
IF ( mrt_nlevels == 0 ) THEN
message_string = 'output of "' // var // '" requires mrt_nlevels > 0'
CALL message( 'check_parameters', 'PA0510', 1, 2, 0, 6, 0 )
ENDIF
IF ( var == 'rtm_mrt_sw' .AND. .NOT. mrt_include_sw ) THEN
message_string = 'output of "' // var // '" requires rtm_mrt_sw = .TRUE.'
CALL message( 'check_parameters', 'PA0511', 1, 2, 0, 6, 0 )
ENDIF
IF ( var == 'rtm_mrt' ) THEN
unit = 'K'
ELSE
unit = 'W m-2'
ENDIF
CASE DEFAULT
unit = 'illegal'
END SELECT
END IF
END SUBROUTINE radiation_check_data_output
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Set module-specific timeseries units and labels
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_check_data_output_ts( dots_max, dots_num )
INTEGER(iwp),INTENT(IN) :: dots_max !<
INTEGER(iwp),INTENT(INOUT) :: dots_num !<
!
!-- Next line is just to avoid compiler warning about unused variable.
IF ( dots_max == 0 ) CONTINUE
!
!-- Temporary solution to add LSM and radiation time series to the default output
IF ( land_surface .OR. radiation ) THEN
IF ( TRIM( radiation_scheme ) == 'rrtmg' ) THEN
dots_num = dots_num + 15
ELSE
dots_num = dots_num + 11
ENDIF
ENDIF
END SUBROUTINE radiation_check_data_output_ts
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Check data output of profiles for radiation model
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_check_data_output_pr( variable, var_count, unit, dopr_unit )
USE arrays_3d, &
ONLY: zu
USE control_parameters, &
ONLY: data_output_pr, &
message_string
USE indices
USE profil_parameter
USE statistics
IMPLICIT NONE
CHARACTER(LEN=*) :: dopr_unit !< local value of dopr_unit
CHARACTER(LEN=*) :: unit !<
CHARACTER(LEN=*) :: variable !<
INTEGER(iwp) :: var_count !<
SELECT CASE ( TRIM( variable ) )
CASE ( 'rad_net' )
IF ( ( .NOT. radiation ) .OR. radiation_scheme == 'constant' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme = "constant"'
CALL message( 'check_parameters', 'PA0408', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 99
dopr_unit = 'W/m2'
hom(:,2,99,:) = SPREAD( zw, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_lw_in' )
IF ( ( .NOT. radiation) .OR. radiation_scheme == 'constant' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme = "constant"'
CALL message( 'check_parameters', 'PA0408', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 100
dopr_unit = 'W/m2'
hom(:,2,100,:) = SPREAD( zw, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_lw_out' )
IF ( ( .NOT. radiation ) .OR. radiation_scheme == 'constant' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme = "constant"'
CALL message( 'check_parameters', 'PA0408', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 101
dopr_unit = 'W/m2'
hom(:,2,101,:) = SPREAD( zw, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_sw_in' )
IF ( ( .NOT. radiation ) .OR. radiation_scheme == 'constant' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme = "constant"'
CALL message( 'check_parameters', 'PA0408', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 102
dopr_unit = 'W/m2'
hom(:,2,102,:) = SPREAD( zw, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_sw_out')
IF ( ( .NOT. radiation ) .OR. radiation_scheme == 'constant' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme = "constant"'
CALL message( 'check_parameters', 'PA0408', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 103
dopr_unit = 'W/m2'
hom(:,2,103,:) = SPREAD( zw, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_lw_cs_hr' )
IF ( ( .NOT. radiation ) .OR. radiation_scheme /= 'rrtmg' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme /= "rrtmg"'
CALL message( 'check_parameters', 'PA0413', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 104
dopr_unit = 'K/h'
hom(:,2,104,:) = SPREAD( zu, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_lw_hr' )
IF ( ( .NOT. radiation ) .OR. radiation_scheme /= 'rrtmg' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme /= "rrtmg"'
CALL message( 'check_parameters', 'PA0413', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 105
dopr_unit = 'K/h'
hom(:,2,105,:) = SPREAD( zu, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_sw_cs_hr' )
IF ( ( .NOT. radiation ) .OR. radiation_scheme /= 'rrtmg' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme /= "rrtmg"'
CALL message( 'check_parameters', 'PA0413', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 106
dopr_unit = 'K/h'
hom(:,2,106,:) = SPREAD( zu, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE ( 'rad_sw_hr' )
IF ( ( .NOT. radiation ) .OR. radiation_scheme /= 'rrtmg' ) THEN
message_string = 'data_output_pr = ' // TRIM( data_output_pr(var_count) ) // ' is' // &
'not available for radiation = .FALSE. or ' // &
'radiation_scheme /= "rrtmg"'
CALL message( 'check_parameters', 'PA0413', 1, 2, 0, 6, 0 )
ELSE
dopr_index(var_count) = 107
dopr_unit = 'K/h'
hom(:,2,107,:) = SPREAD( zu, 2, statistic_regions+1 )
unit = dopr_unit
ENDIF
CASE DEFAULT
unit = 'illegal'
END SELECT
END SUBROUTINE radiation_check_data_output_pr
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Check parameters routine for radiation model
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_check_parameters
USE control_parameters, &
ONLY: land_surface, &
message_string, &
urban_surface
USE netcdf_data_input_mod, &
ONLY: input_pids_static
IMPLICIT NONE
!
!-- In case no urban-surface or land-surface model is applied, usage of a radiation model makes
!-- no sense.
IF ( .NOT. land_surface .AND. .NOT. urban_surface ) THEN
message_string = 'Usage of radiation module is only allowed if ' // &
'land-surface and/or urban-surface model is applied.'
CALL message( 'radiation_check_parameters', 'PA0486', 1, 2, 0, 6, 0 )
ENDIF
IF ( radiation_scheme /= 'constant' .AND. radiation_scheme /= 'clear-sky' .AND. &
radiation_scheme /= 'rrtmg' .AND. radiation_scheme /= 'external' ) THEN
message_string = 'unknown radiation_scheme = '// TRIM( radiation_scheme )
CALL message( 'radiation_check_parameters', 'PA0405', 1, 2, 0, 6, 0 )
ELSEIF ( radiation_scheme == 'rrtmg' ) THEN
#if ! defined ( __rrtmg )
message_string = 'radiation_scheme = "rrtmg" requires compilation of PALM with ' // &
'pre-processor directive -D__rrtmg'
CALL message( 'radiation_check_parameters', 'PA0407', 1, 2, 0, 6, 0 )
#endif
#if defined ( __rrtmg ) && ! defined( __netcdf )
message_string = 'radiation_scheme = "rrtmg" requires the use of NetCDF (preprocessor ' // &
'directive -D__netcdf'
CALL message( 'radiation_check_parameters', 'PA0412', 1, 2, 0, 6, 0 )
#endif
ENDIF
!
!-- Checks performed only if data is given via namelist only.
IF ( .NOT. input_pids_static ) THEN
IF ( albedo_type == 0 .AND. albedo == 9999999.9_wp .AND. &
radiation_scheme == 'clear-sky') THEN
message_string = 'radiation_scheme = "clear-sky" in combination with albedo_type = 0 ' //&
'requires setting of albedo /= 9999999.9'
CALL message( 'radiation_check_parameters', 'PA0410', 1, 2, 0, 6, 0 )
ENDIF
IF ( albedo_type == 0 .AND. radiation_scheme == 'rrtmg' .AND. &
( albedo_lw_dif == 9999999.9_wp .OR. albedo_lw_dir == 9999999.9_wp .OR. &
albedo_sw_dif == 9999999.9_wp .OR. albedo_sw_dir == 9999999.9_wp ) ) THEN
message_string = 'radiation_scheme = "rrtmg" in combination with albedo_type = 0 ' // &
'requires setting of albedo_lw_dif /= 9999999.9' // &
'albedo_lw_dir /= 9999999.9 albedo_sw_dif /= 9999999.9 and' // &
'albedo_sw_dir /= 9999999.9'
CALL message( 'radiation_check_parameters', 'PA0411', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
!
!-- Parallel rad_angular_discretization without raytrace_mpi_rma is not implemented
!-- Serial mode does not allow mpi_rma
#if defined( __parallel )
IF ( rad_angular_discretization .AND. .NOT. raytrace_mpi_rma ) THEN
message_string = 'rad_angular_discretization can only be used together with ' // &
'raytrace_mpi_rma or when no parallelization is applied.'
CALL message( 'radiation_check_parameters', 'PA0745', 1, 2, 0, 6, 0 )
ENDIF
#else
IF ( raytrace_mpi_rma ) THEN
message_string = 'raytrace_mpi_rma = .T. not allowed in serial mode'
CALL message( 'radiation_check_parameters', 'PA0710', 1, 2, 0, 6, 0 )
ENDIF
#endif
IF ( cloud_droplets .AND. radiation_scheme == 'rrtmg' .AND. average_radiation ) THEN
message_string = 'average_radiation = .T. with radiation_scheme = "rrtmg" in ' // &
'combination cloud_droplets = .T. is not implementd'
CALL message( 'radiation_check_parameters', 'PA0746', 1, 2, 0, 6, 0 )
ENDIF
!
!-- Initialize svf normalization reporting histogram
svfnorm_report_num = 1
DO WHILE ( svfnorm_report_thresh(svfnorm_report_num) < 1e20_wp .AND. svfnorm_report_num <= 30 )
svfnorm_report_num = svfnorm_report_num + 1
ENDDO
svfnorm_report_num = svfnorm_report_num - 1
!
!-- Check for dt_radiation
IF ( dt_radiation <= 0.0 ) THEN
message_string = 'dt_radiation must be > 0.0'
CALL message( 'radiation_check_parameters', 'PA0591', 1, 2, 0, 6, 0 )
ENDIF
!
!-- Check for the angular discretization parameters
!-- Error message when too small values are set
IF ( raytrace_discrete_elevs < 4 .OR. raytrace_discrete_azims < 8 ) THEN
message_string = 'Too coarse angular discretization settings: ' // &
'raytrace_discrete_elevs < 4 and/or raytrace_discrete_elevs < 8'
CALL message( 'radiation_check_parameters', 'PA0735', 1, 2, 0, 6, 0 )
ENDIF
!-- Warning message when small values are set
IF ( raytrace_discrete_elevs < 9 .OR. raytrace_discrete_azims < 18 ) THEN
message_string = 'Relatively coarse angular discretization settings are set: ' // &
'raytrace_discrete_elevs < 9 and/or raytrace_discrete_elevs < 18'
CALL message( 'radiation_check_parameters', 'PA0747', 0, 1, 0, 6, 0 )
ENDIF
END SUBROUTINE radiation_check_parameters
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Initialization of the radiation model and Radiative Transfer Model
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_init
#if defined( __rrtmg )
USE control_parameters, &
ONLY: run_identifier
#endif
USE control_parameters, &
ONLY: bc_lr_cyc, &
bc_ns_cyc
IMPLICIT NONE
INTEGER(iwp) :: i !< running index x-direction
INTEGER(iwp) :: is !< running index for input surface elements
INTEGER(iwp) :: ioff !< offset in x between surface element reference grid point in atmosphere and actual surface
INTEGER(iwp) :: j !< running index y-direction
INTEGER(iwp) :: joff !< offset in y between surface element reference grid point in atmosphere and actual surface
INTEGER(iwp) :: k !< running index z-direction
INTEGER(iwp) :: l !< running index for orientation of vertical surfaces
INTEGER(iwp) :: m !< running index for surface elements
INTEGER(iwp) :: ntime = 0 !< number of available external radiation timesteps
#if defined( __rrtmg )
INTEGER(iwp) :: ind_type !< running index for subgrid-surface tiles
#endif
LOGICAL :: radiation_input_root_domain !< flag indicating the existence of a dynamic input file for the root domain
IF ( debug_output ) CALL debug_message( 'radiation_init', 'start' )
!
!-- Activate radiation_interactions according to the existence of vertical surfaces and/or trees
! or if biometeorology output is required for flat surfaces.
!-- The namelist parameter radiation_interactions_on can override this behavior (this check cannot
!-- be performed in check_parameters, because vertical_surfaces_exist is first set in
!-- init_surface_arrays).
IF ( radiation_interactions_on ) THEN
IF ( vertical_surfaces_exist .OR. plant_canopy .OR. biometeorology ) THEN
radiation_interactions = .TRUE.
average_radiation = .TRUE.
ELSE
radiation_interactions_on = .FALSE. !< Reset namelist parameter: no interactions
!< Calculations necessary in case of flat surface
ENDIF
ELSEIF ( vertical_surfaces_exist .OR. plant_canopy .OR. biometeorology ) THEN
message_string = 'radiation_interactions_on is set to .FALSE. although vertical ' // &
'surfaces and/or trees or biometeorology exist is ON. The model will ' // &
'run without RTM (no shadows, no radiation reflections)'
CALL message( 'radiation_init', 'PA0348', 0, 1, 0, 6, 0 )
ENDIF
!
!-- Warning message when cyclic boundary conditions are set
IF ( radiation_interactions .AND. ( bc_lr_cyc .OR. bc_ns_cyc ) ) THEN
message_string = 'The current raytracing algorithm in the Radiative Transfer Model does' // &
' NOT support explicitly cyclic boundary conditions. Surface radiation' // &
' fluxes near the boundaries should be evaluated in this view point'
CALL message( 'radiation_init', 'PA0659', 0, 1, 0, 6, 0 )
ENDIF
!
!-- Precalculate some time constants
d_hours_day = 1.0_wp / REAL( hours_per_day, KIND = wp )
d_seconds_hour = 1.0_wp / seconds_per_hour
!
!-- If required, initialize radiation interactions between surfaces via sky-view factors. This must
!-- be done before radiation is initialized.
IF ( radiation_interactions ) CALL radiation_interaction_init
!
!-- Allocate array for storing the surface net radiation
DO l = 0, 1
IF ( .NOT. ALLOCATED( surf_lsm_h(l)%rad_net ) .AND. surf_lsm_h(l)%ns > 0 ) THEN
ALLOCATE( surf_lsm_h(l)%rad_net(1:surf_lsm_h(l)%ns) )
surf_lsm_h(l)%rad_net = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( surf_usm_h(l)%rad_net ) .AND. surf_usm_h(l)%ns > 0 ) THEN
ALLOCATE( surf_usm_h(l)%rad_net(1:surf_usm_h(l)%ns) )
surf_usm_h(l)%rad_net = 0.0_wp
ENDIF
ENDDO
DO l = 0, 3
IF ( .NOT. ALLOCATED( surf_lsm_v(l)%rad_net ) .AND. surf_lsm_v(l)%ns > 0 ) THEN
ALLOCATE( surf_lsm_v(l)%rad_net(1:surf_lsm_v(l)%ns) )
surf_lsm_v(l)%rad_net = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( surf_usm_v(l)%rad_net ) .AND. surf_usm_v(l)%ns > 0 ) THEN
ALLOCATE( surf_usm_v(l)%rad_net(1:surf_usm_v(l)%ns) )
surf_usm_v(l)%rad_net = 0.0_wp
ENDIF
ENDDO
!
!-- Allocate array for storing the surface longwave (out) radiation change
DO l = 0, 1
IF ( .NOT. ALLOCATED( surf_lsm_h(l)%rad_lw_out_change_0 ) .AND. &
surf_lsm_h(l)%ns > 0 ) THEN
ALLOCATE( surf_lsm_h(l)%rad_lw_out_change_0(1:surf_lsm_h(l)%ns) )
surf_lsm_h(l)%rad_lw_out_change_0 = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( surf_usm_h(l)%rad_lw_out_change_0 ) .AND. &
surf_usm_h(l)%ns > 0 ) THEN
ALLOCATE( surf_usm_h(l)%rad_lw_out_change_0(1:surf_usm_h(l)%ns) )
surf_usm_h(l)%rad_lw_out_change_0 = 0.0_wp
ENDIF
ENDDO
DO l = 0, 3
IF ( .NOT. ALLOCATED( surf_lsm_v(l)%rad_lw_out_change_0 ) .AND. &
surf_lsm_v(l)%ns > 0 ) THEN
ALLOCATE( surf_lsm_v(l)%rad_lw_out_change_0(1:surf_lsm_v(l)%ns) )
surf_lsm_v(l)%rad_lw_out_change_0 = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( surf_usm_v(l)%rad_lw_out_change_0 ) .AND. &
surf_usm_v(l)%ns > 0 ) THEN
ALLOCATE( surf_usm_v(l)%rad_lw_out_change_0(1:surf_usm_v(l)%ns) )
surf_usm_v(l)%rad_lw_out_change_0 = 0.0_wp
ENDIF
ENDDO
!
!-- Allocate surface arrays for incoming/outgoing short/longwave radiation
DO l = 0, 1
IF ( .NOT. ALLOCATED( surf_lsm_h(l)%rad_sw_in ) .AND. surf_lsm_h(l)%ns > 0 ) THEN
ALLOCATE( surf_lsm_h(l)%rad_sw_in(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_sw_out(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_sw_dir(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_sw_dif(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_sw_ref(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_sw_res(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_lw_in(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_lw_out(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_lw_dif(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_lw_ref(1:surf_lsm_h(l)%ns) )
ALLOCATE( surf_lsm_h(l)%rad_lw_res(1:surf_lsm_h(l)%ns) )
surf_lsm_h(l)%rad_sw_in = 0.0_wp
surf_lsm_h(l)%rad_sw_out = 0.0_wp
surf_lsm_h(l)%rad_sw_dir = 0.0_wp
surf_lsm_h(l)%rad_sw_dif = 0.0_wp
surf_lsm_h(l)%rad_sw_ref = 0.0_wp
surf_lsm_h(l)%rad_sw_res = 0.0_wp
surf_lsm_h(l)%rad_lw_in = 0.0_wp
surf_lsm_h(l)%rad_lw_out = 0.0_wp
surf_lsm_h(l)%rad_lw_dif = 0.0_wp
surf_lsm_h(l)%rad_lw_ref = 0.0_wp
surf_lsm_h(l)%rad_lw_res = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( surf_usm_h(l)%rad_sw_in ) .AND. surf_usm_h(l)%ns > 0 ) THEN
ALLOCATE( surf_usm_h(l)%rad_sw_in(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_sw_out(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_sw_dir(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_sw_dif(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_sw_ref(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_sw_res(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_lw_in(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_lw_out(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_lw_dif(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_lw_ref(1:surf_usm_h(l)%ns) )
ALLOCATE( surf_usm_h(l)%rad_lw_res(1:surf_usm_h(l)%ns) )
surf_usm_h(l)%rad_sw_in = 0.0_wp
surf_usm_h(l)%rad_sw_out = 0.0_wp
surf_usm_h(l)%rad_sw_dir = 0.0_wp
surf_usm_h(l)%rad_sw_dif = 0.0_wp
surf_usm_h(l)%rad_sw_ref = 0.0_wp
surf_usm_h(l)%rad_sw_res = 0.0_wp
surf_usm_h(l)%rad_lw_in = 0.0_wp
surf_usm_h(l)%rad_lw_out = 0.0_wp
surf_usm_h(l)%rad_lw_dif = 0.0_wp
surf_usm_h(l)%rad_lw_ref = 0.0_wp
surf_usm_h(l)%rad_lw_res = 0.0_wp
ENDIF
ENDDO
DO l = 0, 3
IF ( .NOT. ALLOCATED( surf_lsm_v(l)%rad_sw_in ) .AND. surf_lsm_v(l)%ns > 0 ) THEN
ALLOCATE( surf_lsm_v(l)%rad_sw_in(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_sw_out(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_sw_dir(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_sw_dif(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_sw_ref(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_sw_res(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_lw_in(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_lw_out(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_lw_dif(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_lw_ref(1:surf_lsm_v(l)%ns) )
ALLOCATE( surf_lsm_v(l)%rad_lw_res(1:surf_lsm_v(l)%ns) )
surf_lsm_v(l)%rad_sw_in = 0.0_wp
surf_lsm_v(l)%rad_sw_out = 0.0_wp
surf_lsm_v(l)%rad_sw_dir = 0.0_wp
surf_lsm_v(l)%rad_sw_dif = 0.0_wp
surf_lsm_v(l)%rad_sw_ref = 0.0_wp
surf_lsm_v(l)%rad_sw_res = 0.0_wp
surf_lsm_v(l)%rad_lw_in = 0.0_wp
surf_lsm_v(l)%rad_lw_out = 0.0_wp
surf_lsm_v(l)%rad_lw_dif = 0.0_wp
surf_lsm_v(l)%rad_lw_ref = 0.0_wp
surf_lsm_v(l)%rad_lw_res = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( surf_usm_v(l)%rad_sw_in ) .AND. surf_usm_v(l)%ns > 0 ) THEN
ALLOCATE( surf_usm_v(l)%rad_sw_in(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_sw_out(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_sw_dir(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_sw_dif(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_sw_ref(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_sw_res(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_lw_in(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_lw_out(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_lw_dif(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_lw_ref(1:surf_usm_v(l)%ns) )
ALLOCATE( surf_usm_v(l)%rad_lw_res(1:surf_usm_v(l)%ns) )
surf_usm_v(l)%rad_sw_in = 0.0_wp
surf_usm_v(l)%rad_sw_out = 0.0_wp
surf_usm_v(l)%rad_sw_dir = 0.0_wp
surf_usm_v(l)%rad_sw_dif = 0.0_wp
surf_usm_v(l)%rad_sw_ref = 0.0_wp
surf_usm_v(l)%rad_sw_res = 0.0_wp
surf_usm_v(l)%rad_lw_in = 0.0_wp
surf_usm_v(l)%rad_lw_out = 0.0_wp
surf_usm_v(l)%rad_lw_dif = 0.0_wp
surf_usm_v(l)%rad_lw_ref = 0.0_wp
surf_usm_v(l)%rad_lw_res = 0.0_wp
ENDIF
ENDDO
!
!-- Fix net radiation in case of radiation_scheme = 'constant'
IF ( radiation_scheme == 'constant' ) THEN
DO l = 0, 1
IF ( ALLOCATED( surf_lsm_h(l)%rad_net ) ) surf_lsm_h(l)%rad_net = net_radiation
IF ( ALLOCATED( surf_usm_h(l)%rad_net ) ) surf_usm_h(l)%rad_net = net_radiation
ENDDO
!
!-- @Todo: weight with inclination angle
DO l = 0, 3
IF ( ALLOCATED( surf_lsm_v(l)%rad_net ) ) surf_lsm_v(l)%rad_net = net_radiation
IF ( ALLOCATED( surf_usm_v(l)%rad_net ) ) surf_usm_v(l)%rad_net = net_radiation
ENDDO
! radiation = .FALSE.
!
!-- Calculate orbital constants
ELSE
decl_1 = SIN( 23.45_wp * pi / 180.0_wp )
decl_2 = 2.0_wp * pi / 365.0_wp
decl_3 = decl_2 * 81.0_wp
lat = latitude * pi / 180.0_wp
lon = longitude * pi / 180.0_wp
ENDIF
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
!
!-- Allocate arrays for incoming/outgoing short/longwave radiation
IF ( .NOT. ALLOCATED( rad_sw_in ) ) THEN
ALLOCATE( rad_sw_in(0:0,nysg:nyng,nxlg:nxrg) )
rad_sw_in = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_out ) ) THEN
ALLOCATE( rad_sw_out(0:0,nysg:nyng,nxlg:nxrg) )
rad_sw_out = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_in ) ) THEN
ALLOCATE( rad_lw_in(0:0,nysg:nyng,nxlg:nxrg) )
rad_lw_in = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_out ) ) THEN
ALLOCATE( rad_lw_out(0:0,nysg:nyng,nxlg:nxrg) )
rad_lw_out = 0.0_wp
ENDIF
!
!-- Allocate average arrays for incoming/outgoing short/longwave radiation
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) THEN
ALLOCATE( rad_sw_in_av(0:0,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) THEN
ALLOCATE( rad_sw_out_av(0:0,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) THEN
ALLOCATE( rad_lw_in_av(0:0,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) THEN
ALLOCATE( rad_lw_out_av(0:0,nysg:nyng,nxlg:nxrg) )
ENDIF
!
!-- Allocate arrays for broadband albedo, and level 1 initialization via namelist paramter,
!-- unless not already allocated.
DO l = 0, 1
IF ( .NOT. ALLOCATED(surf_lsm_h(l)%albedo) ) THEN
ALLOCATE( surf_lsm_h(l)%albedo(1:surf_lsm_h(l)%ns,0:2) )
surf_lsm_h(l)%albedo = albedo
ENDIF
IF ( .NOT. ALLOCATED(surf_usm_h(l)%albedo) ) THEN
ALLOCATE( surf_usm_h(l)%albedo(1:surf_usm_h(l)%ns,0:2) )
surf_usm_h(l)%albedo = albedo
ENDIF
ENDDO
DO l = 0, 3
IF ( .NOT. ALLOCATED( surf_lsm_v(l)%albedo ) ) THEN
ALLOCATE( surf_lsm_v(l)%albedo(1:surf_lsm_v(l)%ns,0:2) )
surf_lsm_v(l)%albedo = albedo
ENDIF
IF ( .NOT. ALLOCATED( surf_usm_v(l)%albedo ) ) THEN
ALLOCATE( surf_usm_v(l)%albedo(1:surf_usm_v(l)%ns,0:2) )
surf_usm_v(l)%albedo = albedo
ENDIF
ENDDO
!
!-- Level 2 initialization of broadband albedo via given albedo_type.
!-- Only if albedo_type is non-zero. In case of urban surface and input data is read from ASCII
!-- file, albedo_type will be zero, so that albedo won't be overwritten.
DO l = 0, 1
DO m = 1, surf_lsm_h(l)%ns
IF ( surf_lsm_h(l)%albedo_type(m,ind_veg_wall) /= 0 ) &
surf_lsm_h(l)%albedo(m,ind_veg_wall) = &
albedo_pars(0,surf_lsm_h(l)%albedo_type(m,ind_veg_wall))
IF ( surf_lsm_h(l)%albedo_type(m,ind_pav_green) /= 0 ) &
surf_lsm_h(l)%albedo(m,ind_pav_green) = &
albedo_pars(0,surf_lsm_h(l)%albedo_type(m,ind_pav_green))
IF ( surf_lsm_h(l)%albedo_type(m,ind_wat_win) /= 0 ) &
surf_lsm_h(l)%albedo(m,ind_wat_win) = &
albedo_pars(0,surf_lsm_h(l)%albedo_type(m,ind_wat_win))
ENDDO
DO m = 1, surf_usm_h(l)%ns
IF ( surf_usm_h(l)%albedo_type(m,ind_veg_wall) /= 0 ) &
surf_usm_h(l)%albedo(m,ind_veg_wall) = &
albedo_pars(0,surf_usm_h(l)%albedo_type(m,ind_veg_wall))
IF ( surf_usm_h(l)%albedo_type(m,ind_pav_green) /= 0 ) &
surf_usm_h(l)%albedo(m,ind_pav_green) = &
albedo_pars(0,surf_usm_h(l)%albedo_type(m,ind_pav_green))
IF ( surf_usm_h(l)%albedo_type(m,ind_wat_win) /= 0 ) &
surf_usm_h(l)%albedo(m,ind_wat_win) = &
albedo_pars(0,surf_usm_h(l)%albedo_type(m,ind_wat_win))
ENDDO
ENDDO
DO l = 0, 3
DO m = 1, surf_lsm_v(l)%ns
IF ( surf_lsm_v(l)%albedo_type(m,ind_veg_wall) /= 0 ) &
surf_lsm_v(l)%albedo(m,ind_veg_wall) = &
albedo_pars(0,surf_lsm_v(l)%albedo_type(m,ind_veg_wall))
IF ( surf_lsm_v(l)%albedo_type(m,ind_pav_green) /= 0 ) &
surf_lsm_v(l)%albedo(m,ind_pav_green) = &
albedo_pars(0,surf_lsm_v(l)%albedo_type(m,ind_pav_green))
IF ( surf_lsm_v(l)%albedo_type(m,ind_wat_win) /= 0 ) &
surf_lsm_v(l)%albedo(m,ind_wat_win) = &
albedo_pars(0,surf_lsm_v(l)%albedo_type(m,ind_wat_win))
ENDDO
DO m = 1, surf_usm_v(l)%ns
IF ( surf_usm_v(l)%albedo_type(m,ind_veg_wall) /= 0 ) &
surf_usm_v(l)%albedo(m,ind_veg_wall) = &
albedo_pars(0,surf_usm_v(l)%albedo_type(m,ind_veg_wall))
IF ( surf_usm_v(l)%albedo_type(m,ind_pav_green) /= 0 ) &
surf_usm_v(l)%albedo(m,ind_pav_green) = &
albedo_pars(0,surf_usm_v(l)%albedo_type(m,ind_pav_green))
IF ( surf_usm_v(l)%albedo_type(m,ind_wat_win) /= 0 ) &
surf_usm_v(l)%albedo(m,ind_wat_win) = &
albedo_pars(0,surf_usm_v(l)%albedo_type(m,ind_wat_win))
ENDDO
ENDDO
!
!-- Level 3 initialization at grid points where albedo type is zero.
!-- In this case, albedo is taken from file. In case of constant radiation or clear sky, only
!-- broadband albedo is given.
IF ( albedo_pars_f%from_file ) THEN
!
!-- Horizontal surfaces
DO l = 0, 1
DO m = 1, surf_lsm_h(l)%ns
i = surf_lsm_h(l)%i(m)
j = surf_lsm_h(l)%j(m)
IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) THEN
surf_lsm_h(l)%albedo(m,ind_veg_wall) = albedo_pars_f%pars_xy(0,j,i)
surf_lsm_h(l)%albedo(m,ind_pav_green) = albedo_pars_f%pars_xy(0,j,i)
surf_lsm_h(l)%albedo(m,ind_wat_win) = albedo_pars_f%pars_xy(0,j,i)
ENDIF
ENDDO
DO m = 1, surf_usm_h(l)%ns
i = surf_usm_h(l)%i(m)
j = surf_usm_h(l)%j(m)
IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_h(l)%albedo(m,ind_veg_wall) = albedo_pars_f%pars_xy(0,j,i)
surf_usm_h(l)%albedo(m,ind_pav_green) = albedo_pars_f%pars_xy(0,j,i)
surf_usm_h(l)%albedo(m,ind_wat_win) = albedo_pars_f%pars_xy(0,j,i)
ENDIF
ENDDO
ENDDO
!
!-- Vertical surfaces
DO l = 0, 3
ioff = surf_lsm_v(l)%ioff
joff = surf_lsm_v(l)%joff
DO m = 1, surf_lsm_v(l)%ns
i = surf_lsm_v(l)%i(m) + ioff
j = surf_lsm_v(l)%j(m) + joff
IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) THEN
surf_lsm_v(l)%albedo(m,ind_veg_wall) = albedo_pars_f%pars_xy(0,j,i)
surf_lsm_v(l)%albedo(m,ind_pav_green) = albedo_pars_f%pars_xy(0,j,i)
surf_lsm_v(l)%albedo(m,ind_wat_win) = albedo_pars_f%pars_xy(0,j,i)
ENDIF
ENDDO
ioff = surf_usm_v(l)%ioff
joff = surf_usm_v(l)%joff
DO m = 1, surf_usm_v(l)%ns
i = surf_usm_v(l)%i(m) + ioff
j = surf_usm_v(l)%j(m) + joff
IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_v(l)%albedo(m,ind_veg_wall) = albedo_pars_f%pars_xy(0,j,i)
surf_usm_v(l)%albedo(m,ind_pav_green) = albedo_pars_f%pars_xy(0,j,i)
surf_usm_v(l)%albedo(m,ind_wat_win) = albedo_pars_f%pars_xy(0,j,i)
ENDIF
ENDDO
ENDDO
ENDIF
!
!-- Read explicit albedo values from building surface pars. If present, they override all less
!-- specific albedo values and force an albedo_type to zero in order to take effect.
IF ( building_surface_pars_f%from_file ) THEN
DO l = 0, 1
DO m = 1, surf_usm_h(l)%ns
i = surf_usm_h(l)%i(m)
j = surf_usm_h(l)%j(m)
k = surf_usm_h(l)%k(m)
!
!-- Iterate over surfaces in column, check height and orientation
DO is = building_surface_pars_f%index_ji(1,j,i), &
building_surface_pars_f%index_ji(2,j,i)
IF ( building_surface_pars_f%coords(4,is) == -surf_usm_h(l)%koff .AND. &
building_surface_pars_f%coords(1,is) == k ) THEN
IF ( building_surface_pars_f%pars(ind_s_alb_b_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%albedo(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_b_wall,is)
surf_usm_h(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%albedo(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_b_win,is)
surf_usm_h(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%albedo(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_b_green,is)
surf_usm_h(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
EXIT ! Surface was found and processed
ENDIF
ENDDO
ENDDO
ENDDO
DO l = 0, 3
DO m = 1, surf_usm_v(l)%ns
i = surf_usm_v(l)%i(m)
j = surf_usm_v(l)%j(m)
k = surf_usm_v(l)%k(m)
!
!-- Iterate over surfaces in column, check height and orientation
DO is = building_surface_pars_f%index_ji(1,j,i), &
building_surface_pars_f%index_ji(2,j,i)
IF ( building_surface_pars_f%coords(5,is) == -surf_usm_v(l)%joff .AND. &
building_surface_pars_f%coords(6,is) == -surf_usm_v(l)%ioff .AND. &
building_surface_pars_f%coords(1,is) == k ) THEN
IF ( building_surface_pars_f%pars(ind_s_alb_b_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%albedo(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_b_wall,is)
surf_usm_v(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%albedo(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_b_win,is)
surf_usm_v(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%albedo(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_b_green,is)
surf_usm_v(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
EXIT ! Surface was found and processed
ENDIF
ENDDO
ENDDO
ENDDO
ENDIF
!
!-- Initialization actions for RRTMG
ELSEIF ( radiation_scheme == 'rrtmg' ) THEN
#if defined ( __rrtmg )
!
!-- Allocate albedos for short/longwave radiation, horizontal surfaces for wall/green/window
!-- (USM) or vegetation/pavement/water surfaces (LSM).
DO l = 0, 1
ALLOCATE( surf_lsm_h(l)%aldif(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_lsm_h(l)%aldir(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_lsm_h(l)%asdif(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_lsm_h(l)%asdir(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_lsm_h(l)%rrtm_aldif(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_lsm_h(l)%rrtm_aldir(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_lsm_h(l)%rrtm_asdif(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_lsm_h(l)%rrtm_asdir(1:surf_lsm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%aldif(1:surf_usm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%aldir(1:surf_usm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%asdif(1:surf_usm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%asdir(1:surf_usm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%rrtm_aldif(1:surf_usm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%rrtm_aldir(1:surf_usm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%rrtm_asdif(1:surf_usm_h(l)%ns,0:2) )
ALLOCATE( surf_usm_h(l)%rrtm_asdir(1:surf_usm_h(l)%ns,0:2) )
!
!-- Allocate broadband albedo (temporary for the current radiation implementations)
IF ( .NOT. ALLOCATED(surf_lsm_h(l)%albedo) ) &
ALLOCATE( surf_lsm_h(l)%albedo(1:surf_lsm_h(l)%ns,0:2) )
IF ( .NOT. ALLOCATED(surf_usm_h(l)%albedo) ) &
ALLOCATE( surf_usm_h(l)%albedo(1:surf_usm_h(l)%ns,0:2) )
ENDDO
!
!-- Allocate albedos for short/longwave radiation, vertical surfaces
DO l = 0, 3
ALLOCATE( surf_lsm_v(l)%aldif(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_lsm_v(l)%aldir(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_lsm_v(l)%asdif(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_lsm_v(l)%asdir(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_lsm_v(l)%rrtm_aldif(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_lsm_v(l)%rrtm_aldir(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_lsm_v(l)%rrtm_asdif(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_lsm_v(l)%rrtm_asdir(1:surf_lsm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%aldif(1:surf_usm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%aldir(1:surf_usm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%asdif(1:surf_usm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%asdir(1:surf_usm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%rrtm_aldif(1:surf_usm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%rrtm_aldir(1:surf_usm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%rrtm_asdif(1:surf_usm_v(l)%ns,0:2) )
ALLOCATE( surf_usm_v(l)%rrtm_asdir(1:surf_usm_v(l)%ns,0:2) )
!
!-- Allocate broadband albedo (temporary for the current radiation implementations)
IF ( .NOT. ALLOCATED( surf_lsm_v(l)%albedo ) ) &
ALLOCATE( surf_lsm_v(l)%albedo(1:surf_lsm_v(l)%ns,0:2) )
IF ( .NOT. ALLOCATED( surf_usm_v(l)%albedo ) ) &
ALLOCATE( surf_usm_v(l)%albedo(1:surf_usm_v(l)%ns,0:2) )
ENDDO
!
!-- Level 1 initialization of spectral albedos via namelist paramters. Please note, in this case
!-- all surface tiles are initialized the same.
DO l = 0, 1
IF ( surf_lsm_h(l)%ns > 0 ) THEN
surf_lsm_h(l)%aldif = albedo_lw_dif
surf_lsm_h(l)%aldir = albedo_lw_dir
surf_lsm_h(l)%asdif = albedo_sw_dif
surf_lsm_h(l)%asdir = albedo_sw_dir
surf_lsm_h(l)%albedo = albedo_sw_dif
ENDIF
IF ( surf_usm_h(l)%ns > 0 ) THEN
IF ( surf_usm_h(l)%albedo_from_ascii ) THEN
surf_usm_h(l)%aldif = surf_usm_h(l)%albedo
surf_usm_h(l)%aldir = surf_usm_h(l)%albedo
surf_usm_h(l)%asdif = surf_usm_h(l)%albedo
surf_usm_h(l)%asdir = surf_usm_h(l)%albedo
ELSE
surf_usm_h(l)%aldif = albedo_lw_dif
surf_usm_h(l)%aldir = albedo_lw_dir
surf_usm_h(l)%asdif = albedo_sw_dif
surf_usm_h(l)%asdir = albedo_sw_dir
surf_usm_h(l)%albedo = albedo_sw_dif
ENDIF
ENDIF
ENDDO
DO l = 0, 3
IF ( surf_lsm_v(l)%ns > 0 ) THEN
surf_lsm_v(l)%aldif = albedo_lw_dif
surf_lsm_v(l)%aldir = albedo_lw_dir
surf_lsm_v(l)%asdif = albedo_sw_dif
surf_lsm_v(l)%asdir = albedo_sw_dir
surf_lsm_v(l)%albedo = albedo_sw_dif
ENDIF
IF ( surf_usm_v(l)%ns > 0 ) THEN
IF ( surf_usm_v(l)%albedo_from_ascii ) THEN
surf_usm_v(l)%aldif = surf_usm_v(l)%albedo
surf_usm_v(l)%aldir = surf_usm_v(l)%albedo
surf_usm_v(l)%asdif = surf_usm_v(l)%albedo
surf_usm_v(l)%asdir = surf_usm_v(l)%albedo
ELSE
surf_usm_v(l)%aldif = albedo_lw_dif
surf_usm_v(l)%aldir = albedo_lw_dir
surf_usm_v(l)%asdif = albedo_sw_dif
surf_usm_v(l)%asdir = albedo_sw_dir
ENDIF
ENDIF
ENDDO
!
!-- Level 2 initialization of spectral albedos via albedo_type.
!-- Please note, for natural- and urban-type surfaces, a tile approach is applied so that the
!-- resulting albedo is calculated via the weighted average of respective surface fractions.
DO l = 0, 1
DO m = 1, surf_lsm_h(l)%ns
!
!-- Spectral albedos for vegetation/pavement/water surfaces
DO ind_type = 0, 2
IF ( surf_lsm_h(l)%albedo_type(m,ind_type) /= 0 ) THEN
surf_lsm_h(l)%aldif(m,ind_type) = &
albedo_pars(1,surf_lsm_h(l)%albedo_type(m,ind_type))
surf_lsm_h(l)%asdif(m,ind_type) = &
albedo_pars(2,surf_lsm_h(l)%albedo_type(m,ind_type))
surf_lsm_h(l)%aldir(m,ind_type) = &
albedo_pars(1,surf_lsm_h(l)%albedo_type(m,ind_type))
surf_lsm_h(l)%asdir(m,ind_type) = &
albedo_pars(2,surf_lsm_h(l)%albedo_type(m,ind_type))
surf_lsm_h(l)%albedo(m,ind_type) = &
albedo_pars(0,surf_lsm_h(l)%albedo_type(m,ind_type))
ENDIF
ENDDO
ENDDO
!
!-- For urban surface only if albedo has not been already initialized in the urban-surface
!-- model via the ASCII file.
IF ( .NOT. surf_usm_h(l)%albedo_from_ascii ) THEN
DO m = 1, surf_usm_h(l)%ns
!
!-- Spectral albedos for wall/green/window surfaces
DO ind_type = 0, 2
IF ( surf_usm_h(l)%albedo_type(m,ind_type) /= 0 ) THEN
surf_usm_h(l)%aldif(m,ind_type) = &
albedo_pars(1,surf_usm_h(l)%albedo_type(m,ind_type))
surf_usm_h(l)%asdif(m,ind_type) = &
albedo_pars(2,surf_usm_h(l)%albedo_type(m,ind_type))
surf_usm_h(l)%aldir(m,ind_type) = &
albedo_pars(1,surf_usm_h(l)%albedo_type(m,ind_type))
surf_usm_h(l)%asdir(m,ind_type) = &
albedo_pars(2,surf_usm_h(l)%albedo_type(m,ind_type))
surf_usm_h(l)%albedo(m,ind_type) = &
albedo_pars(0,surf_usm_h(l)%albedo_type(m,ind_type))
ENDIF
ENDDO
ENDDO
ENDIF
ENDDO
DO l = 0, 3
DO m = 1, surf_lsm_v(l)%ns
!
!-- Spectral albedos for vegetation/pavement/water surfaces
DO ind_type = 0, 2
IF ( surf_lsm_v(l)%albedo_type(m,ind_type) /= 0 ) THEN
surf_lsm_v(l)%aldif(m,ind_type) = &
albedo_pars(1,surf_lsm_v(l)%albedo_type(m,ind_type))
surf_lsm_v(l)%asdif(m,ind_type) = &
albedo_pars(2,surf_lsm_v(l)%albedo_type(m,ind_type))
surf_lsm_v(l)%aldir(m,ind_type) = &
albedo_pars(1,surf_lsm_v(l)%albedo_type(m,ind_type))
surf_lsm_v(l)%asdir(m,ind_type) = &
albedo_pars(2,surf_lsm_v(l)%albedo_type(m,ind_type))
surf_lsm_v(l)%albedo(m,ind_type) = &
albedo_pars(0,surf_lsm_v(l)%albedo_type(m,ind_type))
ENDIF
ENDDO
ENDDO
!
!-- For urban surface only if albedo has not been already initialized in the urban-surface
!-- model via the ASCII file.
IF ( .NOT. surf_usm_v(l)%albedo_from_ascii ) THEN
DO m = 1, surf_usm_v(l)%ns
!
!-- Spectral albedos for wall/green/window surfaces
DO ind_type = 0, 2
IF ( surf_usm_v(l)%albedo_type(m,ind_type) /= 0 ) THEN
surf_usm_v(l)%aldif(m,ind_type) = &
albedo_pars(1,surf_usm_v(l)%albedo_type(m,ind_type))
surf_usm_v(l)%asdif(m,ind_type) = &
albedo_pars(2,surf_usm_v(l)%albedo_type(m,ind_type))
surf_usm_v(l)%aldir(m,ind_type) = &
albedo_pars(1,surf_usm_v(l)%albedo_type(m,ind_type))
surf_usm_v(l)%asdir(m,ind_type) = &
albedo_pars(2,surf_usm_v(l)%albedo_type(m,ind_type))
surf_usm_v(l)%albedo(m,ind_type) = &
albedo_pars(0,surf_usm_v(l)%albedo_type(m,ind_type))
ENDIF
ENDDO
ENDDO
ENDIF
ENDDO
!
!-- Level 3 initialization at grid points where albedo type is zero.
!-- This case, spectral albedos are taken from file if available
IF ( albedo_pars_f%from_file ) THEN
!
!-- Horizontal
DO l = 0, 1
DO m = 1, surf_lsm_h(l)%ns
i = surf_lsm_h(l)%i(m)
j = surf_lsm_h(l)%j(m)
!
!-- Spectral albedos for vegetation/pavement/water surfaces
DO ind_type = 0, 2
IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) &
surf_lsm_h(l)%albedo(m,ind_type) = albedo_pars_f%pars_xy(0,j,i)
IF ( albedo_pars_f%pars_xy(1,j,i) /= albedo_pars_f%fill ) &
surf_lsm_h(l)%aldir(m,ind_type) = albedo_pars_f%pars_xy(1,j,i)
IF ( albedo_pars_f%pars_xy(1,j,i) /= albedo_pars_f%fill ) &
surf_lsm_h(l)%aldif(m,ind_type) = albedo_pars_f%pars_xy(1,j,i)
IF ( albedo_pars_f%pars_xy(2,j,i) /= albedo_pars_f%fill ) &
surf_lsm_h(l)%asdir(m,ind_type) = albedo_pars_f%pars_xy(2,j,i)
IF ( albedo_pars_f%pars_xy(2,j,i) /= albedo_pars_f%fill ) &
surf_lsm_h(l)%asdif(m,ind_type) = albedo_pars_f%pars_xy(2,j,i)
ENDDO
ENDDO
!
!-- For urban surface only if albedo has not been already initialized in the urban-surface
!-- model via the ASCII file.
IF ( .NOT. surf_usm_h(l)%albedo_from_ascii ) THEN
DO m = 1, surf_usm_h(l)%ns
i = surf_usm_h(l)%i(m)
j = surf_usm_h(l)%j(m)
!
!-- Broadband albedos for wall/green/window surfaces
DO ind_type = 0, 2
IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) &
surf_usm_h(l)%albedo(m,ind_type) = albedo_pars_f%pars_xy(0,j,i)
ENDDO
!
!-- Spectral albedos especially for building wall surfaces
IF ( albedo_pars_f%pars_xy(1,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_h(l)%aldir(m,ind_veg_wall) = albedo_pars_f%pars_xy(1,j,i)
surf_usm_h(l)%aldif(m,ind_veg_wall) = albedo_pars_f%pars_xy(1,j,i)
ENDIF
IF ( albedo_pars_f%pars_xy(2,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_h(l)%asdir(m,ind_veg_wall) = albedo_pars_f%pars_xy(2,j,i)
surf_usm_h(l)%asdif(m,ind_veg_wall) = albedo_pars_f%pars_xy(2,j,i)
ENDIF
!
!-- Spectral albedos especially for building green surfaces
IF ( albedo_pars_f%pars_xy(3,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_h(l)%aldir(m,ind_pav_green) = albedo_pars_f%pars_xy(3,j,i)
surf_usm_h(l)%aldif(m,ind_pav_green) = albedo_pars_f%pars_xy(3,j,i)
ENDIF
IF ( albedo_pars_f%pars_xy(4,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_h(l)%asdir(m,ind_pav_green) = albedo_pars_f%pars_xy(4,j,i)
surf_usm_h(l)%asdif(m,ind_pav_green) = albedo_pars_f%pars_xy(4,j,i)
ENDIF
!
!-- Spectral albedos especially for building window surfaces
IF ( albedo_pars_f%pars_xy(5,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_h(l)%aldir(m,ind_wat_win) = albedo_pars_f%pars_xy(5,j,i)
surf_usm_h(l)%aldif(m,ind_wat_win) = albedo_pars_f%pars_xy(5,j,i)
ENDIF
IF ( albedo_pars_f%pars_xy(6,j,i) /= albedo_pars_f%fill ) THEN
surf_usm_h(l)%asdir(m,ind_wat_win) = albedo_pars_f%pars_xy(6,j,i)
surf_usm_h(l)%asdif(m,ind_wat_win) = albedo_pars_f%pars_xy(6,j,i)
ENDIF
ENDDO
ENDIF
ENDDO
!
!-- Vertical
DO l = 0, 3
ioff = surf_lsm_v(l)%ioff
joff = surf_lsm_v(l)%joff
DO m = 1, surf_lsm_v(l)%ns
i = surf_lsm_v(l)%i(m)
j = surf_lsm_v(l)%j(m)
!
!-- Spectral albedos for vegetation/pavement/water surfaces
DO ind_type = 0, 2
IF ( albedo_pars_f%pars_xy(0,j+joff,i+ioff) /= albedo_pars_f%fill ) &
surf_lsm_v(l)%albedo(m,ind_type) = albedo_pars_f%pars_xy(0,j+joff,i+ioff)
IF ( albedo_pars_f%pars_xy(1,j+joff,i+ioff) /= albedo_pars_f%fill ) &
surf_lsm_v(l)%aldir(m,ind_type) = albedo_pars_f%pars_xy(1,j+joff,i+ioff)
IF ( albedo_pars_f%pars_xy(1,j+joff,i+ioff) /= albedo_pars_f%fill ) &
surf_lsm_v(l)%aldif(m,ind_type) = albedo_pars_f%pars_xy(1,j+joff,i+ioff)
IF ( albedo_pars_f%pars_xy(2,j+joff,i+ioff) /= albedo_pars_f%fill ) &
surf_lsm_v(l)%asdir(m,ind_type) = albedo_pars_f%pars_xy(2,j+joff,i+ioff)
IF ( albedo_pars_f%pars_xy(2,j+joff,i+ioff) /= albedo_pars_f%fill ) &
surf_lsm_v(l)%asdif(m,ind_type) = albedo_pars_f%pars_xy(2,j+joff,i+ioff)
ENDDO
ENDDO
!
!-- For urban surface only if albedo has not been already initialized in the urban-surface
!-- model via the ASCII file.
IF ( .NOT. surf_usm_v(l)%albedo_from_ascii ) THEN
ioff = surf_usm_v(l)%ioff
joff = surf_usm_v(l)%joff
DO m = 1, surf_usm_v(l)%ns
i = surf_usm_v(l)%i(m)
j = surf_usm_v(l)%j(m)
!
!-- Broadband albedos for wall/green/window surfaces
DO ind_type = 0, 2
IF ( albedo_pars_f%pars_xy(0,j+joff,i+ioff) /= albedo_pars_f%fill ) &
surf_usm_v(l)%albedo(m,ind_type) = albedo_pars_f%pars_xy(0,j+joff,i+ioff)
ENDDO
!
!-- Spectral albedos especially for building wall surfaces
IF ( albedo_pars_f%pars_xy(1,j+joff,i+ioff) /= albedo_pars_f%fill ) THEN
surf_usm_v(l)%aldir(m,ind_veg_wall) = albedo_pars_f%pars_xy(1,j+joff,i+ioff)
surf_usm_v(l)%aldif(m,ind_veg_wall) = albedo_pars_f%pars_xy(1,j+joff,i+ioff)
ENDIF
IF ( albedo_pars_f%pars_xy(2,j+joff,i+ioff) /= albedo_pars_f%fill ) THEN
surf_usm_v(l)%asdir(m,ind_veg_wall) = albedo_pars_f%pars_xy(2,j+joff,i+ioff)
surf_usm_v(l)%asdif(m,ind_veg_wall) = albedo_pars_f%pars_xy(2,j+joff,i+ioff)
ENDIF
!
!-- Spectral albedos especially for building green surfaces
IF ( albedo_pars_f%pars_xy(3,j+joff,i+ioff) /= albedo_pars_f%fill ) THEN
surf_usm_v(l)%aldir(m,ind_pav_green) = albedo_pars_f%pars_xy(3,j+joff,i+ioff)
surf_usm_v(l)%aldif(m,ind_pav_green) = albedo_pars_f%pars_xy(3,j+joff,i+ioff)
ENDIF
IF ( albedo_pars_f%pars_xy(4,j+joff,i+ioff) /= albedo_pars_f%fill ) THEN
surf_usm_v(l)%asdir(m,ind_pav_green) = albedo_pars_f%pars_xy(4,j+joff,i+ioff)
surf_usm_v(l)%asdif(m,ind_pav_green) = albedo_pars_f%pars_xy(4,j+joff,i+ioff)
ENDIF
!
!-- Spectral albedos especially for building window surfaces
IF ( albedo_pars_f%pars_xy(5,j+joff,i+ioff) /= albedo_pars_f%fill ) THEN
surf_usm_v(l)%aldir(m,ind_wat_win) = albedo_pars_f%pars_xy(5,j+joff,i+ioff)
surf_usm_v(l)%aldif(m,ind_wat_win) = albedo_pars_f%pars_xy(5,j+joff,i+ioff)
ENDIF
IF ( albedo_pars_f%pars_xy(6,j+joff,i+ioff) /= albedo_pars_f%fill ) THEN
surf_usm_v(l)%asdir(m,ind_wat_win) = albedo_pars_f%pars_xy(6,j+joff,i+ioff)
surf_usm_v(l)%asdif(m,ind_wat_win) = albedo_pars_f%pars_xy(6,j+joff,i+ioff)
ENDIF
ENDDO
ENDIF
ENDDO
ENDIF
!
!-- Read explicit albedo values from building surface pars. If present, they override all less
!-- specific albedo values and force an albedo_type to zero in order to take effect.
IF ( building_surface_pars_f%from_file ) THEN
DO l = 0, 1
DO m = 1, surf_usm_h(l)%ns
i = surf_usm_h(l)%i(m)
j = surf_usm_h(l)%j(m)
k = surf_usm_h(l)%k(m)
!
!-- Iterate over surfaces in column, check height and orientation
DO is = building_surface_pars_f%index_ji(1,j,i), &
building_surface_pars_f%index_ji(2,j,i)
IF ( building_surface_pars_f%coords(4,is) == -surf_usm_h(l)%koff .AND. &
building_surface_pars_f%coords(1,is) == k ) THEN
IF ( building_surface_pars_f%pars(ind_s_alb_b_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%albedo(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_b_wall,is)
surf_usm_h(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_l_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%aldir(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_l_wall,is)
surf_usm_h(l)%aldif(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_l_wall,is)
surf_usm_h(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_s_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%asdir(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_s_wall,is)
surf_usm_h(l)%asdif(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_s_wall,is)
surf_usm_h(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%albedo(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_b_win,is)
surf_usm_h(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_l_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%aldir(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_l_win,is)
surf_usm_h(l)%aldif(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_l_win,is)
surf_usm_h(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_s_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%asdir(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_s_win,is)
surf_usm_h(l)%asdif(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_s_win,is)
surf_usm_h(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%albedo(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_b_green,is)
surf_usm_h(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_l_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%aldir(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_l_green,is)
surf_usm_h(l)%aldif(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_l_green,is)
surf_usm_h(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_s_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_h(l)%asdir(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_s_green,is)
surf_usm_h(l)%asdif(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_s_green,is)
surf_usm_h(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
EXIT ! Surface was found and processed
ENDIF
ENDDO
ENDDO
ENDDO
DO l = 0, 3
DO m = 1, surf_usm_v(l)%ns
i = surf_usm_v(l)%i(m)
j = surf_usm_v(l)%j(m)
k = surf_usm_v(l)%k(m)
!
!-- Iterate over surfaces in column, check height and orientation
DO is = building_surface_pars_f%index_ji(1,j,i), &
building_surface_pars_f%index_ji(2,j,i)
IF ( building_surface_pars_f%coords(5,is) == -surf_usm_v(l)%joff .AND. &
building_surface_pars_f%coords(6,is) == -surf_usm_v(l)%ioff .AND. &
building_surface_pars_f%coords(1,is) == k ) THEN
IF ( building_surface_pars_f%pars(ind_s_alb_b_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%albedo(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_b_wall,is)
surf_usm_v(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_l_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%aldir(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_l_wall,is)
surf_usm_v(l)%aldif(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_l_wall,is)
surf_usm_v(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_s_wall,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%asdir(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_s_wall,is)
surf_usm_v(l)%asdif(m,ind_veg_wall) = &
building_surface_pars_f%pars(ind_s_alb_s_wall,is)
surf_usm_v(l)%albedo_type(m,ind_veg_wall) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%albedo(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_b_win,is)
surf_usm_v(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_l_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%aldir(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_l_win,is)
surf_usm_v(l)%aldif(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_l_win,is)
surf_usm_v(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_s_win,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%asdir(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_s_win,is)
surf_usm_v(l)%asdif(m,ind_wat_win) = &
building_surface_pars_f%pars(ind_s_alb_s_win,is)
surf_usm_v(l)%albedo_type(m,ind_wat_win) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_b_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%albedo(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_b_green,is)
surf_usm_v(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_l_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%aldir(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_l_green,is)
surf_usm_v(l)%aldif(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_l_green,is)
surf_usm_v(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
IF ( building_surface_pars_f%pars(ind_s_alb_s_green,is) /= &
building_surface_pars_f%fill ) THEN
surf_usm_v(l)%asdir(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_s_green,is)
surf_usm_v(l)%asdif(m,ind_pav_green) = &
building_surface_pars_f%pars(ind_s_alb_s_green,is)
surf_usm_v(l)%albedo_type(m,ind_pav_green) = 0
ENDIF
EXIT ! Surface was found and processed
ENDIF
ENDDO
ENDDO
ENDDO
ENDIF
!
!-- Calculate initial values of current (cosine of) the zenith angle and whether the sun is up
CALL get_date_time( time_since_reference_point, day_of_year=day_of_year, &
second_of_day=second_of_day )
CALL calc_zenith( day_of_year, second_of_day )
!
!-- Calculate initial surface albedo for different surfaces
IF ( .NOT. constant_albedo ) THEN
#if defined( __netcdf )
!
!-- Horizontally aligned natural and urban surfaces
DO l = 0, 1
CALL calc_albedo( surf_lsm_h(l) )
CALL calc_albedo( surf_usm_h(l) )
ENDDO
!
!-- Vertically aligned natural and urban surfaces
DO l = 0, 3
CALL calc_albedo( surf_lsm_v(l) )
CALL calc_albedo( surf_usm_v(l) )
ENDDO
#endif
ELSE
!
!-- Initialize sun-inclination independent spectral albedos
!-- Horizontal surfaces
DO l = 0, 1
IF ( surf_lsm_h(l)%ns > 0 ) THEN
surf_lsm_h(l)%rrtm_aldir = surf_lsm_h(l)%aldir
surf_lsm_h(l)%rrtm_asdir = surf_lsm_h(l)%asdir
surf_lsm_h(l)%rrtm_aldif = surf_lsm_h(l)%aldif
surf_lsm_h(l)%rrtm_asdif = surf_lsm_h(l)%asdif
ENDIF
IF ( surf_usm_h(l)%ns > 0 ) THEN
surf_usm_h(l)%rrtm_aldir = surf_usm_h(l)%aldir
surf_usm_h(l)%rrtm_asdir = surf_usm_h(l)%asdir
surf_usm_h(l)%rrtm_aldif = surf_usm_h(l)%aldif
surf_usm_h(l)%rrtm_asdif = surf_usm_h(l)%asdif
ENDIF
ENDDO
!
!-- Vertical surfaces
DO l = 0, 3
IF ( surf_lsm_v(l)%ns > 0 ) THEN
surf_lsm_v(l)%rrtm_aldir = surf_lsm_v(l)%aldir
surf_lsm_v(l)%rrtm_asdir = surf_lsm_v(l)%asdir
surf_lsm_v(l)%rrtm_aldif = surf_lsm_v(l)%aldif
surf_lsm_v(l)%rrtm_asdif = surf_lsm_v(l)%asdif
ENDIF
IF ( surf_usm_v(l)%ns > 0 ) THEN
surf_usm_v(l)%rrtm_aldir = surf_usm_v(l)%aldir
surf_usm_v(l)%rrtm_asdir = surf_usm_v(l)%asdir
surf_usm_v(l)%rrtm_aldif = surf_usm_v(l)%aldif
surf_usm_v(l)%rrtm_asdif = surf_usm_v(l)%asdif
ENDIF
ENDDO
ENDIF
!
!-- Allocate 3d arrays of radiative fluxes and heating rates
IF ( .NOT. ALLOCATED( rad_sw_in ) ) THEN
ALLOCATE( rad_sw_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_in = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) THEN
ALLOCATE( rad_sw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_out ) ) THEN
ALLOCATE( rad_sw_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_out = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) THEN
ALLOCATE( rad_sw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_hr ) ) THEN
ALLOCATE( rad_sw_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_hr = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_hr_av ) ) THEN
ALLOCATE( rad_sw_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_hr_av = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_cs_hr ) ) THEN
ALLOCATE( rad_sw_cs_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_cs_hr = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_sw_cs_hr_av ) ) THEN
ALLOCATE( rad_sw_cs_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_cs_hr_av = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_in ) ) THEN
ALLOCATE( rad_lw_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_in = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) THEN
ALLOCATE( rad_lw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_out ) ) THEN
ALLOCATE( rad_lw_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_out = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) THEN
ALLOCATE( rad_lw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_hr ) ) THEN
ALLOCATE( rad_lw_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_hr = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_hr_av ) ) THEN
ALLOCATE( rad_lw_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_hr_av = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_cs_hr ) ) THEN
ALLOCATE( rad_lw_cs_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_cs_hr = 0.0_wp
ENDIF
IF ( .NOT. ALLOCATED( rad_lw_cs_hr_av ) ) THEN
ALLOCATE( rad_lw_cs_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_cs_hr_av = 0.0_wp
ENDIF
ALLOCATE( rad_sw_cs_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ALLOCATE( rad_sw_cs_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_cs_in = 0.0_wp
rad_sw_cs_out = 0.0_wp
ALLOCATE( rad_lw_cs_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ALLOCATE( rad_lw_cs_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_cs_in = 0.0_wp
rad_lw_cs_out = 0.0_wp
!
!-- Allocate 1-element array for surface temperature
!-- (RRTMG anticipates an array as passed argument).
ALLOCATE( rrtm_tsfc(1) )
!
!-- Allocate surface emissivity.
!-- Values will be given directly before calling rrtm_lw.
ALLOCATE( rrtm_emis(0:0,1:nbndlw+1) )
!
!-- Initialize RRTMG, before check if files are existent
INQUIRE( FILE = 'RRTMG_LW', EXIST = lw_exists )
IF ( .NOT. lw_exists ) THEN
message_string = 'Input file RRTMG_LW for rrtmg model missing.& Please provide ' // &
TRIM( run_identifier ) // '_rlw file in the INPUT directory.'
CALL message( 'radiation_init', 'PA0583', 1, 2, 0, 6, 0 )
ENDIF
INQUIRE( FILE = 'RRTMG_SW', EXIST = sw_exists )
IF ( .NOT. sw_exists ) THEN
message_string = 'Input file RRTMG_SW for rrtmg model missing.& Please provide ' // &
TRIM( run_identifier ) // '_rsw file in the INPUT directory.'
CALL message( 'radiation_init', 'PA0584', 1, 2, 0, 6, 0 )
ENDIF
IF ( lw_radiation ) CALL rrtmg_lw_ini ( c_p )
IF ( sw_radiation ) CALL rrtmg_sw_ini ( c_p )
!
!-- Set input files for RRTMG
INQUIRE( FILE = 'RAD_SND_DATA', EXIST = snd_exists )
IF ( .NOT. snd_exists ) THEN
rrtm_input_file = 'RRTMG_LW'
ENDIF
!
!-- Read vertical layers for RRTMG from sounding data
!-- The routine provides nzt_rad, hyp_snd(1:nzt_rad), t_snd(nzt+2:nzt_rad), rrtm_play(1:nzt_rad),
!-- rrtm_plev(1_nzt_rad+1), rrtm_tlay(nzt+2:nzt_rad), rrtm_tlev(nzt+2:nzt_rad+1)
CALL read_sounding_data
!
!-- Read trace gas profiles from file. This routine provides the rrtm_ arrays (1:nzt_rad+1)
CALL read_trace_gas_data
#endif
ENDIF
!
!-- Initializaion actions exclusively required for external radiation forcing
IF ( radiation_scheme == 'external' ) THEN
!
!-- Open the radiation input file. Note, for child domain, a dynamic input file is often not
!-- provided. In order to not need to duplicate the dynamic input file just for the radiation
!-- input, take it from the dynamic file for the parent if not available for the child domain(s).
!-- In this case this is possible because radiation input should be the same for each model.
INQUIRE( FILE = TRIM( input_file_dynamic ), EXIST = radiation_input_root_domain )
IF ( .NOT. input_pids_dynamic .AND. .NOT. radiation_input_root_domain ) THEN
message_string = 'In case of external radiation forcing a dynamic input file is ' // &
'required. If no dynamic input for the child domain(s) is ' // &
'provided, at least one for the root domain is needed.'
CALL message( 'radiation_init', 'PA0315', 1, 2, 0, 6, 0 )
ENDIF
#if defined( __netcdf )
!
!-- Open dynamic input file for child domain if available, else, open dynamic input file for the
!-- root domain.
IF ( input_pids_dynamic ) THEN
CALL open_read_file( TRIM( input_file_dynamic ) // TRIM( coupling_char ), pids_id )
ELSEIF ( radiation_input_root_domain ) THEN
CALL open_read_file( TRIM( input_file_dynamic ), pids_id )
ENDIF
CALL inquire_num_variables( pids_id, num_var_pids )
!
!-- Allocate memory to store variable names and read them
ALLOCATE( vars_pids(1:num_var_pids) )
CALL inquire_variable_names( pids_id, vars_pids )
!
!-- Input time dimension.
IF ( check_existence( vars_pids, 'time_rad' ) ) THEN
CALL get_dimension_length( pids_id, ntime, 'time_rad' )
ALLOCATE( time_rad_f%var1d(0:ntime-1) )
!
!-- Read variable
CALL get_variable( pids_id, 'time_rad', time_rad_f%var1d )
time_rad_f%from_file = .TRUE.
ENDIF
!
!-- Input shortwave downwelling.
IF ( check_existence( vars_pids, 'rad_sw_in' ) ) THEN
!
!-- Get _FillValue attribute
CALL get_attribute( pids_id, char_fill, rad_sw_in_f%fill, .FALSE., 'rad_sw_in' )
!
!-- Get level-of-detail
CALL get_attribute( pids_id, char_lod, rad_sw_in_f%lod, .FALSE., 'rad_sw_in' )
!
!-- Level-of-detail 1 - radiation depends only on time_rad
IF ( rad_sw_in_f%lod == 1 ) THEN
ALLOCATE( rad_sw_in_f%var1d(0:ntime-1) )
CALL get_variable( pids_id, 'rad_sw_in', rad_sw_in_f%var1d )
rad_sw_in_f%from_file = .TRUE.
!
!-- Level-of-detail 2 - radiation depends on time_rad, y, x
ELSEIF ( rad_sw_in_f%lod == 2 ) THEN
ALLOCATE( rad_sw_in_f%var3d(0:ntime-1,nys:nyn,nxl:nxr) )
CALL get_variable( pids_id, 'rad_sw_in', rad_sw_in_f%var3d, nxl, nxr, nys, nyn, 0, &
ntime-1 )
rad_sw_in_f%from_file = .TRUE.
ELSE
message_string = '"rad_sw_in" has no valid lod attribute'
CALL message( 'radiation_init', 'PA0646', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
!
!-- Input longwave downwelling.
IF ( check_existence( vars_pids, 'rad_lw_in' ) ) THEN
!
!-- Get _FillValue attribute
CALL get_attribute( pids_id, char_fill, rad_lw_in_f%fill, .FALSE., 'rad_lw_in' )
!
!-- Get level-of-detail
CALL get_attribute( pids_id, char_lod, rad_lw_in_f%lod, .FALSE., 'rad_lw_in' )
!
!-- Level-of-detail 1 - radiation depends only on time_rad
IF ( rad_lw_in_f%lod == 1 ) THEN
ALLOCATE( rad_lw_in_f%var1d(0:ntime-1) )
CALL get_variable( pids_id, 'rad_lw_in', rad_lw_in_f%var1d )
rad_lw_in_f%from_file = .TRUE.
!
!-- Level-of-detail 2 - radiation depends on time_rad, y, x
ELSEIF ( rad_lw_in_f%lod == 2 ) THEN
ALLOCATE( rad_lw_in_f%var3d(0:ntime-1,nys:nyn,nxl:nxr) )
CALL get_variable( pids_id, 'rad_lw_in', rad_lw_in_f%var3d, nxl, nxr, nys, nyn, 0, &
ntime-1 )
rad_lw_in_f%from_file = .TRUE.
ELSE
message_string = '"rad_lw_in" has no valid lod attribute'
CALL message( 'radiation_init', 'PA0646', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
!
!-- Input shortwave downwelling, diffuse part.
IF ( check_existence( vars_pids, 'rad_sw_in_dif' ) ) THEN
!
!-- Read _FillValue attribute
CALL get_attribute( pids_id, char_fill, rad_sw_in_dif_f%fill, .FALSE., 'rad_sw_in_dif' )
!
!-- Get level-of-detail
CALL get_attribute( pids_id, char_lod, rad_sw_in_dif_f%lod, .FALSE., 'rad_sw_in_dif' )
!
!-- Level-of-detail 1 - radiation depends only on time_rad
IF ( rad_sw_in_dif_f%lod == 1 ) THEN
ALLOCATE( rad_sw_in_dif_f%var1d(0:ntime-1) )
CALL get_variable( pids_id, 'rad_sw_in_dif', rad_sw_in_dif_f%var1d )
rad_sw_in_dif_f%from_file = .TRUE.
!
!-- Level-of-detail 2 - radiation depends on time_rad, y, x
ELSEIF ( rad_sw_in_dif_f%lod == 2 ) THEN
ALLOCATE( rad_sw_in_dif_f%var3d(0:ntime-1,nys:nyn,nxl:nxr) )
CALL get_variable( pids_id, 'rad_sw_in_dif', rad_sw_in_dif_f%var3d, nxl, nxr, nys, &
nyn, 0, ntime-1 )
rad_sw_in_dif_f%from_file = .TRUE.
ELSE
message_string = '"rad_sw_in_dif" has no valid lod attribute'
CALL message( 'radiation_init', 'PA0646', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
!
!-- Finally, close the input file and deallocate temporary arrays
DEALLOCATE( vars_pids )
CALL close_input_file( pids_id )
#endif
!
!-- Make some consistency checks.
IF ( .NOT. rad_sw_in_f%from_file .OR. .NOT. rad_lw_in_f%from_file ) THEN
message_string = 'In case of external radiation forcing both, rad_sw_in and ' // &
'rad_lw_in are required.'
CALL message( 'radiation_init', 'PA0195', 1, 2, 0, 6, 0 )
ENDIF
IF ( .NOT. time_rad_f%from_file ) THEN
message_string = 'In case of external radiation forcing dimension time_rad is required.'
CALL message( 'radiation_init', 'PA0196', 1, 2, 0, 6, 0 )
ENDIF
CALL get_date_time( 0.0_wp, second_of_day=second_of_day )
IF ( end_time - spinup_time > time_rad_f%var1d(ntime-1) ) THEN
message_string = 'External radiation forcing does not cover the entire simulation time.'
CALL message( 'radiation_init', 'PA0314', 1, 2, 0, 6, 0 )
ENDIF
!
!-- Check for fill values in radiation
IF ( ALLOCATED( rad_sw_in_f%var1d ) ) THEN
IF ( ANY( rad_sw_in_f%var1d == rad_sw_in_f%fill ) ) THEN
message_string = 'External radiation array "rad_sw_in" must not contain any ' // &
'fill values.'
CALL message( 'radiation_init', 'PA0197', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
IF ( ALLOCATED( rad_lw_in_f%var1d ) ) THEN
IF ( ANY( rad_lw_in_f%var1d == rad_lw_in_f%fill ) ) THEN
message_string = 'External radiation array "rad_lw_in" must not contain any ' // &
'fill values.'
CALL message( 'radiation_init', 'PA0198', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
IF ( ALLOCATED( rad_sw_in_dif_f%var1d ) ) THEN
IF ( ANY( rad_sw_in_dif_f%var1d == rad_sw_in_dif_f%fill ) ) THEN
message_string = 'External radiation array "rad_sw_in_dif" must not contain any ' // &
'fill values.'
CALL message( 'radiation_init', 'PA0199', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
IF ( ALLOCATED( rad_sw_in_f%var3d ) ) THEN
IF ( ANY( rad_sw_in_f%var3d == rad_sw_in_f%fill ) ) THEN
message_string = 'External radiation array "rad_sw_in" must not contain any ' // &
'fill values.'
CALL message( 'radiation_init', 'PA0197', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
IF ( ALLOCATED( rad_lw_in_f%var3d ) ) THEN
IF ( ANY( rad_lw_in_f%var3d == rad_lw_in_f%fill ) ) THEN
message_string = 'External radiation array "rad_lw_in" must not contain any ' // &
'fill values.'
CALL message( 'radiation_init', 'PA0198', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
IF ( ALLOCATED( rad_sw_in_dif_f%var3d ) ) THEN
IF ( ANY( rad_sw_in_dif_f%var3d == rad_sw_in_dif_f%fill ) ) THEN
message_string = 'External radiation array "rad_sw_in_dif" must not contain any ' // &
'fill values.'
CALL message( 'radiation_init', 'PA0199', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
!
!-- Currently, 2D external radiation input is not possible in combination with topography where
!-- average radiation is used.
IF ( ( rad_lw_in_f%lod == 2 .OR. rad_sw_in_f%lod == 2 .OR. &
rad_sw_in_dif_f%lod == 2 ) .AND. average_radiation ) THEN
message_string = 'External radiation with lod = 2 is currently not possible with ' // &
'average_radiation = .T..'
CALL message( 'radiation_init', 'PA0670', 1, 2, 0, 6, 0 )
ENDIF
!
!-- All radiation input should have the same level of detail. The sum of lods divided by the
!-- number of available radiation arrays must be 1 (if all are lod = 1) or 2 (if all are lod = 2).
IF ( REAL( MERGE( rad_lw_in_f%lod, 0, rad_lw_in_f%from_file ) + &
MERGE( rad_sw_in_f%lod, 0, rad_sw_in_f%from_file ) + &
MERGE( rad_sw_in_dif_f%lod, 0, rad_sw_in_dif_f%from_file ), KIND = wp ) / &
( MERGE( 1.0_wp, 0.0_wp, rad_lw_in_f%from_file ) + &
MERGE( 1.0_wp, 0.0_wp, rad_sw_in_f%from_file ) + &
MERGE( 1.0_wp, 0.0_wp, rad_sw_in_dif_f%from_file ) ) /= 1.0_wp .AND. &
REAL( MERGE( rad_lw_in_f%lod, 0, rad_lw_in_f%from_file ) + &
MERGE( rad_sw_in_f%lod, 0, rad_sw_in_f%from_file ) + &
MERGE( rad_sw_in_dif_f%lod, 0, rad_sw_in_dif_f%from_file ), KIND = wp ) / &
( MERGE( 1.0_wp, 0.0_wp, rad_lw_in_f%from_file ) + &
MERGE( 1.0_wp, 0.0_wp, rad_sw_in_f%from_file ) + &
MERGE( 1.0_wp, 0.0_wp, rad_sw_in_dif_f%from_file ) ) &
/= 2.0_wp ) THEN
message_string = 'External radiation input should have the same lod.'
CALL message( 'radiation_init', 'PA0673', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
!
!-- Perform user actions if required
CALL user_init_radiation
!
!-- Calculate radiative fluxes at model start
SELECT CASE ( TRIM( radiation_scheme ) )
CASE ( 'rrtmg' )
CALL radiation_rrtmg
CASE ( 'clear-sky' )
CALL radiation_clearsky
CASE ( 'constant' )
CALL radiation_constant
CASE ( 'external' )
!
!-- During spinup apply clear-sky model
IF ( time_since_reference_point < 0.0_wp ) THEN
CALL radiation_clearsky
ELSE
CALL radiation_external
ENDIF
CASE DEFAULT
END SELECT
!
!-- If required, read or calculate and write out the SVF.
IF ( radiation_interactions ) THEN
!
!-- Find all discretized apparent solar positions for radiation interaction.
CALL radiation_presimulate_solar_pos
IF ( read_svf ) THEN
!
!-- Read sky-view factors and further required data from file
CALL radiation_read_svf()
ENDIF
!
!-- read_svf can be set .FALSE. in radiation_read_svf, therefore another IF and no ELSE
IF ( .NOT. read_svf ) THEN
!
!-- Calculate svf and csf.
CALL radiation_calc_svf()
ENDIF
IF ( write_svf ) THEN
!
!-- Write svf, csf svfsurf and csfsurf data to file.
CALL radiation_write_svf()
ENDIF
!
!-- Adjust radiative fluxes.
!-- In case of urban and land surfaces, also call an initial interaction.
CALL radiation_interaction
ENDIF
IF ( debug_output ) CALL debug_message( 'radiation_init', 'end' )
END SUBROUTINE radiation_init
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Use external radiative forcing (short- and longwave downwelling radiation) from a driver
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_external
IMPLICIT NONE
INTEGER(iwp) :: l !< running index for surface orientation
INTEGER(iwp) :: t !< index of current timestep
INTEGER(iwp) :: tm !< index of previous timestep
LOGICAL :: horizontal !< flag indicating treatment of horinzontal surfaces
REAL(wp) :: fac_dt !< interpolation factor
REAL(wp) :: second_of_day_init !< second of the day at model start
TYPE(surf_type), POINTER :: surf !< pointer on respective surface type, used to generalize routine
!
!-- Calculate current zenith angle
CALL get_date_time( time_since_reference_point, day_of_year = day_of_year, &
second_of_day = second_of_day )
CALL calc_zenith( day_of_year, second_of_day )
!
!-- Interpolate external radiation on current timestep
IF ( time_since_reference_point <= 0.0_wp ) THEN
t = 0
tm = 0
fac_dt = 0
ELSE
CALL get_date_time( 0.0_wp, second_of_day=second_of_day_init )
t = 0
DO WHILE ( time_rad_f%var1d(t) <= time_since_reference_point )
t = t + 1
ENDDO
tm = MAX( t-1, 0 )
fac_dt = ( time_since_reference_point - time_rad_f%var1d(tm) + dt_3d ) / &
MAX( TINY( 1._wp ), ( time_rad_f%var1d(t) - time_rad_f%var1d(tm) ) )
fac_dt = MIN( 1.0_wp, fac_dt )
ENDIF
!
!-- Call clear-sky calculation for each surface orientation.
!-- First, horizontal surfaces
horizontal = .TRUE.
DO l = 0, 1
surf => surf_lsm_h(l)
CALL radiation_external_surf
surf => surf_usm_h(l)
CALL radiation_external_surf
ENDDO
horizontal = .FALSE.
!
!-- Vertical surfaces
DO l = 0, 3
surf => surf_lsm_v(l)
CALL radiation_external_surf
surf => surf_usm_v(l)
CALL radiation_external_surf
ENDDO
CONTAINS
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Todo: Subroutine description missing!
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_external_surf
USE control_parameters
IMPLICIT NONE
INTEGER(iwp) :: i !< grid index along x-dimension
INTEGER(iwp) :: j !< grid index along y-dimension
INTEGER(iwp) :: k !< grid index along z-dimension
INTEGER(iwp) :: m !< running index for surface elements
REAL(wp) :: lw_in !< downwelling longwave radiation, interpolated value
REAL(wp) :: sw_in !< downwelling shortwave radiation, interpolated value
REAL(wp) :: sw_in_dif !< downwelling diffuse shortwave radiation, interpolated value
IF ( surf%ns < 1 ) RETURN
!
!-- Level-of-detail = 1. Note, here it must be distinguished between averaged radiation and
!-- non-averaged radiation for the upwelling fluxes.
IF ( rad_sw_in_f%lod == 1 ) THEN
sw_in = ( 1.0_wp - fac_dt ) * rad_sw_in_f%var1d(tm) + fac_dt * rad_sw_in_f%var1d(t)
lw_in = ( 1.0_wp - fac_dt ) * rad_lw_in_f%var1d(tm) + fac_dt * rad_lw_in_f%var1d(t)
!
!-- Limit shortwave incoming radiation to positive values, in order to overcome possible
!-- observation errors.
sw_in = MAX( 0.0_wp, sw_in )
sw_in = MERGE( sw_in, 0.0_wp, sun_up )
surf%rad_sw_in = sw_in
surf%rad_lw_in = lw_in
IF ( average_radiation ) THEN
surf%rad_sw_out = albedo_urb * surf%rad_sw_in
surf%rad_lw_out = emissivity_urb * sigma_sb * t_rad_urb**4 + &
( 1.0_wp - emissivity_urb ) * surf%rad_lw_in
surf%rad_net = surf%rad_sw_in - surf%rad_sw_out + surf%rad_lw_in - surf%rad_lw_out
surf%rad_lw_out_change_0 = 4.0_wp * emissivity_urb * sigma_sb * t_rad_urb**3
ELSE
DO m = 1, surf%ns
k = surf%k(m)
surf%rad_sw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%albedo(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%albedo(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%albedo(m,ind_wat_win) ) &
* surf%rad_sw_in(m)
surf%rad_lw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%emissivity(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%emissivity(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%emissivity(m,ind_wat_win) ) &
* sigma_sb * ( surf%pt_surface(m) * exner(k) )**4
surf%rad_lw_out_change_0(m) = ( surf%frac(m,ind_veg_wall) * &
surf%emissivity(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * &
surf%emissivity(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * &
surf%emissivity(m,ind_wat_win) ) * 4.0_wp * sigma_sb &
* ( surf%pt_surface(m) * exner(k) )**3
ENDDO
ENDIF
!
!-- If diffuse shortwave radiation is available, store it on the respective files.
IF ( rad_sw_in_dif_f%from_file ) THEN
sw_in_dif= ( 1.0_wp - fac_dt ) * rad_sw_in_dif_f%var1d(tm) &
+ fac_dt * rad_sw_in_dif_f%var1d(t)
IF ( ALLOCATED( rad_sw_in_diff ) ) rad_sw_in_diff = sw_in_dif
IF ( ALLOCATED( rad_sw_in_dir ) ) rad_sw_in_dir = sw_in - sw_in_dif
!
!-- Diffuse longwave radiation equals the total downwelling longwave radiation
IF ( ALLOCATED( rad_lw_in_diff ) ) rad_lw_in_diff = lw_in
ENDIF
!
!-- level-of-detail = 2
ELSE
DO m = 1, surf%ns
i = surf%i(m)
j = surf%j(m)
k = surf%k(m)
surf%rad_sw_in(m) = ( 1.0_wp - fac_dt ) * rad_sw_in_f%var3d(tm,j,i) &
+ fac_dt * rad_sw_in_f%var3d(t,j,i)
!
!-- Limit shortwave incoming radiation to positive values, in order to overcome possible
!-- observation errors.
surf%rad_sw_in(m) = MAX( 0.0_wp, surf%rad_sw_in(m) )
surf%rad_sw_in(m) = MERGE( surf%rad_sw_in(m), 0.0_wp, sun_up )
surf%rad_lw_in(m) = ( 1.0_wp - fac_dt ) * rad_lw_in_f%var3d(tm,j,i) &
+ fac_dt * rad_lw_in_f%var3d(t,j,i)
!
!-- Weighted average according to surface fraction.
surf%rad_sw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%albedo(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%albedo(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%albedo(m,ind_wat_win) ) &
* surf%rad_sw_in(m)
surf%rad_lw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%emissivity(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%emissivity(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%emissivity(m,ind_wat_win) ) &
* sigma_sb * ( surf%pt_surface(m) * exner(k) )**4
surf%rad_lw_out_change_0(m) = ( surf%frac(m,ind_veg_wall) * &
surf%emissivity(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * &
surf%emissivity(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * &
surf%emissivity(m,ind_wat_win) ) * 4.0_wp * sigma_sb &
* ( surf%pt_surface(m) * exner(k) )**3
surf%rad_net(m) = surf%rad_sw_in(m) - surf%rad_sw_out(m) + surf%rad_lw_in(m) - &
surf%rad_lw_out(m)
!
!-- If diffuse shortwave radiation is available, store it on the respective files.
IF ( rad_sw_in_dif_f%from_file ) THEN
IF ( ALLOCATED( rad_sw_in_diff ) ) &
rad_sw_in_diff(j,i) = ( 1.0_wp - fac_dt ) * rad_sw_in_dif_f%var3d(tm,j,i) &
+ fac_dt * rad_sw_in_dif_f%var3d(t,j,i)
!
!-- dir = sw_in - sw_in_dif.
IF ( ALLOCATED( rad_sw_in_dir ) ) &
rad_sw_in_dir(j,i) = surf%rad_sw_in(m) - rad_sw_in_diff(j,i)
!
!-- Diffuse longwave radiation equals the total downwelling longwave radiation
IF ( ALLOCATED( rad_lw_in_diff ) ) rad_lw_in_diff(j,i) = surf%rad_lw_in(m)
ENDIF
ENDDO
ENDIF
!
!-- Store radiation also on 2D arrays, which are still used for direct-diffuse splitting. Note,
!-- this is only required for horizontal surfaces, which covers all x,y position.
IF ( horizontal ) THEN
DO m = 1, surf%ns
i = surf%i(m)
j = surf%j(m)
rad_sw_in(0,j,i) = surf%rad_sw_in(m)
rad_lw_in(0,j,i) = surf%rad_lw_in(m)
rad_sw_out(0,j,i) = surf%rad_sw_out(m)
rad_lw_out(0,j,i) = surf%rad_lw_out(m)
ENDDO
ENDIF
END SUBROUTINE radiation_external_surf
END SUBROUTINE radiation_external
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> A simple clear sky radiation model
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_clearsky
IMPLICIT NONE
INTEGER(iwp) :: l !< running index for surface orientation
LOGICAL :: horizontal !< flag indicating treatment of horinzontal surfaces
REAL(wp) :: pt1 !< potential temperature at first grid level or mean value at urban layer top
REAL(wp) :: pt1_l !< potential temperature at first grid level or mean value at urban layer top at local subdomain
REAL(wp) :: ql1 !< liquid water mixing ratio at first grid level or mean value at urban layer top
REAL(wp) :: ql1_l !< liquid water mixing ratio at first grid level or mean value at urban layer top at local subdomain
TYPE(surf_type), POINTER :: surf !< pointer on respective surface type, used to generalize routine
!
!-- Calculate current zenith angle
CALL get_date_time( time_since_reference_point, day_of_year = day_of_year, &
second_of_day = second_of_day )
CALL calc_zenith( day_of_year, second_of_day )
!
!-- Calculate sky transmissivity
sky_trans = 0.6_wp + 0.2_wp * cos_zenith
!
!-- Calculate value of the Exner function at model surface
!
!-- In case averaged radiation is used, calculate mean temperature and liquid water mixing ratio at
!-- the urban-layer top.
IF ( average_radiation ) THEN
pt1 = 0.0_wp
IF ( bulk_cloud_model .OR. cloud_droplets ) ql1 = 0.0_wp
pt1_l = SUM( pt(nz_urban_t,nys:nyn,nxl:nxr) )
IF ( bulk_cloud_model .OR. cloud_droplets ) ql1_l = SUM( ql(nz_urban_t,nys:nyn,nxl:nxr) )
#if defined( __parallel )
IF ( collective_wait ) CALL MPI_BARRIER( comm2d, ierr )
CALL MPI_ALLREDUCE( pt1_l, pt1, 1, MPI_REAL, MPI_SUM, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE1:', ierr, pt1_l, pt1
FLUSH( 9 )
ENDIF
IF ( bulk_cloud_model .OR. cloud_droplets ) THEN
CALL MPI_ALLREDUCE( ql1_l, ql1, 1, MPI_REAL, MPI_SUM, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE2:', ierr, ql1_l, ql1
FLUSH( 9 )
ENDIF
ENDIF
#else
pt1 = pt1_l
IF ( bulk_cloud_model .OR. cloud_droplets ) ql1 = ql1_l
#endif
IF ( bulk_cloud_model .OR. cloud_droplets ) pt1 = pt1 + lv_d_cp / exner(nz_urban_t) * ql1
!
!-- Finally, divide by number of grid points
pt1 = pt1 / REAL( ( nx + 1 ) * ( ny + 1 ), KIND = wp )
ENDIF
!
!-- Call clear-sky calculation for each surface orientation.
!-- First, horizontal surfaces
horizontal = .TRUE.
DO l = 0, 1
surf => surf_lsm_h(l)
CALL radiation_clearsky_surf
surf => surf_usm_h(l)
CALL radiation_clearsky_surf
ENDDO
horizontal = .FALSE.
!
!-- Vertical surfaces
DO l = 0, 3
surf => surf_lsm_v(l)
CALL radiation_clearsky_surf
surf => surf_usm_v(l)
CALL radiation_clearsky_surf
ENDDO
CONTAINS
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Todo: Subroutine description missing.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_clearsky_surf
IMPLICIT NONE
INTEGER(iwp) :: i !< index x-direction
INTEGER(iwp) :: j !< index y-direction
INTEGER(iwp) :: k !< index z-direction
INTEGER(iwp) :: m !< running index for surface elements
IF ( surf%ns < 1 ) RETURN
!
!-- Calculate radiation fluxes and net radiation (rad_net) assuming homogeneous urban radiation
!-- conditions.
IF ( average_radiation ) THEN
k = nz_urban_t
surf%rad_sw_in = solar_constant * sky_trans * cos_zenith
surf%rad_sw_out = albedo_urb * surf%rad_sw_in
surf%rad_lw_in = emissivity_atm_clsky * sigma_sb * ( pt1 * exner(k+1) )**4
surf%rad_lw_out = emissivity_urb * sigma_sb * ( t_rad_urb )**4 * &
( 1.0_wp - emissivity_urb ) * surf%rad_lw_in
surf%rad_net = surf%rad_sw_in - surf%rad_sw_out + surf%rad_lw_in - surf%rad_lw_out
surf%rad_lw_out_change_0 = 4.0_wp * emissivity_urb * sigma_sb * ( t_rad_urb )**3
!
!-- Calculate radiation fluxes and net radiation (rad_net) for each surface element.
ELSE
DO m = 1, surf%ns
i = surf%i(m)
j = surf%j(m)
k = surf%k(m)
surf%rad_sw_in(m) = solar_constant * sky_trans * cos_zenith
!
!-- Weighted average according to surface fraction.
!-- ATTENTION: when radiation interactions are switched on the calculated fluxes below are not
!-- actually used as they are overwritten in radiation_interaction.
surf%rad_sw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%albedo(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%albedo(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%albedo(m,ind_wat_win) ) &
* surf%rad_sw_in(m)
surf%rad_lw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%emissivity(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%emissivity(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%emissivity(m,ind_wat_win) ) &
* sigma_sb * ( surf%pt_surface(m) * exner(nzb) )**4
surf%rad_lw_out_change_0(m) = ( surf%frac(m,ind_veg_wall) * &
surf%emissivity(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * &
surf%emissivity(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * &
surf%emissivity(m,ind_wat_win) ) * 4.0_wp * sigma_sb &
* ( surf%pt_surface(m) * exner(nzb) )** 3
IF ( bulk_cloud_model .OR. cloud_droplets ) THEN
pt1 = pt(k,j,i) + lv_d_cp / exner(k) * ql(k,j,i)
surf%rad_lw_in(m) = emissivity_atm_clsky * sigma_sb * ( pt1 * exner(k) )**4
ELSE
surf%rad_lw_in(m) = emissivity_atm_clsky * sigma_sb * ( pt(k,j,i) * exner(k) )**4
ENDIF
surf%rad_net(m) = surf%rad_sw_in(m) - surf%rad_sw_out(m) + surf%rad_lw_in(m) - &
surf%rad_lw_out(m)
ENDDO
ENDIF
!
!-- Fill out values in radiation arrays. Note, this is only required for horizontal surfaces, which
!-- covers all x,y position.
IF ( horizontal ) THEN
DO m = 1, surf%ns
i = surf%i(m)
j = surf%j(m)
rad_sw_in(0,j,i) = surf%rad_sw_in(m)
rad_sw_out(0,j,i) = surf%rad_sw_out(m)
rad_lw_in(0,j,i) = surf%rad_lw_in(m)
rad_lw_out(0,j,i) = surf%rad_lw_out(m)
ENDDO
ENDIF
END SUBROUTINE radiation_clearsky_surf
END SUBROUTINE radiation_clearsky
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> This scheme keeps the prescribed net radiation constant during the run
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_constant
IMPLICIT NONE
INTEGER(iwp) :: l !< running index for surface orientation
LOGICAL :: horizontal !< flag indicating treatment of horinzontal surfaces
REAL(wp) :: pt1 !< potential temperature at first grid level or mean value at urban layer top
REAL(wp) :: pt1_l !< potential temperature at first grid level or mean value at urban layer top at local subdomain
REAL(wp) :: ql1 !< liquid water mixing ratio at first grid level or mean value at urban layer top
REAL(wp) :: ql1_l !< liquid water mixing ratio at first grid level or mean value at urban layer top at local subdomain
TYPE(surf_type), POINTER :: surf !< pointer on respective surface type, used to generalize routine
!
!-- In case averaged radiation is used, calculate mean temperature and liquid water mixing ratio at
!-- the urban-layer top.
IF ( average_radiation ) THEN
pt1 = 0.0_wp
IF ( bulk_cloud_model .OR. cloud_droplets ) ql1 = 0.0_wp
pt1_l = SUM( pt(nz_urban_t,nys:nyn,nxl:nxr) )
IF ( bulk_cloud_model .OR. cloud_droplets ) ql1_l = SUM( ql(nz_urban_t,nys:nyn,nxl:nxr) )
#if defined( __parallel )
IF ( collective_wait ) CALL MPI_BARRIER( comm2d, ierr )
CALL MPI_ALLREDUCE( pt1_l, pt1, 1, MPI_REAL, MPI_SUM, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE3:', ierr, pt1_l, pt1
FLUSH( 9 )
ENDIF
IF ( bulk_cloud_model .OR. cloud_droplets ) THEN
CALL MPI_ALLREDUCE( ql1_l, ql1, 1, MPI_REAL, MPI_SUM, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE4:', ierr, ql1_l, ql1
FLUSH( 9 )
ENDIF
ENDIF
#else
pt1 = pt1_l
IF ( bulk_cloud_model .OR. cloud_droplets ) ql1 = ql1_l
#endif
IF ( bulk_cloud_model .OR. cloud_droplets ) pt1 = pt1 + lv_d_cp / exner(nz_urban_t+1) * &
ql1
!
!-- Finally, divide by number of grid points
pt1 = pt1 / REAL( ( nx + 1 ) * ( ny + 1 ), KIND = wp )
ENDIF
!
!-- First, horizontal surfaces
horizontal = .TRUE.
DO l = 0, 1
surf => surf_lsm_h(l)
CALL radiation_constant_surf
surf => surf_usm_h(l)
CALL radiation_constant_surf
ENDDO
horizontal = .FALSE.
!
!-- Vertical surfaces
DO l = 0, 3
surf => surf_lsm_v(l)
CALL radiation_constant_surf
surf => surf_usm_v(l)
CALL radiation_constant_surf
ENDDO
CONTAINS
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Todo: Subroutine description missing!
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_constant_surf
IMPLICIT NONE
INTEGER(iwp) :: i !< index x-direction
INTEGER(iwp) :: ioff !< offset between surface element and adjacent grid point along x
INTEGER(iwp) :: j !< index y-direction
INTEGER(iwp) :: joff !< offset between surface element and adjacent grid point along y
INTEGER(iwp) :: k !< index z-direction
INTEGER(iwp) :: koff !< offset between surface element and adjacent grid point along z
INTEGER(iwp) :: m !< running index for surface elements
IF ( surf%ns < 1 ) RETURN
!-- Calculate homogenoeus urban radiation fluxes
IF ( average_radiation ) THEN
surf%rad_net = net_radiation
surf%rad_lw_in = emissivity_atm_clsky * sigma_sb * ( pt1 * exner(nz_urban_t+1) )**4
surf%rad_lw_out = emissivity_urb * sigma_sb * ( t_rad_urb )**4 &
+ ( 1.0_wp - emissivity_urb ) & ! Shouldn't this be a bulk value -- emissivity_urb?
* surf%rad_lw_in
surf%rad_lw_out_change_0 = 4.0_wp * emissivity_urb * sigma_sb * t_rad_urb**3
surf%rad_sw_in = ( surf%rad_net - surf%rad_lw_in + surf%rad_lw_out ) / &
( 1.0_wp - albedo_urb )
surf%rad_sw_out = albedo_urb * surf%rad_sw_in
!
!-- Calculate radiation fluxes for each surface element
ELSE
!
!-- Determine index offset between surface element and adjacent atmospheric grid point
ioff = surf%ioff
joff = surf%joff
koff = surf%koff
!
!-- Prescribe net radiation and estimate the remaining radiative fluxes
DO m = 1, surf%ns
i = surf%i(m)
j = surf%j(m)
k = surf%k(m)
surf%rad_net(m) = net_radiation
IF ( bulk_cloud_model .OR. cloud_droplets ) THEN
pt1 = pt(k,j,i) + lv_d_cp / exner(k) * ql(k,j,i)
surf%rad_lw_in(m) = emissivity_atm_clsky * sigma_sb * ( pt1 * exner(k) )**4
ELSE
surf%rad_lw_in(m) = emissivity_atm_clsky * sigma_sb * ( pt(k,j,i) * exner(k) )**4
ENDIF
!
!-- Weighted average according to surface fraction.
surf%rad_lw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%emissivity(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%emissivity(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%emissivity(m,ind_wat_win) ) &
* sigma_sb * ( surf%pt_surface(m) * exner(nzb) )**4
surf%rad_sw_in(m) = ( surf%rad_net(m) - surf%rad_lw_in(m) + surf%rad_lw_out(m) ) &
/ ( 1.0_wp - ( surf%frac(m,ind_veg_wall) * &
surf%albedo(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * &
surf%albedo(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * &
surf%albedo(m,ind_wat_win) &
) &
)
surf%rad_sw_out(m) = ( surf%frac(m,ind_veg_wall) * surf%albedo(m,ind_veg_wall) &
+ surf%frac(m,ind_pav_green) * surf%albedo(m,ind_pav_green) &
+ surf%frac(m,ind_wat_win) * surf%albedo(m,ind_wat_win) ) &
* surf%rad_sw_in(m)
ENDDO
ENDIF
!
!-- Fill out values in radiation arrays. Note, this is only required for horizontal surfaces, which
!-- covers all x,y position.
IF ( horizontal ) THEN
DO m = 1, surf%ns
i = surf%i(m)
j = surf%j(m)
rad_sw_in(0,j,i) = surf%rad_sw_in(m)
rad_sw_out(0,j,i) = surf%rad_sw_out(m)
rad_lw_in(0,j,i) = surf%rad_lw_in(m)
rad_lw_out(0,j,i) = surf%rad_lw_out(m)
ENDDO
ENDIF
END SUBROUTINE radiation_constant_surf
END SUBROUTINE radiation_constant
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Header output for radiation model
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_header ( io )
IMPLICIT NONE
INTEGER(iwp), INTENT(IN) :: io !< Unit of the output file
!
!-- Write radiation model header
WRITE( io, 3 )
IF ( radiation_scheme == 'constant' ) THEN
WRITE( io, 4 ) net_radiation
ELSEIF ( radiation_scheme == 'clear-sky' ) THEN
WRITE( io, 5 )
ELSEIF ( radiation_scheme == 'rrtmg' ) THEN
WRITE( io, 6 )
IF ( .NOT. lw_radiation ) WRITE( io, 10 )
IF ( .NOT. sw_radiation ) WRITE( io, 11 )
ELSEIF ( radiation_scheme == 'external' ) THEN
WRITE( io, 14 )
ENDIF
IF ( albedo_type_f%from_file .OR. vegetation_type_f%from_file .OR. &
pavement_type_f%from_file .OR. water_type_f%from_file .OR. &
building_type_f%from_file ) THEN
WRITE( io, 13 )
ELSE
IF ( albedo_type == 0 ) THEN
WRITE( io, 7 ) albedo
ELSE
WRITE( io, 8 ) TRIM( albedo_type_name(albedo_type) )
ENDIF
ENDIF
IF ( constant_albedo ) THEN
WRITE( io, 9 )
ENDIF
WRITE( io, 12 ) dt_radiation
3 FORMAT ( //' Radiation model information:'/ ' ----------------------------'/ )
4 FORMAT ( ' --> Using constant net radiation: net_radiation = ', F6.2, // 'W/m**2' )
5 FORMAT ( ' --> Simple radiation scheme for clear sky is used (no clouds,', ' default)' )
6 FORMAT ( ' --> RRTMG scheme is used' )
7 FORMAT ( /' User-specific surface albedo: albedo =', F6.3 )
8 FORMAT ( /' Albedo is set for land surface type: ', A )
9 FORMAT ( /' --> Albedo is fixed during the run' )
10 FORMAT ( /' --> Longwave radiation is disabled' )
11 FORMAT ( /' --> Shortwave radiation is disabled.' )
12 FORMAT ( ' Timestep: dt_radiation = ', F6.2, ' s' )
13 FORMAT ( /' Albedo is set individually for each xy-location, according ', &
'to given surface type.')
14 FORMAT ( ' --> External radiation forcing is used' )
END SUBROUTINE radiation_header
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Parin for &radiation_parameters for radiation model and RTM
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_parin
IMPLICIT NONE
CHARACTER(LEN=100) :: line !< dummy string that contains the current line of the parameter file
INTEGER(iwp) :: io_status !< status after reading the namelist file
LOGICAL :: switch_off_module = .FALSE. !< local namelist parameter to switch off the module
!< although the respective module namelist appears in
!< the namelist file
NAMELIST /radiation_parameters/ albedo, &
albedo_lw_dif, &
albedo_lw_dir, &
albedo_sw_dif, &
albedo_sw_dir, &
albedo_type, &
bufsize_alltoall, &
constant_albedo, &
dt_radiation, &
emissivity, &
lw_radiation, &
max_raytracing_dist, &
min_irrf_value, &
mrt_geom, &
mrt_geom_params, &
mrt_include_sw, &
mrt_nlevels, &
mrt_skip_roof, &
net_radiation, &
nrefsteps, &
plant_lw_interact, &
rad_angular_discretization, &
radiation_interactions_on, &
radiation_scheme, &
raytrace_discrete_azims, &
raytrace_discrete_elevs, &
raytrace_mpi_rma, &
trace_fluxes_above, &
skip_time_do_radiation, &
surface_reflections, &
svfnorm_report_thresh, &
switch_off_module, &
sw_radiation, &
unscheduled_radiation_calls
!
!-- Move to the beginning of the namelist file and try to find and read the namelist.
REWIND( 11 )
READ( 11, radiation_parameters, IOSTAT=io_status )
!
!-- Action depending on the READ status
IF ( io_status == 0 ) THEN
!
!-- radiation_parameters namelist was found and read correctly. Set flag that indicates that the
!-- radiation model is switched on.
IF ( .NOT. switch_off_module ) radiation = .TRUE.
ELSEIF ( io_status > 0 ) THEN
!
!-- radiation_parameters namelist was found but contained errors. Print an error message
!-- including the line that caused the problem.
BACKSPACE( 11 )
READ( 11 , '(A)' ) line
CALL parin_fail_message( 'radiation_parameters', line )
ENDIF
END SUBROUTINE radiation_parin
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Implementation of the RRTMG radiation_scheme
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_rrtmg
#if defined ( __rrtmg )
USE exchange_horiz_mod, &
ONLY: exchange_horiz
USE indices, &
ONLY: nbgp
USE palm_date_time_mod, &
ONLY: hours_per_day
USE particle_attributes, &
ONLY: grid_particles, &
number_of_particles, &
particles, &
prt_count
IMPLICIT NONE
INTEGER(iwp) :: i, j, k, l, m, n !< loop indices
INTEGER(iwp) :: k_topo_l !< topography top index
INTEGER(iwp) :: k_topo !< topography top index
REAL(wp) :: d_hours_day !< 1 / hours-per-day
REAL(wp) :: nc_rad, & !< number concentration of cloud droplets
s_r2, & !< weighted sum over all droplets with r^2
s_r3 !< weighted sum over all droplets with r^3
REAL(wp), DIMENSION(0:0) :: zenith !< to provide indexed array
REAL(wp), DIMENSION(0:nzt+1) :: pt_av, q_av, ql_av !<
!
!-- Just dummy arguments
REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: rrtm_lw_taucld_dum, & !<
rrtm_lw_tauaer_dum, & !<
rrtm_sw_taucld_dum, & !<
rrtm_sw_ssacld_dum, & !<
rrtm_sw_asmcld_dum, & !<
rrtm_sw_fsfcld_dum, & !<
rrtm_sw_tauaer_dum, & !<
rrtm_sw_ssaaer_dum, & !<
rrtm_sw_asmaer_dum, & !<
rrtm_sw_ecaer_dum !<
!
!-- Pre-calculate parameters
d_hours_day = 1.0_wp / REAL( hours_per_day, KIND = wp )
!
!-- Calculate current (cosine of) zenith angle and whether the sun is up
CALL get_date_time( time_since_reference_point, day_of_year = day_of_year, &
second_of_day=second_of_day )
CALL calc_zenith( day_of_year, second_of_day )
zenith(0) = cos_zenith
!
!-- Calculate surface albedo. In case average radiation is applied, this is not required.
#if defined( __netcdf )
IF ( .NOT. constant_albedo ) THEN
!
!-- Horizontally aligned default, natural and urban surfaces
DO l = 0, 1
CALL calc_albedo( surf_lsm_h(l) )
CALL calc_albedo( surf_usm_h(l) )
ENDDO
!
!-- Vertically aligned default, natural and urban surfaces
DO l = 0, 3
CALL calc_albedo( surf_lsm_v(l) )
CALL calc_albedo( surf_usm_v(l) )
ENDDO
ENDIF
#endif
!
!-- Prepare input data for RRTMG
!
!-- In case of large scale forcing with surface data, calculate new pressure profile. nzt_rad might
!-- be modified by these calls and all required arrays will then be re-allocated.
IF ( large_scale_forcing .AND. lsf_surf ) THEN
CALL read_sounding_data
CALL read_trace_gas_data
ENDIF
IF ( average_radiation ) THEN
!
!-- Determine minimum topography top index.
k_topo_l = MINVAL( topo_top_ind(nys:nyn,nxl:nxr,0) )
#if defined( __parallel )
CALL MPI_ALLREDUCE( k_topo_l, k_topo, 1, MPI_INTEGER, MPI_MIN, comm2d, ierr )
#else
k_topo = k_topo_l
#endif
rrtm_asdir(1) = albedo_urb
rrtm_asdif(1) = albedo_urb
rrtm_aldir(1) = albedo_urb
rrtm_aldif(1) = albedo_urb
rrtm_emis = emissivity_urb
!
!-- Calculate mean pt profile.
CALL calc_mean_profile( pt, 4, .TRUE. )
pt_av = hom(:, 1, 4, 0)
IF ( humidity ) THEN
CALL calc_mean_profile( q, 41, .TRUE. )
q_av = hom(:, 1, 41, 0)
ENDIF
!
!-- Prepare profiles of temperature and H2O volume mixing ratio
rrtm_tlev(0,k_topo+1) = t_rad_urb
IF ( bulk_cloud_model ) THEN
CALL calc_mean_profile( ql, 54, .TRUE. )
! Average ql is now in hom(:, 1, 54, 0)
ql_av = hom(:, 1, 54, 0)
DO k = nzb+1, nzt+1
rrtm_tlay(0,k) = pt_av(k) * ( (hyp(k) ) / 100000._wp )**.286_wp + lv_d_cp * ql_av(k)
rrtm_h2ovmr(0,k) = mol_mass_air_d_wv * ( q_av(k) - ql_av(k) )
ENDDO
ELSE
DO k = nzb+1, nzt+1
rrtm_tlay(0,k) = pt_av(k) * ( (hyp(k) ) / 100000._wp )**.286_wp
ENDDO
IF ( humidity ) THEN
DO k = nzb+1, nzt+1
rrtm_h2ovmr(0,k) = mol_mass_air_d_wv * q_av(k)
ENDDO
ELSE
rrtm_h2ovmr(0,nzb+1:nzt+1) = 0.0_wp
ENDIF
ENDIF
!
!-- Avoid temperature/humidity jumps at the top of the PALM domain by linear interpolation from
!-- nzt+2 to nzt+7. Jumps are induced by discrepancies between the values in the domain and
!-- those above that are prescribed in RRTMG.
DO k = nzt+2, nzt+7
rrtm_tlay(0,k) = rrtm_tlay(0,nzt+1) + ( rrtm_tlay(0,nzt+8) - rrtm_tlay(0,nzt+1) ) / &
( rrtm_play(0,nzt+8) - rrtm_play(0,nzt+1) ) * &
( rrtm_play(0,k) - rrtm_play(0,nzt+1) )
rrtm_h2ovmr(0,k) = rrtm_h2ovmr(0,nzt+1) + ( rrtm_h2ovmr(0,nzt+8) - &
rrtm_h2ovmr(0,nzt+1) ) / &
( rrtm_play(0,nzt+8) - rrtm_play(0,nzt+1) ) * &
( rrtm_play(0,k) - rrtm_play(0,nzt+1) )
ENDDO
!-- Linear interpolation to zw grid. Loop reaches one level further up due to the staggered grid
!-- in RRTMG.
DO k = k_topo+2, nzt+8
rrtm_tlev(0,k) = rrtm_tlay(0,k-1) + ( rrtm_tlay(0,k) - rrtm_tlay(0,k-1) ) / &
( rrtm_play(0,k) - rrtm_play(0,k-1) ) * &
( rrtm_plev(0,k) - rrtm_play(0,k-1) )
ENDDO
!
!-- Calculate liquid water path and cloud fraction for each column.
!-- Note that LWP is required in g/m2 instead of kg/kg m.
rrtm_cldfr = 0.0_wp
rrtm_reliq = 0.0_wp
rrtm_cliqwp = 0.0_wp
rrtm_icld = 0
IF ( bulk_cloud_model ) THEN
DO k = nzb+1, nzt+1
rrtm_cliqwp(0,k) = ql_av(k) * 1000._wp * ( rrtm_plev(0,k) - rrtm_plev(0,k+1) ) * &
100._wp / g
IF ( rrtm_cliqwp(0,k) > 0._wp ) THEN
rrtm_cldfr(0,k) = 1._wp
IF ( rrtm_icld == 0 ) rrtm_icld = 1
!
!-- Calculate cloud droplet effective radius
rrtm_reliq(0,k) = 1.0E6_wp * ( 3.0_wp * ql_av(k) * rho_surface / &
( 4.0_wp * pi * nc_const * rho_l ) )**0.33333333333333_wp &
* EXP( LOG( sigma_gc )**2 )
!
!-- Limit effective radius
IF ( rrtm_reliq(0,k) > 0.0_wp ) THEN
rrtm_reliq(0,k) = MAX( rrtm_reliq(0,k), 2.5_wp )
rrtm_reliq(0,k) = MIN( rrtm_reliq(0,k), 60.0_wp )
ENDIF
ENDIF
ENDDO
ENDIF
!
!-- Set surface temperature
rrtm_tsfc = t_rad_urb
IF ( lw_radiation ) THEN
!
!-- Due to technical reasons, copy optical depth to dummy arguments which are allocated on the
!-- exact size as the rrtmg_lw is called. As one dimension is allocated with zero size,
!-- compiler complains that rank of the array does not match that of the assumed-shaped
!-- arguments in the RRTMG library. In order to avoid this, write to dummy arguments and
!-- pass the entire dummy array. Seems to be the only existing work-around.
ALLOCATE( rrtm_lw_taucld_dum(1:nbndlw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_lw_tauaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndlw+1) )
rrtm_lw_taucld_dum = rrtm_lw_taucld(1:nbndlw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_lw_tauaer_dum = rrtm_lw_tauaer(0:0,k_topo+1:nzt_rad+1,1:nbndlw+1)
CALL rrtmg_lw( 1, nzt_rad-k_topo, rrtm_icld, rrtm_idrv, rrtm_play(:,k_topo+1:), &
rrtm_plev(:,k_topo+1:), rrtm_tlay(:,k_topo+1:), rrtm_tlev(:,k_topo+1:), &
rrtm_tsfc, rrtm_h2ovmr(:,k_topo+1:), rrtm_o3vmr(:,k_topo+1:), &
rrtm_co2vmr(:,k_topo+1:), rrtm_ch4vmr(:,k_topo+1:), &
rrtm_n2ovmr(:,k_topo+1:), rrtm_o2vmr(:,k_topo+1:), &
rrtm_cfc11vmr(:,k_topo+1:), rrtm_cfc12vmr(:,k_topo+1:), &
rrtm_cfc22vmr(:,k_topo+1:), rrtm_ccl4vmr(:,k_topo+1:), rrtm_emis, &
rrtm_inflglw, rrtm_iceflglw, rrtm_liqflglw, rrtm_cldfr(:,k_topo+1:), &
rrtm_lw_taucld_dum, rrtm_cicewp(:,k_topo+1:), rrtm_cliqwp(:,k_topo+1:), &
rrtm_reice(:,k_topo+1:), rrtm_reliq(:,k_topo+1:), rrtm_lw_tauaer_dum, &
rrtm_lwuflx(:,k_topo:), rrtm_lwdflx(:,k_topo:), rrtm_lwhr(:,k_topo+1:), &
rrtm_lwuflxc(:,k_topo:), rrtm_lwdflxc(:,k_topo:), rrtm_lwhrc(:,k_topo+1:),&
rrtm_lwuflx_dt(:,k_topo:), rrtm_lwuflxc_dt(:,k_topo:) )
DEALLOCATE( rrtm_lw_taucld_dum )
DEALLOCATE( rrtm_lw_tauaer_dum )
!
!-- Save fluxes
DO i = nxl, nxr
DO j = nys, nyn
k_topo_l = topo_top_ind(j,i,0)
DO k = k_topo_l, nzt+1
rad_lw_in(k,j,i) = rrtm_lwdflx(0,k-k_topo_l+k_topo)
rad_lw_out(k,j,i) = rrtm_lwuflx(0,k-k_topo_l+k_topo)
ENDDO
ENDDO
ENDDO
rad_lw_in_diff(:,:) = rrtm_lwdflx(0,k_topo)
!
!-- Save heating rates (convert from K/d to K/h).
!-- Further, even though an aggregated radiation is computed, map signle-column profiles on
!-- top of any topography, in order to obtain correct near surface radiation heating/cooling
!-- rates.
DO i = nxl, nxr
DO j = nys, nyn
k_topo_l = topo_top_ind(j,i,0)
DO k = k_topo_l+1, nzt+1
rad_lw_hr(k,j,i) = rrtm_lwhr(0,k-k_topo_l+k_topo) * d_hours_day
rad_lw_cs_hr(k,j,i) = rrtm_lwhrc(0,k-k_topo_l+k_topo) * d_hours_day
ENDDO
ENDDO
ENDDO
ENDIF
IF ( sw_radiation .AND. sun_up ) THEN
!
!-- Due to technical reasons, copy optical depths and other to dummy arguments which are
!-- allocated on the exact size as the rrtmg_sw is called. As one dimesion is allocated with
!-- zero size, compiler complains that rank of the array does not match that of the
!-- assumed-shaped arguments in the RRTMG library. In order to avoid this, write to dummy
!-- arguments and pass the entire dummy array. Seems to be the only existing work-around.
ALLOCATE( rrtm_sw_taucld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_ssacld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_asmcld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_fsfcld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_tauaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_ssaaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_asmaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_ecaer_dum(0:0,k_topo+1:nzt_rad+1,1:naerec+1) )
rrtm_sw_taucld_dum = rrtm_sw_taucld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_ssacld_dum = rrtm_sw_ssacld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_asmcld_dum = rrtm_sw_asmcld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_fsfcld_dum = rrtm_sw_fsfcld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_tauaer_dum = rrtm_sw_tauaer(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1)
rrtm_sw_ssaaer_dum = rrtm_sw_ssaaer(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1)
rrtm_sw_asmaer_dum = rrtm_sw_asmaer(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1)
rrtm_sw_ecaer_dum = rrtm_sw_ecaer(0:0,k_topo+1:nzt_rad+1,1:naerec+1)
CALL rrtmg_sw( 1, nzt_rad-k_topo, rrtm_icld, rrtm_iaer, rrtm_play(:,k_topo+1:nzt_rad+1), &
rrtm_plev(:,k_topo+1:nzt_rad+2), rrtm_tlay(:,k_topo+1:nzt_rad+1), &
rrtm_tlev(:,k_topo+1:nzt_rad+2), rrtm_tsfc, &
rrtm_h2ovmr(:,k_topo+1:nzt_rad+1), rrtm_o3vmr(:,k_topo+1:nzt_rad+1), &
rrtm_co2vmr(:,k_topo+1:nzt_rad+1), rrtm_ch4vmr(:,k_topo+1:nzt_rad+1), &
rrtm_n2ovmr(:,k_topo+1:nzt_rad+1), rrtm_o2vmr(:,k_topo+1:nzt_rad+1), &
rrtm_asdir, rrtm_asdif, rrtm_aldir, rrtm_aldif, zenith, 0.0_wp, &
day_of_year, solar_constant, rrtm_inflgsw, rrtm_iceflgsw, rrtm_liqflgsw, &
rrtm_cldfr(:,k_topo+1:nzt_rad+1), rrtm_sw_taucld_dum, rrtm_sw_ssacld_dum, &
rrtm_sw_asmcld_dum, rrtm_sw_fsfcld_dum, rrtm_cicewp(:,k_topo+1:nzt_rad+1),&
rrtm_cliqwp(:,k_topo+1:nzt_rad+1), rrtm_reice(:,k_topo+1:nzt_rad+1), &
rrtm_reliq(:,k_topo+1:nzt_rad+1), rrtm_sw_tauaer_dum, &
rrtm_sw_ssaaer_dum, rrtm_sw_asmaer_dum, rrtm_sw_ecaer_dum, &
rrtm_swuflx(:,k_topo:nzt_rad+1), rrtm_swdflx(:,k_topo:nzt_rad+1), &
rrtm_swhr(:,k_topo+1:nzt_rad+1), rrtm_swuflxc(:,k_topo:nzt_rad+1), &
rrtm_swdflxc(:,k_topo:nzt_rad+1), rrtm_swhrc(:,k_topo+1:nzt_rad+1), &
rrtm_dirdflux(:,k_topo:nzt_rad+1), rrtm_difdflux(:,k_topo:nzt_rad+1) )
DEALLOCATE( rrtm_sw_taucld_dum )
DEALLOCATE( rrtm_sw_ssacld_dum )
DEALLOCATE( rrtm_sw_asmcld_dum )
DEALLOCATE( rrtm_sw_fsfcld_dum )
DEALLOCATE( rrtm_sw_tauaer_dum )
DEALLOCATE( rrtm_sw_ssaaer_dum )
DEALLOCATE( rrtm_sw_asmaer_dum )
DEALLOCATE( rrtm_sw_ecaer_dum )
!
!-- Save radiation fluxes for the entire depth of the model domain
DO i = nxl, nxr
DO j = nys, nyn
k_topo_l = topo_top_ind(j,i,0)
DO k = k_topo_l, nzt+1
rad_sw_in(k,j,i) = rrtm_swdflx(0,k-k_topo_l+k_topo)
rad_sw_out(k,j,i) = rrtm_swuflx(0,k-k_topo_l+k_topo)
ENDDO
ENDDO
ENDDO
!-- Save direct and diffuse SW radiation at the surface (required by RTM)
rad_sw_in_dir(:,:) = rrtm_dirdflux(0,k_topo)
rad_sw_in_diff(:,:) = rrtm_difdflux(0,k_topo)
!
!-- Save heating rates (convert from K/d to K/s)
DO i = nxl, nxr
DO j = nys, nyn
k_topo_l = topo_top_ind(j,i,0)
DO k = k_topo_l+1, nzt+1
rad_sw_hr(k,j,i) = rrtm_swhr(0,k-k_topo_l+k_topo) * d_hours_day
rad_sw_cs_hr(k,j,i) = rrtm_swhrc(0,k-k_topo_l+k_topo) * d_hours_day
ENDDO
ENDDO
ENDDO
!
!-- Solar radiation is zero during night
ELSE
rad_sw_in = 0.0_wp
rad_sw_out = 0.0_wp
rad_sw_in_dir(:,:) = 0.0_wp
rad_sw_in_diff(:,:) = 0.0_wp
ENDIF
!
!-- RRTMG is called for each (j,i) grid point separately, starting at the highest topography level.
!-- Here no RTM is used since average_radiation is false. In fact, this branch is only called for
!-- homogeneous flat terrain so that the topography-top index is actually always zero.
ELSE
!
!-- Loop over all grid points
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Prepare profiles of temperature and H2O volume mixing ratio
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
rrtm_tlev(0,nzb+1) = surf_lsm_h(0)%pt_surface(m) * exner(nzb)
ENDDO
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
rrtm_tlev(0,nzb+1) = surf_usm_h(0)%pt_surface(m) * exner(nzb)
ENDDO
IF ( bulk_cloud_model ) THEN
DO k = nzb+1, nzt+1
rrtm_tlay(0,k) = pt(k,j,i) * exner(k) + lv_d_cp * ql(k,j,i)
rrtm_h2ovmr(0,k) = mol_mass_air_d_wv * (q(k,j,i) - ql(k,j,i))
ENDDO
ELSEIF ( cloud_droplets ) THEN
DO k = nzb+1, nzt+1
rrtm_tlay(0,k) = pt(k,j,i) * exner(k) + lv_d_cp * ql(k,j,i)
rrtm_h2ovmr(0,k) = mol_mass_air_d_wv * q(k,j,i)
ENDDO
ELSE
DO k = nzb+1, nzt+1
rrtm_tlay(0,k) = pt(k,j,i) * exner(k)
ENDDO
IF ( humidity ) THEN
DO k = nzb+1, nzt+1
rrtm_h2ovmr(0,k) = mol_mass_air_d_wv * q(k,j,i)
ENDDO
ELSE
rrtm_h2ovmr(0,nzb+1:nzt+1) = 0.0_wp
ENDIF
ENDIF
!
!-- Avoid temperature/humidity jumps at the top of the LES domain by linear interpolation
!-- from nzt+2 to nzt+7
DO k = nzt+2, nzt+7
rrtm_tlay(0,k) = rrtm_tlay(0,nzt+1) + ( rrtm_tlay(0,nzt+8) - rrtm_tlay(0,nzt+1) ) /&
( rrtm_play(0,nzt+8) - rrtm_play(0,nzt+1) ) * &
( rrtm_play(0,k) - rrtm_play(0,nzt+1) )
rrtm_h2ovmr(0,k) = rrtm_h2ovmr(0,nzt+1) + &
( rrtm_h2ovmr(0,nzt+8) - rrtm_h2ovmr(0,nzt+1) ) / &
( rrtm_play(0,nzt+8) - rrtm_play(0,nzt+1) ) * &
( rrtm_play(0,k) - rrtm_play(0,nzt+1) )
ENDDO
!-- Linear interpolation to zw grid
DO k = nzb+2, nzt+8
rrtm_tlev(0,k) = rrtm_tlay(0,k-1) + (rrtm_tlay(0,k) - rrtm_tlay(0,k-1) ) / &
( rrtm_play(0,k) - rrtm_play(0,k-1) ) * &
( rrtm_plev(0,k) - rrtm_play(0,k-1) )
ENDDO
!
!-- Calculate liquid water path and cloud fraction for each column.
!-- Note that LWP is required in g/m2 instead of kg/kg m.
rrtm_cldfr = 0.0_wp
rrtm_reliq = 0.0_wp
rrtm_cliqwp = 0.0_wp
rrtm_icld = 0
IF ( bulk_cloud_model .OR. cloud_droplets ) THEN
DO k = nzb+1, nzt+1
rrtm_cliqwp(0,k) = ql(k,j,i) * 1000.0_wp * &
( rrtm_plev(0,k) - rrtm_plev(0,k+1) ) * 100.0_wp / g
IF ( rrtm_cliqwp(0,k) > 0.0_wp ) THEN
rrtm_cldfr(0,k) = 1.0_wp
IF ( rrtm_icld == 0 ) rrtm_icld = 1
!
!-- Calculate cloud droplet effective radius
IF ( bulk_cloud_model ) THEN
!
!-- Calculate effective droplet radius. In case of using cloud_scheme =
!-- 'morrison' and a non reasonable number of cloud droplets the inital aerosol
!-- number concentration is considered.
IF ( microphysics_morrison ) THEN
IF ( nc(k,j,i) > 1.0E-20_wp ) THEN
nc_rad = nc(k,j,i)
ELSE
nc_rad = na_init
ENDIF
ELSE
nc_rad = nc_const
ENDIF
rrtm_reliq(0,k) = 1.0E6_wp * ( 3.0_wp * ql(k,j,i) * rho_surface / &
( 4.0_wp * pi * nc_rad * rho_l ) )**0.33333333333333_wp * &
EXP( LOG( sigma_gc )**2 )
ELSEIF ( cloud_droplets ) THEN
number_of_particles = prt_count(k,j,i)
IF (number_of_particles <= 0) CYCLE
particles => grid_particles(k,j,i)%particles(1:number_of_particles)
s_r2 = 0.0_wp
s_r3 = 0.0_wp
DO n = 1, number_of_particles
IF ( particles(n)%particle_mask ) THEN
s_r2 = s_r2 + particles(n)%radius**2 * particles(n)%weight_factor
s_r3 = s_r3 + particles(n)%radius**3 * particles(n)%weight_factor
ENDIF
ENDDO
IF ( s_r2 > 0.0_wp ) rrtm_reliq(0,k) = s_r3 / s_r2
ENDIF
!
!-- Limit effective radius
IF ( rrtm_reliq(0,k) > 0.0_wp ) THEN
rrtm_reliq(0,k) = MAX( rrtm_reliq(0,k), 2.5_wp )
rrtm_reliq(0,k) = MIN( rrtm_reliq(0,k), 60.0_wp )
ENDIF
ENDIF
ENDDO
ENDIF
!
!-- Write surface emissivity and surface temperature at current surface element on
!-- RRTMG-shaped array. Please note, as RRTMG is a single column model, surface attributes
!-- are only obtained from upward facing horizontally aligned surfaces (for simplicity).
!-- Taking surface attributes from horizontal and vertical walls would lead to multiple
!-- solutions. Moreover, for natural- and urban-type surfaces, several surface classes can
!-- exist at a surface element next to each other. To obtain bulk parameters, apply a
!-- weighted average for these surfaces.
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
rrtm_emis = surf_lsm_h(0)%frac(m,ind_veg_wall) * &
surf_lsm_h(0)%emissivity(m,ind_veg_wall) + &
surf_lsm_h(0)%frac(m,ind_pav_green) * &
surf_lsm_h(0)%emissivity(m,ind_pav_green) + &
surf_lsm_h(0)%frac(m,ind_wat_win) * &
surf_lsm_h(0)%emissivity(m,ind_wat_win)
rrtm_tsfc = surf_lsm_h(0)%pt_surface(m) * exner(nzb)
ENDDO
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
rrtm_emis = surf_usm_h(0)%frac(m,ind_veg_wall) * &
surf_usm_h(0)%emissivity(m,ind_veg_wall) + &
surf_usm_h(0)%frac(m,ind_pav_green) * &
surf_usm_h(0)%emissivity(m,ind_pav_green) + &
surf_usm_h(0)%frac(m,ind_wat_win) * &
surf_usm_h(0)%emissivity(m,ind_wat_win)
rrtm_tsfc = surf_usm_h(0)%pt_surface(m) * exner(nzb)
ENDDO
!
!-- Obtain topography top index (lower bound of RRTMG). Is actually always zero.
k_topo = topo_top_ind(j,i,0)
IF ( lw_radiation ) THEN
!
!-- Due to technical reasons, copy optical depth to dummy arguments which are allocated
!-- on the exact size as the rrtmg_lw is called. As one dimension is allocated with zero
!-- size, compiler complains that rank of the array does not match that of the
!-- assumed-shaped arguments in the RRTMG library. In order to avoid this, write to
!-- dummy arguments and pass the entire dummy array. Seems to be the only existing
!-- work-around.
ALLOCATE( rrtm_lw_taucld_dum(1:nbndlw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_lw_tauaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndlw+1) )
rrtm_lw_taucld_dum = rrtm_lw_taucld(1:nbndlw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_lw_tauaer_dum = rrtm_lw_tauaer(0:0,k_topo+1:nzt_rad+1,1:nbndlw+1)
CALL rrtmg_lw( 1, nzt_rad-k_topo, rrtm_icld, rrtm_idrv, &
rrtm_play(:,k_topo+1:nzt_rad+1), rrtm_plev(:,k_topo+1:nzt_rad+2), &
rrtm_tlay(:,k_topo+1:nzt_rad+1), rrtm_tlev(:,k_topo+1:nzt_rad+2), &
rrtm_tsfc, rrtm_h2ovmr(:,k_topo+1:nzt_rad+1), &
rrtm_o3vmr(:,k_topo+1:nzt_rad+1), rrtm_co2vmr(:,k_topo+1:nzt_rad+1),&
rrtm_ch4vmr(:,k_topo+1:nzt_rad+1), &
rrtm_n2ovmr(:,k_topo+1:nzt_rad+1), &
rrtm_o2vmr(:,k_topo+1:nzt_rad+1), &
rrtm_cfc11vmr(:,k_topo+1:nzt_rad+1), &
rrtm_cfc12vmr(:,k_topo+1:nzt_rad+1), &
rrtm_cfc22vmr(:,k_topo+1:nzt_rad+1), &
rrtm_ccl4vmr(:,k_topo+1:nzt_rad+1), rrtm_emis, rrtm_inflglw, &
rrtm_iceflglw, rrtm_liqflglw, rrtm_cldfr(:,k_topo+1:nzt_rad+1), &
rrtm_lw_taucld_dum, rrtm_cicewp(:,k_topo+1:nzt_rad+1), &
rrtm_cliqwp(:,k_topo+1:nzt_rad+1), rrtm_reice(:,k_topo+1:nzt_rad+1),&
rrtm_reliq(:,k_topo+1:nzt_rad+1), rrtm_lw_tauaer_dum, &
rrtm_lwuflx(:,k_topo:nzt_rad+1), rrtm_lwdflx(:,k_topo:nzt_rad+1), &
rrtm_lwhr(:,k_topo+1:nzt_rad+1), rrtm_lwuflxc(:,k_topo:nzt_rad+1), &
rrtm_lwdflxc(:,k_topo:nzt_rad+1), rrtm_lwhrc(:,k_topo+1:nzt_rad+1), &
rrtm_lwuflx_dt(:,k_topo:nzt_rad+1), &
rrtm_lwuflxc_dt(:,k_topo:nzt_rad+1) )
DEALLOCATE( rrtm_lw_taucld_dum )
DEALLOCATE( rrtm_lw_tauaer_dum )
!
!-- Save fluxes
DO k = k_topo, nzt+1
rad_lw_in(k,j,i) = rrtm_lwdflx(0,k)
rad_lw_out(k,j,i) = rrtm_lwuflx(0,k)
ENDDO
!
!-- Save heating rates (convert from K/d to K/h)
DO k = k_topo+1, nzt+1
rad_lw_hr(k,j,i) = rrtm_lwhr(0,k-k_topo) * d_hours_day
rad_lw_cs_hr(k,j,i) = rrtm_lwhrc(0,k-k_topo) * d_hours_day
ENDDO
!
!-- Save surface radiative fluxes and change in LW heating rate onto respective surface
!-- elements
!-- Horizontal surfaces
DO l = 0, 1
DO m = surf_lsm_h(l)%start_index(j,i), surf_lsm_h(l)%end_index(j,i)
surf_lsm_h(l)%rad_lw_in(m) = rrtm_lwdflx(0,k_topo)
surf_lsm_h(l)%rad_lw_out(m) = rrtm_lwuflx(0,k_topo)
surf_lsm_h(l)%rad_lw_out_change_0(m) = rrtm_lwuflx_dt(0,k_topo)
ENDDO
DO m = surf_usm_h(l)%start_index(j,i), surf_usm_h(l)%end_index(j,i)
surf_usm_h(l)%rad_lw_in(m) = rrtm_lwdflx(0,k_topo)
surf_usm_h(l)%rad_lw_out(m) = rrtm_lwuflx(0,k_topo)
surf_usm_h(l)%rad_lw_out_change_0(m) = rrtm_lwuflx_dt(0,k_topo)
ENDDO
ENDDO
!
!-- Vertical surfaces. Fluxes are obtain at vertical level of the respective surface
!-- element
DO l = 0, 3
DO m = surf_lsm_v(l)%start_index(j,i), surf_lsm_v(l)%end_index(j,i)
k = surf_lsm_v(l)%k(m)
surf_lsm_v(l)%rad_lw_in(m) = rrtm_lwdflx(0,k)
surf_lsm_v(l)%rad_lw_out(m) = rrtm_lwuflx(0,k)
surf_lsm_v(l)%rad_lw_out_change_0(m) = rrtm_lwuflx_dt(0,k)
ENDDO
DO m = surf_usm_v(l)%start_index(j,i), surf_usm_v(l)%end_index(j,i)
k = surf_usm_v(l)%k(m)
surf_usm_v(l)%rad_lw_in(m) = rrtm_lwdflx(0,k)
surf_usm_v(l)%rad_lw_out(m) = rrtm_lwuflx(0,k)
surf_usm_v(l)%rad_lw_out_change_0(m) = rrtm_lwuflx_dt(0,k)
ENDDO
ENDDO
ENDIF
IF ( sw_radiation .AND. sun_up ) THEN
!
!-- Get albedo for direct/diffusive long/shortwave radiation at current (y,x)-location
!-- from surface variables. Only obtain it from upward facing horizontal surfaces,
!-- as RRTMG is a single column model. (Please note, only one loop will be entered,
!-- controlled by start-end index.)
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
rrtm_asdir(1) = SUM( surf_lsm_h(0)%frac(m,:) * surf_lsm_h(0)%rrtm_asdir(m,:) )
rrtm_asdif(1) = SUM( surf_lsm_h(0)%frac(m,:) * surf_lsm_h(0)%rrtm_asdif(m,:) )
rrtm_aldir(1) = SUM( surf_lsm_h(0)%frac(m,:) * surf_lsm_h(0)%rrtm_aldir(m,:) )
rrtm_aldif(1) = SUM( surf_lsm_h(0)%frac(m,:) * surf_lsm_h(0)%rrtm_aldif(m,:) )
ENDDO
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
rrtm_asdir(1) = SUM( surf_usm_h(0)%frac(m,:) * surf_usm_h(0)%rrtm_asdir(m,:) )
rrtm_asdif(1) = SUM( surf_usm_h(0)%frac(m,:) * surf_usm_h(0)%rrtm_asdif(m,:) )
rrtm_aldir(1) = SUM( surf_usm_h(0)%frac(m,:) * surf_usm_h(0)%rrtm_aldir(m,:) )
rrtm_aldif(1) = SUM( surf_usm_h(0)%frac(m,:) * surf_usm_h(0)%rrtm_aldif(m,:) )
ENDDO
!
!-- Due to technical reasons, copy optical depths and other to dummy arguments which are
!-- allocated on the exact size as the rrtmg_sw is called. As one dimension is allocated
!-- with zero size, compiler complains that rank of the array does not match that of the
!-- assumed-shaped arguments in the RRTMG library. In order to avoid this, write to
!-- dummy arguments and pass the entire dummy array. Seems to be the only existing
!-- work-around.
ALLOCATE( rrtm_sw_taucld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_ssacld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_asmcld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_fsfcld_dum(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_tauaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_ssaaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_asmaer_dum(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_ecaer_dum(0:0,k_topo+1:nzt_rad+1,1:naerec+1) )
rrtm_sw_taucld_dum = rrtm_sw_taucld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_ssacld_dum = rrtm_sw_ssacld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_asmcld_dum = rrtm_sw_asmcld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_fsfcld_dum = rrtm_sw_fsfcld(1:nbndsw+1,0:0,k_topo+1:nzt_rad+1)
rrtm_sw_tauaer_dum = rrtm_sw_tauaer(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1)
rrtm_sw_ssaaer_dum = rrtm_sw_ssaaer(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1)
rrtm_sw_asmaer_dum = rrtm_sw_asmaer(0:0,k_topo+1:nzt_rad+1,1:nbndsw+1)
rrtm_sw_ecaer_dum = rrtm_sw_ecaer(0:0,k_topo+1:nzt_rad+1,1:naerec+1)
CALL rrtmg_sw( 1, nzt_rad-k_topo, rrtm_icld, rrtm_iaer, &
rrtm_play(:,k_topo+1:nzt_rad+1), rrtm_plev(:,k_topo+1:nzt_rad+2), &
rrtm_tlay(:,k_topo+1:nzt_rad+1), rrtm_tlev(:,k_topo+1:nzt_rad+2), &
rrtm_tsfc, rrtm_h2ovmr(:,k_topo+1:nzt_rad+1), &
rrtm_o3vmr(:,k_topo+1:nzt_rad+1), rrtm_co2vmr(:,k_topo+1:nzt_rad+1),&
rrtm_ch4vmr(:,k_topo+1:nzt_rad+1), &
rrtm_n2ovmr(:,k_topo+1:nzt_rad+1), &
rrtm_o2vmr(:,k_topo+1:nzt_rad+1), rrtm_asdir, rrtm_asdif, &
rrtm_aldir, rrtm_aldif, zenith, 0.0_wp, day_of_year, &
solar_constant, rrtm_inflgsw, rrtm_iceflgsw, rrtm_liqflgsw, &
rrtm_cldfr(:,k_topo+1:nzt_rad+1), rrtm_sw_taucld_dum, &
rrtm_sw_ssacld_dum, rrtm_sw_asmcld_dum, rrtm_sw_fsfcld_dum, &
rrtm_cicewp(:,k_topo+1:nzt_rad+1), &
rrtm_cliqwp(:,k_topo+1:nzt_rad+1), &
rrtm_reice(:,k_topo+1:nzt_rad+1), rrtm_reliq(:,k_topo+1:nzt_rad+1), &
rrtm_sw_tauaer_dum, rrtm_sw_ssaaer_dum, rrtm_sw_asmaer_dum, &
rrtm_sw_ecaer_dum, rrtm_swuflx(:,k_topo:nzt_rad+1), &
rrtm_swdflx(:,k_topo:nzt_rad+1), rrtm_swhr(:,k_topo+1:nzt_rad+1), &
rrtm_swuflxc(:,k_topo:nzt_rad+1), rrtm_swdflxc(:,k_topo:nzt_rad+1), &
rrtm_swhrc(:,k_topo+1:nzt_rad+1), rrtm_dirdflux(:,k_topo:nzt_rad+1),&
rrtm_difdflux(:,k_topo:nzt_rad+1) )
DEALLOCATE( rrtm_sw_taucld_dum )
DEALLOCATE( rrtm_sw_ssacld_dum )
DEALLOCATE( rrtm_sw_asmcld_dum )
DEALLOCATE( rrtm_sw_fsfcld_dum )
DEALLOCATE( rrtm_sw_tauaer_dum )
DEALLOCATE( rrtm_sw_ssaaer_dum )
DEALLOCATE( rrtm_sw_asmaer_dum )
DEALLOCATE( rrtm_sw_ecaer_dum )
!
!-- Save fluxes
DO k = nzb, nzt+1
rad_sw_in(k,j,i) = rrtm_swdflx(0,k)
rad_sw_out(k,j,i) = rrtm_swuflx(0,k)
ENDDO
!
!-- Save heating rates (convert from K/d to K/s)
DO k = nzb+1, nzt+1
rad_sw_hr(k,j,i) = rrtm_swhr(0,k) * d_hours_day
rad_sw_cs_hr(k,j,i) = rrtm_swhrc(0,k) * d_hours_day
ENDDO
!
!-- Save surface radiative fluxes onto respective surface elements
!-- Horizontal surfaces
DO l = 0, 1
DO m = surf_lsm_h(l)%start_index(j,i), surf_lsm_h(l)%end_index(j,i)
surf_lsm_h(l)%rad_sw_in(m) = rrtm_swdflx(0,k_topo)
surf_lsm_h(l)%rad_sw_out(m) = rrtm_swuflx(0,k_topo)
ENDDO
DO m = surf_usm_h(l)%start_index(j,i), surf_usm_h(l)%end_index(j,i)
surf_usm_h(l)%rad_sw_in(m) = rrtm_swdflx(0,k_topo)
surf_usm_h(l)%rad_sw_out(m) = rrtm_swuflx(0,k_topo)
ENDDO
ENDDO
!
!-- Vertical surfaces. Fluxes are obtain at respective vertical level of the surface
!-- element
DO l = 0, 3
DO m = surf_lsm_v(l)%start_index(j,i), surf_lsm_v(l)%end_index(j,i)
k = surf_lsm_v(l)%k(m)
surf_lsm_v(l)%rad_sw_in(m) = rrtm_swdflx(0,k)
surf_lsm_v(l)%rad_sw_out(m) = rrtm_swuflx(0,k)
ENDDO
DO m = surf_usm_v(l)%start_index(j,i), surf_usm_v(l)%end_index(j,i)
k = surf_usm_v(l)%k(m)
surf_usm_v(l)%rad_sw_in(m) = rrtm_swdflx(0,k)
surf_usm_v(l)%rad_sw_out(m) = rrtm_swuflx(0,k)
ENDDO
ENDDO
!
!-- Solar radiation is zero during night
ELSE
rad_sw_in = 0.0_wp
rad_sw_out = 0.0_wp
!-- !!!!!!!! ATTENTION !!!!!!!!!!!!!!!
!-- Surface radiative fluxes should be also set to zero here
!-- Save surface radiative fluxes onto respective surface elements
!-- Horizontal surfaces
DO l = 0, 1
DO m = surf_lsm_h(l)%start_index(j,i), surf_lsm_h(l)%end_index(j,i)
surf_lsm_h(l)%rad_sw_in(m) = 0.0_wp
surf_lsm_h(l)%rad_sw_out(m) = 0.0_wp
ENDDO
DO m = surf_usm_h(l)%start_index(j,i), surf_usm_h(l)%end_index(j,i)
surf_usm_h(l)%rad_sw_in(m) = 0.0_wp
surf_usm_h(l)%rad_sw_out(m) = 0.0_wp
ENDDO
ENDDO
!
!-- Vertical surfaces. Fluxes are obtained at respective vertical level of the surface
!-- element
DO l = 0, 3
DO m = surf_lsm_v(l)%start_index(j,i), surf_lsm_v(l)%end_index(j,i)
k = surf_lsm_v(l)%k(m)
surf_lsm_v(l)%rad_sw_in(m) = 0.0_wp
surf_lsm_v(l)%rad_sw_out(m) = 0.0_wp
ENDDO
DO m = surf_usm_v(l)%start_index(j,i), surf_usm_v(l)%end_index(j,i)
k = surf_usm_v(l)%k(m)
surf_usm_v(l)%rad_sw_in(m) = 0.0_wp
surf_usm_v(l)%rad_sw_out(m) = 0.0_wp
ENDDO
ENDDO
ENDIF
ENDDO
ENDDO
ENDIF
!
!-- Finally, calculate surface net radiation for surface elements.
IF ( .NOT. radiation_interactions ) THEN
!-- First, for horizontal surfaces
DO l = 0, 1
DO m = 1, surf_lsm_h(l)%ns
surf_lsm_h(l)%rad_net(m) = surf_lsm_h(l)%rad_sw_in(m) - surf_lsm_h(l)%rad_sw_out(m) + &
surf_lsm_h(l)%rad_lw_in(m) - surf_lsm_h(l)%rad_lw_out(m)
ENDDO
DO m = 1, surf_usm_h(l)%ns
surf_usm_h(l)%rad_net(m) = surf_usm_h(l)%rad_sw_in(m) - surf_usm_h(l)%rad_sw_out(m) + &
surf_usm_h(l)%rad_lw_in(m) - surf_usm_h(l)%rad_lw_out(m)
ENDDO
ENDDO
!
!-- Vertical surfaces.
!-- Todo: weight with azimuth and zenith angle according to their orientation!
DO l = 0, 3
DO m = 1, surf_lsm_v(l)%ns
surf_lsm_v(l)%rad_net(m) = surf_lsm_v(l)%rad_sw_in(m) - surf_lsm_v(l)%rad_sw_out(m) + &
surf_lsm_v(l)%rad_lw_in(m) - surf_lsm_v(l)%rad_lw_out(m)
ENDDO
DO m = 1, surf_usm_v(l)%ns
surf_usm_v(l)%rad_net(m) = surf_usm_v(l)%rad_sw_in(m) - surf_usm_v(l)%rad_sw_out(m) + &
surf_usm_v(l)%rad_lw_in(m) - surf_usm_v(l)%rad_lw_out(m)
ENDDO
ENDDO
ENDIF
CALL exchange_horiz( rad_lw_in, nbgp )
CALL exchange_horiz( rad_lw_out, nbgp )
CALL exchange_horiz( rad_lw_hr, nbgp )
CALL exchange_horiz( rad_lw_cs_hr, nbgp )
CALL exchange_horiz( rad_sw_in, nbgp )
CALL exchange_horiz( rad_sw_out, nbgp )
CALL exchange_horiz( rad_sw_hr, nbgp )
CALL exchange_horiz( rad_sw_cs_hr, nbgp )
#endif
END SUBROUTINE radiation_rrtmg
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Calculate the cosine of the zenith angle (variable is called zenith)
!--------------------------------------------------------------------------------------------------!
SUBROUTINE calc_zenith( day_of_year, second_of_day )
USE palm_date_time_mod, &
ONLY: seconds_per_day
IMPLICIT NONE
INTEGER(iwp), INTENT(IN) :: day_of_year !< day of the year
REAL(wp) :: declination !< solar declination angle
REAL(wp) :: hour_angle !< solar hour angle
REAL(wp),INTENT(IN) :: second_of_day !< current time of the day in UTC
!
!-- Calculate solar declination and hour angle
declination = ASIN( decl_1 * SIN( decl_2 * REAL( day_of_year, KIND = wp ) - decl_3 ) )
hour_angle = 2.0_wp * pi * ( second_of_day / seconds_per_day ) + lon - pi
!
!-- Calculate cosine of solar zenith angle
cos_zenith = SIN( lat ) * SIN( declination ) + COS( lat ) * COS( declination ) * &
COS( hour_angle )
cos_zenith = MAX( 0.0_wp, cos_zenith )
!
!-- Calculate solar directional vector
IF ( sun_direction ) THEN
!
!-- Direction in longitudes equals to sin(solar_azimuth) * sin(zenith)
sun_dir_lon = - SIN( hour_angle ) * COS( declination )
!
!-- Direction in latitues equals to cos(solar_azimuth) * sin(zenith)
sun_dir_lat = SIN( declination ) * COS( lat ) - COS( hour_angle ) * COS( declination ) * &
SIN( lat )
ENDIF
!
!-- Check if the sun is up (otheriwse shortwave calculations can be skipped)
IF ( cos_zenith > 0.0_wp ) THEN
sun_up = .TRUE.
ELSE
sun_up = .FALSE.
END IF
END SUBROUTINE calc_zenith
#if defined ( __rrtmg ) && defined ( __netcdf )
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Calculates surface albedo components based on Briegleb (1992) and Briegleb et al. (1986)
!--------------------------------------------------------------------------------------------------!
SUBROUTINE calc_albedo( surf )
IMPLICIT NONE
INTEGER(iwp) :: ind_type !< running index surface tiles
INTEGER(iwp) :: m !< running index surface elements
TYPE(surf_type) :: surf !< treated surfaces
IF ( sun_up .AND. .NOT. average_radiation ) THEN
DO m = 1, surf%ns
!
!-- Loop over surface elements
DO ind_type = 0, SIZE( surf%albedo_type, 2 ) - 1
!
!-- Ocean
IF ( surf%albedo_type(m,ind_type) == 1 ) THEN
surf%rrtm_aldir(m,ind_type) = 0.026_wp / ( cos_zenith**1.7_wp + 0.065_wp ) + &
0.15_wp * ( cos_zenith - 0.1_wp ) * &
( cos_zenith - 0.5_wp ) * ( cos_zenith - 1.0_wp )
surf%rrtm_asdir(m,ind_type) = surf%rrtm_aldir(m,ind_type)
!
!-- Snow
ELSEIF ( surf%albedo_type(m,ind_type) == 16 ) THEN
IF ( cos_zenith < 0.5_wp ) THEN
surf%rrtm_aldir(m,ind_type) = 0.5_wp * ( 1.0_wp - surf%aldif(m,ind_type) ) * &
( ( 3.0_wp / ( 1.0_wp + 4.0_wp * cos_zenith ) ) - &
1.0_wp )
surf%rrtm_asdir(m,ind_type) = 0.5_wp * ( 1.0_wp - surf%asdif(m,ind_type) ) * &
( ( 3.0_wp / ( 1.0_wp + 4.0_wp * cos_zenith ) ) - &
1.0_wp )
surf%rrtm_aldir(m,ind_type) = MIN( 0.98_wp, surf%rrtm_aldir(m,ind_type) )
surf%rrtm_asdir(m,ind_type) = MIN( 0.98_wp, surf%rrtm_asdir(m,ind_type) )
ELSE
surf%rrtm_aldir(m,ind_type) = surf%aldif(m,ind_type)
surf%rrtm_asdir(m,ind_type) = surf%asdif(m,ind_type)
ENDIF
!
!-- Sea ice
ELSEIF ( surf%albedo_type(m,ind_type) == 15 ) THEN
surf%rrtm_aldir(m,ind_type) = surf%aldif(m,ind_type)
surf%rrtm_asdir(m,ind_type) = surf%asdif(m,ind_type)
!
!-- Asphalt
ELSEIF ( surf%albedo_type(m,ind_type) == 17 ) THEN
surf%rrtm_aldir(m,ind_type) = surf%aldif(m,ind_type)
surf%rrtm_asdir(m,ind_type) = surf%asdif(m,ind_type)
!
!-- Bare soil
ELSEIF ( surf%albedo_type(m,ind_type) == 18 ) THEN
surf%rrtm_aldir(m,ind_type) = surf%aldif(m,ind_type)
surf%rrtm_asdir(m,ind_type) = surf%asdif(m,ind_type)
!
!-- Land surfaces
ELSE
SELECT CASE ( surf%albedo_type(m,ind_type) )
!
!-- Surface types with strong zenith dependence
CASE ( 1, 2, 3, 4, 11, 12, 13 )
surf%rrtm_aldir(m,ind_type) = surf%aldif(m,ind_type) * 1.4_wp / &
( 1.0_wp + 0.8_wp * cos_zenith )
surf%rrtm_asdir(m,ind_type) = surf%asdif(m,ind_type) * 1.4_wp / &
( 1.0_wp + 0.8_wp * cos_zenith )
!
!-- Surface types with weak zenith dependence
CASE ( 5, 6, 7, 8, 9, 10, 14 )
surf%rrtm_aldir(m,ind_type) = surf%aldif(m,ind_type) * 1.1_wp / &
( 1.0_wp + 0.2_wp * cos_zenith )
surf%rrtm_asdir(m,ind_type) = surf%asdif(m,ind_type) * 1.1_wp / &
( 1.0_wp + 0.2_wp * cos_zenith )
CASE DEFAULT
END SELECT
ENDIF
!
!-- Diffusive albedo is taken from Table 2
surf%rrtm_aldif(m,ind_type) = surf%aldif(m,ind_type)
surf%rrtm_asdif(m,ind_type) = surf%asdif(m,ind_type)
ENDDO
ENDDO
!
!-- Set albedo in case of average radiation
ELSEIF ( sun_up .AND. average_radiation ) THEN
surf%rrtm_asdir = albedo_urb
surf%rrtm_asdif = albedo_urb
surf%rrtm_aldir = albedo_urb
surf%rrtm_aldif = albedo_urb
!
!-- Darkness
ELSE
surf%rrtm_aldir = 0.0_wp
surf%rrtm_asdir = 0.0_wp
surf%rrtm_aldif = 0.0_wp
surf%rrtm_asdif = 0.0_wp
ENDIF
END SUBROUTINE calc_albedo
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Read sounding data (pressure and temperature) from RADIATION_DATA.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE read_sounding_data
IMPLICIT NONE
INTEGER(iwp) :: id, & !< NetCDF id of input file
id_dim_zrad, & !< pressure level id in the NetCDF file
id_var, & !< NetCDF variable id
k, & !< loop index
nz_snd, & !< number of vertical levels in the sounding data
nz_snd_start, & !< start vertical index for sounding data to be used
nz_snd_end !< end vertical index for souding data to be used
REAL(wp) :: t_surface !< actual surface temperature
REAL(wp), DIMENSION(:), ALLOCATABLE :: hyp_snd_tmp, & !< temporary hydrostatic pressure profile (sounding)
t_snd_tmp !< temporary temperature profile (sounding)
!
!-- In case of updates, deallocate arrays first (sufficient to check one array as the others are
!-- automatically allocated). This is required because nzt_rad might change during the update
IF ( ALLOCATED( hyp_snd ) ) THEN
DEALLOCATE( hyp_snd )
DEALLOCATE( t_snd )
DEALLOCATE( rrtm_play )
DEALLOCATE( rrtm_plev )
DEALLOCATE( rrtm_tlay )
DEALLOCATE( rrtm_tlev )
DEALLOCATE( rrtm_cicewp )
DEALLOCATE( rrtm_cldfr )
DEALLOCATE( rrtm_cliqwp )
DEALLOCATE( rrtm_reice )
DEALLOCATE( rrtm_reliq )
DEALLOCATE( rrtm_lw_taucld )
DEALLOCATE( rrtm_lw_tauaer )
DEALLOCATE( rrtm_lwdflx )
DEALLOCATE( rrtm_lwdflxc )
DEALLOCATE( rrtm_lwuflx )
DEALLOCATE( rrtm_lwuflxc )
DEALLOCATE( rrtm_lwuflx_dt )
DEALLOCATE( rrtm_lwuflxc_dt )
DEALLOCATE( rrtm_lwhr )
DEALLOCATE( rrtm_lwhrc )
DEALLOCATE( rrtm_sw_taucld )
DEALLOCATE( rrtm_sw_ssacld )
DEALLOCATE( rrtm_sw_asmcld )
DEALLOCATE( rrtm_sw_fsfcld )
DEALLOCATE( rrtm_sw_tauaer )
DEALLOCATE( rrtm_sw_ssaaer )
DEALLOCATE( rrtm_sw_asmaer )
DEALLOCATE( rrtm_sw_ecaer )
DEALLOCATE( rrtm_swdflx )
DEALLOCATE( rrtm_swdflxc )
DEALLOCATE( rrtm_swuflx )
DEALLOCATE( rrtm_swuflxc )
DEALLOCATE( rrtm_swhr )
DEALLOCATE( rrtm_swhrc )
DEALLOCATE( rrtm_dirdflux )
DEALLOCATE( rrtm_difdflux )
ENDIF
!
!-- Open file for reading
nc_stat = NF90_OPEN( rrtm_input_file, NF90_NOWRITE, id )
CALL netcdf_handle_error_rad( 'read_sounding_data', 549 )
!
!-- Inquire dimension of z axis and save in nz_snd
nc_stat = NF90_INQ_DIMID( id, 'Pressure', id_dim_zrad )
nc_stat = NF90_INQUIRE_DIMENSION( id, id_dim_zrad, len = nz_snd )
CALL netcdf_handle_error_rad( 'read_sounding_data', 551 )
!
!-- Allocate temporary array for storing pressure data
ALLOCATE( hyp_snd_tmp(1:nz_snd) )
hyp_snd_tmp = 0.0_wp
!-- Read pressure from file
nc_stat = NF90_INQ_VARID( id, 'Pressure', id_var )
nc_stat = NF90_GET_VAR( id, id_var, hyp_snd_tmp(:), start = (/1/), count = (/nz_snd/) )
CALL netcdf_handle_error_rad( 'read_sounding_data', 552 )
!
!-- Allocate temporary array for storing temperature data
ALLOCATE( t_snd_tmp(1:nz_snd) )
t_snd_tmp = 0.0_wp
!
!-- Read temperature from file
nc_stat = NF90_INQ_VARID( id, 'ReferenceTemperature', id_var )
nc_stat = NF90_GET_VAR( id, id_var, t_snd_tmp(:), start = (/1/), count = (/nz_snd/) )
CALL netcdf_handle_error_rad( 'read_sounding_data', 553 )
!
!-- Calculate start of sounding data
nz_snd_start = nz_snd + 1
nz_snd_end = nz_snd + 1
!
!-- Start filling vertical dimension at 10hPa above the model domain (hyp is in Pa, hyp_snd in hPa).
DO k = 1, nz_snd
IF ( hyp_snd_tmp(k) < ( hyp(nzt+1) - 1000.0_wp) * 0.01_wp ) THEN
nz_snd_start = k
EXIT
END IF
END DO
IF ( nz_snd_start <= nz_snd ) THEN
nz_snd_end = nz_snd
END IF
!
!-- Calculate of total grid points for RRTMG calculations
nzt_rad = nzt + nz_snd_end - nz_snd_start + 1
!
!-- Save data above LES domain in hyp_snd, t_snd
ALLOCATE( hyp_snd(nzb+1:nzt_rad) )
ALLOCATE( t_snd(nzb+1:nzt_rad) )
hyp_snd = 0.0_wp
t_snd = 0.0_wp
hyp_snd(nzt+2:nzt_rad) = hyp_snd_tmp(nz_snd_start+1:nz_snd_end)
t_snd(nzt+2:nzt_rad) = t_snd_tmp(nz_snd_start+1:nz_snd_end)
nc_stat = NF90_CLOSE( id )
!
!-- Calculate pressure levels on zu and zw grid. Sounding data is added at top of the LES domain.
!-- This routine does not consider horizontal or vertical variability of pressure and temperature
ALLOCATE( rrtm_play(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_plev(0:0,nzb+1:nzt_rad+2) )
t_surface = pt_surface * exner(nzb)
DO k = nzb+1, nzt+1
rrtm_play(0,k) = hyp(k) * 0.01_wp
rrtm_plev(0,k) = barometric_formula(zw(k-1), pt_surface * exner(nzb), surface_pressure )
ENDDO
DO k = nzt+2, nzt_rad
rrtm_play(0,k) = hyp_snd(k)
rrtm_plev(0,k) = 0.5_wp * ( rrtm_play(0,k) + rrtm_play(0,k-1) )
ENDDO
rrtm_plev(0,nzt_rad+1) = MAX( 0.5 * hyp_snd(nzt_rad), 1.5 * hyp_snd(nzt_rad) - 0.5 * &
hyp_snd(nzt_rad-1) )
rrtm_plev(0,nzt_rad+2) = MIN( 1.0E-4_wp, 0.25_wp * rrtm_plev(0,nzt_rad+1) )
rrtm_play(0,nzt_rad+1) = 0.5 * rrtm_plev(0,nzt_rad+1)
!
!-- Calculate temperature/humidity levels at top of the LES domain.
!-- Currently, the temperature is taken from sounding data (might lead to a temperature jump at
!-- interface. To do: Humidity is currently not calculated above the LES domain.
ALLOCATE( rrtm_tlay(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_tlev(0:0,nzb+1:nzt_rad+2) )
DO k = nzt+8, nzt_rad
rrtm_tlay(0,k) = t_snd(k)
ENDDO
rrtm_tlay(0,nzt_rad+1) = 2.0_wp * rrtm_tlay(0,nzt_rad) - rrtm_tlay(0,nzt_rad-1)
DO k = nzt+9, nzt_rad+1
rrtm_tlev(0,k) = rrtm_tlay(0,k-1) + ( rrtm_tlay(0,k) - rrtm_tlay(0,k-1) ) / &
( rrtm_play(0,k) - rrtm_play(0,k-1) ) * &
( rrtm_plev(0,k) - rrtm_play(0,k-1) )
ENDDO
rrtm_tlev(0,nzt_rad+2) = 2.0_wp * rrtm_tlay(0,nzt_rad+1) - rrtm_tlev(0,nzt_rad)
!
!-- Allocate remaining RRTMG arrays
ALLOCATE( rrtm_cicewp(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_cldfr(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_cliqwp(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_reice(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_reliq(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_lw_taucld(1:nbndlw+1,0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_lw_tauaer(0:0,nzb+1:nzt_rad+1,1:nbndlw+1) )
ALLOCATE( rrtm_sw_taucld(1:nbndsw+1,0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_ssacld(1:nbndsw+1,0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_asmcld(1:nbndsw+1,0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_fsfcld(1:nbndsw+1,0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_sw_tauaer(0:0,nzb+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_ssaaer(0:0,nzb+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_asmaer(0:0,nzb+1:nzt_rad+1,1:nbndsw+1) )
ALLOCATE( rrtm_sw_ecaer(0:0,nzb+1:nzt_rad+1,1:naerec+1) )
!
!-- The ice phase is currently not considered in PALM
rrtm_cicewp = 0.0_wp
rrtm_reice = 0.0_wp
!
!-- Set other parameters (move to NAMELIST parameters in the future)
rrtm_lw_tauaer = 0.0_wp
rrtm_lw_taucld = 0.0_wp
rrtm_sw_taucld = 0.0_wp
rrtm_sw_ssacld = 0.0_wp
rrtm_sw_asmcld = 0.0_wp
rrtm_sw_fsfcld = 0.0_wp
rrtm_sw_tauaer = 0.0_wp
rrtm_sw_ssaaer = 0.0_wp
rrtm_sw_asmaer = 0.0_wp
rrtm_sw_ecaer = 0.0_wp
ALLOCATE( rrtm_swdflx(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_swuflx(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_swhr(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_swuflxc(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_swdflxc(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_swhrc(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_dirdflux(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_difdflux(0:0,nzb:nzt_rad+1) )
rrtm_swdflx = 0.0_wp
rrtm_swuflx = 0.0_wp
rrtm_swhr = 0.0_wp
rrtm_swuflxc = 0.0_wp
rrtm_swdflxc = 0.0_wp
rrtm_swhrc = 0.0_wp
rrtm_dirdflux = 0.0_wp
rrtm_difdflux = 0.0_wp
ALLOCATE( rrtm_lwdflx(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_lwuflx(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_lwhr(0:0,nzb+1:nzt_rad+1) )
ALLOCATE( rrtm_lwuflxc(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_lwdflxc(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_lwhrc(0:0,nzb+1:nzt_rad+1) )
rrtm_lwdflx = 0.0_wp
rrtm_lwuflx = 0.0_wp
rrtm_lwhr = 0.0_wp
rrtm_lwuflxc = 0.0_wp
rrtm_lwdflxc = 0.0_wp
rrtm_lwhrc = 0.0_wp
ALLOCATE( rrtm_lwuflx_dt(0:0,nzb:nzt_rad+1) )
ALLOCATE( rrtm_lwuflxc_dt(0:0,nzb:nzt_rad+1) )
rrtm_lwuflx_dt = 0.0_wp
rrtm_lwuflxc_dt = 0.0_wp
END SUBROUTINE read_sounding_data
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Read trace gas data from file and convert into trace gas paths / volume mixing ratios. If a
!> user-defined input file is provided it needs to follow the convections used in RRTMG (see
!> respective netCDF files shipped with RRTMG)
!--------------------------------------------------------------------------------------------------!
SUBROUTINE read_trace_gas_data
USE rrsw_ncpar
IMPLICIT NONE
INTEGER(iwp), PARAMETER :: num_trace_gases = 10 !< number of trace gases (absorbers)
CHARACTER(LEN=5), DIMENSION(num_trace_gases), PARAMETER :: & !< trace gas names
trace_names = (/'O3 ', 'CO2 ', 'CH4 ', 'N2O ', 'O2 ', &
'CFC11', 'CFC12', 'CFC22', 'CCL4 ', 'H2O '/)
INTEGER(iwp) :: id, & !< NetCDF id
k, & !< loop index
m, & !< loop index
n, & !< loop index
nabs, & !< number of absorbers
np, & !< number of pressure levels
id_abs, & !< NetCDF id of the respective absorber
id_dim, & !< NetCDF id of asborber's dimension
id_var !< NetCDf id ot the absorber
REAL(wp) :: p_mls_l, & !< pressure lower limit for interpolation
p_mls_u, & !< pressure upper limit for interpolation
p_wgt_l, & !< pressure weight lower limit for interpolation
p_wgt_u, & !< pressure weight upper limit for interpolation
p_mls_m !< mean pressure between upper and lower limits
REAL(wp), DIMENSION(:), ALLOCATABLE :: p_mls, & !< pressure levels for the absorbers
rrtm_play_tmp, & !< temporary array for pressure zu-levels
rrtm_plev_tmp, & !< temporary array for pressure zw-levels
trace_path_tmp !< temporary array for storing trace gas path data
REAL(wp), DIMENSION(:,:), ALLOCATABLE :: trace_mls, & !< array for storing the absorber amounts
trace_mls_path, & !< array for storing trace gas path data
trace_mls_tmp !< temporary array for storing trace gas data
!
!-- In case of updates, deallocate arrays first (sufficient to check one array as the others are
!-- automatically allocated)
IF ( ALLOCATED( rrtm_o3vmr ) ) THEN
DEALLOCATE( rrtm_o3vmr )
DEALLOCATE( rrtm_co2vmr )
DEALLOCATE( rrtm_ch4vmr )
DEALLOCATE( rrtm_n2ovmr )
DEALLOCATE( rrtm_o2vmr )
DEALLOCATE( rrtm_cfc11vmr )
DEALLOCATE( rrtm_cfc12vmr )
DEALLOCATE( rrtm_cfc22vmr )
DEALLOCATE( rrtm_ccl4vmr )
DEALLOCATE( rrtm_h2ovmr )
ENDIF
!
!-- Allocate trace gas profiles
ALLOCATE( rrtm_o3vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_co2vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_ch4vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_n2ovmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_o2vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_cfc11vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_cfc12vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_cfc22vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_ccl4vmr(0:0,1:nzt_rad+1) )
ALLOCATE( rrtm_h2ovmr(0:0,1:nzt_rad+1) )
!
!-- Open file for reading
nc_stat = NF90_OPEN( rrtm_input_file, NF90_NOWRITE, id )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 549 )
!
!-- Inquire dimension ids and dimensions
nc_stat = NF90_INQ_DIMID( id, 'Pressure', id_dim )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
nc_stat = NF90_INQUIRE_DIMENSION( id, id_dim, len = np)
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
nc_stat = NF90_INQ_DIMID( id, 'Absorber', id_dim )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
nc_stat = NF90_INQUIRE_DIMENSION( id, id_dim, len = nabs )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
!
!-- Allocate pressure, and trace gas arrays
ALLOCATE( p_mls(1:np) )
ALLOCATE( trace_mls(1:num_trace_gases,1:np) )
ALLOCATE( trace_mls_tmp(1:nabs,1:np) )
nc_stat = NF90_INQ_VARID( id, 'Pressure', id_var )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
nc_stat = NF90_GET_VAR( id, id_var, p_mls )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
nc_stat = NF90_INQ_VARID( id, 'AbsorberAmountMLS', id_var )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
nc_stat = NF90_GET_VAR( id, id_var, trace_mls_tmp )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 550 )
!
!-- Write absorber amounts (mls) to trace_mls
DO n = 1, num_trace_gases
CALL getAbsorberIndex( TRIM( trace_names(n) ), id_abs )
trace_mls(n,1:np) = trace_mls_tmp(id_abs,1:np)
!
!-- Replace missing values by zero
WHERE ( trace_mls(n,:) > 2.0_wp )
trace_mls(n,:) = 0.0_wp
END WHERE
END DO
DEALLOCATE( trace_mls_tmp )
nc_stat = NF90_CLOSE( id )
CALL netcdf_handle_error_rad( 'read_trace_gas_data', 551 )
!
!-- Add extra pressure level for calculations of the trace gas paths
ALLOCATE( rrtm_play_tmp(1:nzt_rad+1) )
ALLOCATE( rrtm_plev_tmp(1:nzt_rad+2) )
rrtm_play_tmp(1:nzt_rad) = rrtm_play(0,1:nzt_rad)
rrtm_plev_tmp(1:nzt_rad+1) = rrtm_plev(0,1:nzt_rad+1)
rrtm_play_tmp(nzt_rad+1) = rrtm_plev(0,nzt_rad+1) * 0.5_wp
rrtm_plev_tmp(nzt_rad+2) = MIN( 1.0E-4_wp, 0.25_wp * rrtm_plev(0,nzt_rad+1) )
!
!-- Calculate trace gas path (zero at surface) with interpolation to the sounding levels
ALLOCATE( trace_mls_path(1:nzt_rad+2,1:num_trace_gases) )
trace_mls_path(nzb+1,:) = 0.0_wp
DO k = nzb+2, nzt_rad+2
DO m = 1, num_trace_gases
trace_mls_path(k,m) = trace_mls_path(k-1,m)
!
!-- When the pressure level is higher than the trace gas pressure level, assume that
IF ( rrtm_plev_tmp(k-1) > p_mls(1) ) THEN
trace_mls_path(k,m) = trace_mls_path(k,m) + trace_mls(m,1) * ( rrtm_plev_tmp(k-1) - &
MAX( p_mls(1), rrtm_plev_tmp(k) ) ) / g
ENDIF
!
!-- Integrate for each sounding level from the contributing p_mls levels
DO n = 2, np
!
!-- Limit p_mls so that it is within the model level
p_mls_u = MIN( rrtm_plev_tmp(k-1), MAX( rrtm_plev_tmp(k), p_mls(n) ) )
p_mls_l = MIN( rrtm_plev_tmp(k-1), MAX( rrtm_plev_tmp(k), p_mls(n-1) ) )
IF ( p_mls_l > p_mls_u ) THEN
!
!-- Calculate weights for interpolation
p_mls_m = 0.5_wp * ( p_mls_l + p_mls_u )
p_wgt_u = ( p_mls(n-1) - p_mls_m ) / ( p_mls(n-1) - p_mls(n) )
p_wgt_l = ( p_mls_m - p_mls(n) ) / ( p_mls(n-1) - p_mls(n) )
!
!-- Add level to trace gas path
trace_mls_path(k,m) = trace_mls_path(k,m) + ( p_wgt_u * trace_mls(m,n) + &
p_wgt_l * trace_mls(m,n-1) ) * (p_mls_l - p_mls_u) / g
ENDIF
ENDDO
IF ( rrtm_plev_tmp(k) < p_mls(np) ) THEN
trace_mls_path(k,m) = trace_mls_path(k,m) + trace_mls(m,np) * &
( MIN( rrtm_plev_tmp(k-1), p_mls(np) ) - rrtm_plev_tmp(k) ) / g
ENDIF
ENDDO
ENDDO
!
!-- Prepare trace gas path profiles
ALLOCATE( trace_path_tmp(1:nzt_rad+1) )
DO m = 1, num_trace_gases
trace_path_tmp(1:nzt_rad+1) = ( trace_mls_path(2:nzt_rad+2,m) - &
trace_mls_path(1:nzt_rad+1,m) ) * g / &
( rrtm_plev_tmp(1:nzt_rad+1) - rrtm_plev_tmp(2:nzt_rad+2) )
!
!-- Save trace gas paths to the respective arrays
SELECT CASE ( TRIM( trace_names(m) ) )
CASE ( 'O3' )
rrtm_o3vmr(0,:) = trace_path_tmp(:)
CASE ( 'CO2' )
rrtm_co2vmr(0,:) = trace_path_tmp(:)
CASE ( 'CH4' )
rrtm_ch4vmr(0,:) = trace_path_tmp(:)
CASE ( 'N2O' )
rrtm_n2ovmr(0,:) = trace_path_tmp(:)
CASE ( 'O2' )
rrtm_o2vmr(0,:) = trace_path_tmp(:)
CASE ( 'CFC11' )
rrtm_cfc11vmr(0,:) = trace_path_tmp(:)
CASE ( 'CFC12' )
rrtm_cfc12vmr(0,:) = trace_path_tmp(:)
CASE ( 'CFC22' )
rrtm_cfc22vmr(0,:) = trace_path_tmp(:)
CASE ( 'CCL4' )
rrtm_ccl4vmr(0,:) = trace_path_tmp(:)
CASE ( 'H2O' )
rrtm_h2ovmr(0,:) = trace_path_tmp(:)
CASE DEFAULT
END SELECT
ENDDO
DEALLOCATE( trace_path_tmp )
DEALLOCATE( trace_mls_path )
DEALLOCATE( rrtm_play_tmp )
DEALLOCATE( rrtm_plev_tmp )
DEALLOCATE( trace_mls )
DEALLOCATE( p_mls )
END SUBROUTINE read_trace_gas_data
SUBROUTINE netcdf_handle_error_rad( routine_name, errno )
USE control_parameters, &
ONLY: message_string
USE NETCDF
USE pegrid
IMPLICIT NONE
CHARACTER(LEN=6) :: message_identifier !<
CHARACTER(LEN=*) :: routine_name !<
INTEGER(iwp) :: errno !<
IF ( nc_stat /= NF90_NOERR ) THEN
WRITE( message_identifier, '(''NC'',I4.4)' ) errno
message_string = TRIM( NF90_STRERROR( nc_stat ) )
CALL message( routine_name, message_identifier, 2, 2, 0, 6, 1 )
ENDIF
END SUBROUTINE netcdf_handle_error_rad
#endif
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Calculate temperature tendency due to radiative cooling/heating.
!> Cache-optimized version.
!--------------------------------------------------------------------------------------------------!
#if defined( __rrtmg )
SUBROUTINE radiation_tendency_ij( i, j, tend )
IMPLICIT NONE
INTEGER(iwp) :: i, j, k !< loop indices
REAL(wp), DIMENSION(nzb:nzt+1,nysg:nyng,nxlg:nxrg) :: tend !< pt tendency term
IF ( radiation_scheme == 'rrtmg' ) THEN
!
!-- Calculate tendency based on heating rate
DO k = nzb+1, nzt+1
tend(k,j,i) = tend(k,j,i) + ( rad_lw_hr(k,j,i) + rad_sw_hr(k,j,i) ) * &
d_exner(k) * d_seconds_hour * &
MERGE( 1.0_wp, 0.0_wp, BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDIF
END SUBROUTINE radiation_tendency_ij
#endif
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Calculate temperature tendency due to radiative cooling/heating.
!> Vector-optimized version
!--------------------------------------------------------------------------------------------------!
#if defined( __rrtmg )
SUBROUTINE radiation_tendency( tend )
IMPLICIT NONE
INTEGER(iwp) :: i, j, k !< loop indices
REAL(wp), DIMENSION(nzb:nzt+1,nysg:nyng,nxlg:nxrg) :: tend !< pt tendency term
IF ( radiation_scheme == 'rrtmg' ) THEN
!
!-- Calculate tendency based on heating rate
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb+1, nzt+1
tend(k,j,i) = tend(k,j,i) + ( rad_lw_hr(k,j,i) + rad_sw_hr(k,j,i) ) * &
d_exner(k) * d_seconds_hour * &
MERGE( 1.0_wp, 0.0_wp, BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ENDIF
END SUBROUTINE radiation_tendency
#endif
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Radiative Transfer Model (RTM) version 3.0 for modelling of radiation interactions within urban
!> canopy or inside of surface layer in complex terrain. This subroutine calculates interaction of
!> the solar SW and LW radiation with urban and land surfaces and updates all surface heatfluxes.
!> It also calculates interactions of SW and LW radiation with resolved plant canopy and calculates
!> the corresponding plant canopy heat fluxes. The subroutine also models spatial and temporal
!> distribution of Mean Radiant Temperature (MRT). The resulting values are provided to other
!> PALM-4U modules (RRTMG, USM, LSM, PCM and BIO).
!>
!> The new version 3.0 was radically rewritten from version 1.0. The most significant changes
!> include new angular discretization scheme, redesigned and significantly optimized raytracing
!> scheme, new processes included in modelling (e.g. intetrations of LW radiation with PC),
!> integrated calculation of Mean Radiant Temperature (MRT), and improved and enhanced output and
!> debug capabilities. This new version significantly improves effectivity of the paralelization and
!> the scalability of the model and allows simulation of extensive domain with appropriate HPC
!> resources.
!>
!> More info about RTM v.1.0. see:
!> Resler et al., GMD. 2017, https://doi.org/10.5194/gmd-10-3635-2017
!> Info about RTM v. 3.0 see: Krc et al. 2020 (to appear in GMD),
!> Maronga et al., GMDD 2019, https://doi.org/10.5194/gmd-2019-103
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_interaction
USE control_parameters, &
ONLY: rotation_angle
IMPLICIT NONE
INTEGER(iwp) :: i, j, k, kk, d, refstep, m, mm, l !<
INTEGER(iwp) :: isurf, isurfsrc, isvf, icsf, ipcgb !<
INTEGER(iwp) :: imrt, imrtf !<
INTEGER(iwp) :: isd !< solar direction number
INTEGER(iwp) :: pc_box_dimshift !< transform for best accuracy
REAL(wp) :: asrc !< area of source face
REAL(wp) :: pcrad !< irradiance from plant canopy
REAL(wp) :: pc_box_area, pc_abs_frac, pc_abs_eff !<
REAL(wp) :: temp !< temporary variable for calculation
REAL(wp), DIMENSION(3) :: sunorig !< grid rotated solar direction unit vector (zyx)
REAL(wp), DIMENSION(3) :: sunorig_grid !< grid squashed solar direction unit vector (zyx)
REAL(wp), DIMENSION(3,3) :: mrot !< grid rotation matrix (zyx)
REAL(wp), DIMENSION(0:nsurf_type) :: costheta !< direct irradiance factor of solar angle
REAL(wp), DIMENSION(3,0:nsurf_type) :: vnorm !< face direction normal vectors (zyx)
REAL(wp), DIMENSION(nz_urban_b:nz_urban_t) :: pchf_prep !< precalculated factor for canopy temperature tendency
!
!-- Variables for coupling the radiation modle (e.g. RRTMG) and RTM
REAL(wp) :: area_norm !< reference horizontal area of domain in all processor
REAL(wp) :: pabsswl !< total absorbed SW radiation energy in local processor (W)
REAL(wp) :: pabssw !< total absorbed SW radiation energy in all processors (W)
REAL(wp) :: pabslwl !< total absorbed LW radiation energy in local processor (W)
REAL(wp) :: pabslw !< total absorbed LW radiation energy in all processors (W)
REAL(wp) :: pemitlwl !< total emitted LW radiation energy in all processors (W)
REAL(wp) :: pemitlw !< total emitted LW radiation energy in all processors (W)
REAL(wp) :: pinswl !< total received SW radiation energy in local processor (W)
REAL(wp) :: pinsw !< total received SW radiation energy in all processor (W)
REAL(wp) :: pinlwl !< total received LW radiation energy in local processor (W)
REAL(wp) :: pinlw !< total received LW radiation energy in all processor (W)
REAL(wp) :: pabs_surf_lwdifl !< total absorbed LW radiation in surfaces from sky in local processor (W)
REAL(wp) :: pabs_surf_lwdif !< total absorbed LW radiation in surfaces from sky in all processors (W)
REAL(wp) :: pabs_pc_lwdifl !< total absorbed LW radiation in plant canopy from sky in local processor (W)
REAL(wp) :: pabs_pc_lwdif !< total absorbed LW radiation in plant canopy from sky in all processors (W)
!
!-- Rotation related variables
REAL(wp) :: cos_rot !< cosine of rotation_angle
REAL(wp) :: sun_direct_factor !< factor for direct normal radiation from direct horizontal
REAL(wp) :: sin_rot !< sine of rotation_angle
REAL(wp) :: solar_azim !< solar azimuth in rotated model coordinates
#if defined( __parallel )
REAL(wp), DIMENSION(1:7) :: combine_allreduce !< dummy array used to combine several MPI_ALLREDUCE calls
REAL(wp), DIMENSION(1:7) :: combine_allreduce_l !< dummy array used to combine several MPI_ALLREDUCE calls
#endif
IF ( debug_output_timestep ) THEN
WRITE( debug_string, * ) 'radiation_interaction', time_since_reference_point
CALL debug_message( debug_string, 'start' )
ENDIF
IF ( plant_canopy ) THEN
pchf_prep(:) = r_d * exner(nz_urban_b:nz_urban_t) / ( c_p * hyp(nz_urban_b:nz_urban_t) * &
dx * dy * dz(1) ) !< equals to 1 / (rho * c_p * Vbox * T)
ENDIF
sun_direction = .TRUE.
CALL get_date_time( time_since_reference_point, day_of_year=day_of_year, &
second_of_day = second_of_day )
CALL calc_zenith( day_of_year, second_of_day ) !< Required also for diffusion radiation
!
!-- Prepare rotated normal vectors and irradiance factor
sin_rot = SIN( rotation_angle * pi / 180.0_wp )
cos_rot = COS( rotation_angle * pi / 180.0_wp )
vnorm(1,:) = kdir(:)
vnorm(2,:) = jdir(:)
vnorm(3,:) = idir(:)
mrot(1, :) = (/ 1._wp, 0._wp, 0._wp /)
mrot(2, :) = (/ 0._wp, cos_rot, sin_rot /)
mrot(3, :) = (/ 0._wp, -sin_rot, cos_rot /)
sunorig = (/ cos_zenith, sun_dir_lat, sun_dir_lon /)
sunorig = MATMUL( mrot, sunorig )
!
!-- Direct irradiance factor of solar angle, avoid negative value to prevent negative direct SW values
DO d = 0, nsurf_type
costheta(d) = MAX( DOT_PRODUCT( sunorig, vnorm(:,d) ), 0.0_wp )
ENDDO
IF ( cos_zenith > 0 ) THEN
!
!-- Now we will "squash" the sunorig vector by grid box size in each dimension, so that this
!-- new direction vector will allow us to traverse the ray path within grid coordinates
!-- directly
sunorig_grid = (/ sunorig(1) / dz(1), sunorig(2) / dy, sunorig(3) / dx /)
! sunorig_grid = sunorig_grid / norm2(sunorig_grid)
sunorig_grid = sunorig_grid / SQRT( SUM( sunorig_grid**2 ) )
IF ( npcbl > 0 ) THEN
!
!-- Precompute effective box depth with prototype Leaf Area Density
pc_box_dimshift = MAXLOC( ABS( sunorig ), 1) - 1
CALL box_absorb( CSHIFT( (/ dz(1), dy, dx/), pc_box_dimshift ), 60, prototype_lad, &
CSHIFT( ABS( sunorig ), pc_box_dimshift ), pc_box_area, pc_abs_frac )
pc_box_area = pc_box_area * ABS( sunorig( pc_box_dimshift + 1 ) / sunorig(1) )
pc_abs_eff = LOG( 1._wp - pc_abs_frac ) / prototype_lad
ENDIF
ENDIF
!
!-- Split downwelling shortwave radiation into a diffuse and a direct part. Note, if radiation
!-- scheme is RRTMG or diffuse radiation is externally prescribed, this is not required. Please
!-- note, in case of external radiation, the clear-sky model is applied during spinup, so that
!-- radiation needs to be split also in this case.
IF ( radiation_scheme == 'constant' .OR. radiation_scheme == 'clear-sky' .OR. &
( radiation_scheme == 'external' .AND. .NOT. rad_sw_in_dif_f%from_file ) .OR. &
( radiation_scheme == 'external' .AND. time_since_reference_point < 0.0_wp ) ) THEN
CALL calc_diffusion_radiation
ENDIF
!
!-- First pass of radiation interaction:
!-- 1) direct and diffuse irradiance
!-- 2) thermal emissions
!
!-- Initialize relavant surface flux arrays and radiation energy sum
!-- Surface flux
surfinswdir = 0.0_wp
surfins = 0.0_wp
surfinl = 0.0_wp
surfoutsl(:) = 0.0_wp
surfoutll(:) = 0.0_wp
IF ( nmrtbl > 0 ) THEN
mrtinsw(:) = 0.0_wp
mrtinlw(:) = 0.0_wp
ENDIF
surfinlg(:) = 0.0_wp
!
!-- Radiation energy sum
pinlwl = 0.0_wp
pinswl = 0.0_wp
pemitlwl = 0.0_wp
pabsswl = 0.0_wp
pabslwl = 0.0_wp
pabs_surf_lwdifl = 0.0_wp
pabs_pc_lwdifl = 0.0_wp
!
!-- Set up thermal radiation from surfaces
mm = 1
!-- Following code depends on the order of the execution. Do not parallelize by OpenMP!
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Horizontal walls
DO l = 0, 1
!-- Urban
DO m = surf_usm_h(l)%start_index(j,i), surf_usm_h(l)%end_index(j,i)
surfoutll(mm) = SUM( surf_usm_h(l)%frac(m,:) * surf_usm_h(l)%emissivity(m,:) ) * &
sigma_sb * surf_usm_h(l)%pt_surface(m)**4
albedo_surf(mm) = SUM( surf_usm_h(l)%frac(m,:) * surf_usm_h(l)%albedo(m,:) )
emiss_surf(mm) = SUM( surf_usm_h(l)%frac(m,:) * surf_usm_h(l)%emissivity(m,:) )
mm = mm + 1
ENDDO
!
!-- Land
DO m = surf_lsm_h(l)%start_index(j,i), surf_lsm_h(l)%end_index(j,i)
surfoutll(mm) = SUM( surf_lsm_h(l)%frac(m,:) * surf_lsm_h(l)%emissivity(m,:) ) * &
sigma_sb * surf_lsm_h(l)%pt_surface(m)**4
albedo_surf(mm) = SUM( surf_lsm_h(l)%frac(m,:) * surf_lsm_h(l)%albedo(m,:) )
emiss_surf(mm) = SUM( surf_lsm_h(l)%frac(m,:) * surf_lsm_h(l)%emissivity(m,:) )
mm = mm + 1
ENDDO
ENDDO
!
!-- Vertical walls
DO l = 0, 3
!
!-- Urban
DO m = surf_usm_v(l)%start_index(j,i), surf_usm_v(l)%end_index(j,i)
surfoutll(mm) = SUM( surf_usm_v(l)%frac(m,:) * surf_usm_v(l)%emissivity(m,:) ) * &
sigma_sb * surf_usm_v(l)%pt_surface(m)**4
albedo_surf(mm) = SUM( surf_usm_v(l)%frac(m,:) * surf_usm_v(l)%albedo(m,:) )
emiss_surf(mm) = SUM( surf_usm_v(l)%frac(m,:) * surf_usm_v(l)%emissivity(m,:) )
mm = mm + 1
ENDDO
!
!-- Land
DO m = surf_lsm_v(l)%start_index(j,i), surf_lsm_v(l)%end_index(j,i)
surfoutll(mm) = SUM( surf_lsm_v(l)%frac(m,:) * surf_lsm_v(l)%emissivity(m,:) ) * &
sigma_sb * surf_lsm_v(l)%pt_surface(m)**4
albedo_surf(mm) = SUM( surf_lsm_v(l)%frac(m,:) * surf_lsm_v(l)%albedo(m,:) )
emiss_surf(mm) = SUM( surf_lsm_v(l)%frac(m,:) * surf_lsm_v(l)%emissivity(m,:) )
mm = mm + 1
ENDDO
ENDDO
ENDDO
ENDDO
IF ( trace_fluxes_above >= 0.0_wp ) THEN
CALL radiation_print_debug_surf( 'surfoutll before initial pass', surfoutll )
CALL radiation_print_debug_horz( 'rad_lw_in_diff before initial pass', rad_lw_in_diff )
CALL radiation_print_debug_horz( 'rad_sw_in_diff before initial pass', rad_sw_in_diff )
CALL radiation_print_debug_horz( 'rad_sw_in_dir before initial pass', rad_sw_in_dir )
ENDIF
#if defined( __parallel )
!
!-- Might be optimized and gather only values relevant for current processor
CALL MPI_ALLGATHERV( surfoutll, nsurfl, MPI_REAL, surfoutl, nsurfs, surfstart, MPI_REAL, &
comm2d, ierr ) ! nsurf global
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHERV1:', ierr, SIZE( surfoutll ), nsurfl, SIZE( surfoutl ),&
nsurfs, surfstart
FLUSH( 9 )
ENDIF
#else
surfoutl(:) = surfoutll(:) ! nsurf global
#endif
IF ( surface_reflections) THEN
!$OMP PARALLEL DO PRIVATE (i, j, k, isvf, isurf, isurfsrc, temp) SCHEDULE (STATIC)
DO isvf = 1, nsvfl
isurf = svfsurf(1, isvf)
k = surfl(iz, isurf)
j = surfl(iy, isurf)
i = surfl(ix, isurf)
isurfsrc = svfsurf(2, isvf)
!
!-- For surface-to-surface factors we calculate thermal radiation in 1st pass
IF ( plant_lw_interact ) THEN
temp = svf(1,isvf) * svf(2,isvf) * surfoutl(isurfsrc)
ELSE
temp = svf(1,isvf) * surfoutl(isurfsrc)
ENDIF
!$OMP ATOMIC
surfinl(isurf) = surfinl(isurf) + temp
ENDDO
ENDIF
!
!-- Diffuse radiation using sky view factor
!$OMP PARALLEL DO PRIVATE (i, j, d, isurf) REDUCTION(+:pinswl, pinlwl) SCHEDULE (STATIC)
DO isurf = 1, nsurfl
j = surfl(iy, isurf)
i = surfl(ix, isurf)
d = surfl(id, isurf)
surfinswdif(isurf) = rad_sw_in_diff(j,i) * skyvft(isurf)
!
!-- Update received SW energy for RTM coupling
pinswl = pinswl + surfinswdif(isurf) * facearea(d)
IF ( plant_lw_interact ) THEN
surfinlwdif(isurf) = rad_lw_in_diff(j,i) * skyvft(isurf)
ELSE
surfinlwdif(isurf) = rad_lw_in_diff(j,i) * skyvf(isurf)
ENDIF
!
!-- Update received LW energy for RTM coupling
pinlwl = pinlwl + surfinlwdif(isurf) * facearea(d)
ENDDO
!
!-- MRT diffuse irradiance
!$OMP PARALLEL DO PRIVATE (i, j, imrt) SCHEDULE (STATIC)
DO imrt = 1, nmrtbl
j = mrtbl(iy, imrt)
i = mrtbl(ix, imrt)
mrtinsw(imrt) = mrtskyt(imrt) * rad_sw_in_diff(j,i)
mrtinlw(imrt) = mrtsky(imrt) * rad_lw_in_diff(j,i)
ENDDO
!
!-- Direct radiation
IF ( cos_zenith > 0 ) THEN
!
!-- To avoid numerical instability near horizon depending on what direct radiation is used
!-- (slightly different zenith angle, considering circumsolar etc.), we use a minimum value for
!-- cos_zenith
sun_direct_factor = 1._wp / MAX( min_stable_coszen, cos_zenith )
!
!-- Identify solar direction vector (discretized number) (1)
solar_azim = ATAN2( sun_dir_lon, sun_dir_lat ) * ( 180.0_wp / pi ) - rotation_angle
j = FLOOR( ACOS( cos_zenith ) / pi * REAL( raytrace_discrete_elevs, KIND = wp ) )
i = MODULO( NINT( solar_azim / 360.0_wp * REAL( raytrace_discrete_azims, KIND = wp ) &
- 0.5_wp, iwp ), raytrace_discrete_azims )
isd = dsidir_rev(j, i)
!
!-- TODO: check if isd = -1 to report that this solar position is not precalculated
!$OMP PARALLEL DO PRIVATE (i, j, d, isurf) REDUCTION(+:pinswl) SCHEDULE (STATIC)
DO isurf = 1, nsurfl
j = surfl(iy, isurf)
i = surfl(ix, isurf)
d = surfl(id, isurf)
surfinswdir(isurf) = rad_sw_in_dir(j,i) * costheta(surfl(id, isurf)) * &
dsitrans(isurf, isd) * sun_direct_factor
!
!-- Update received SW energy for RTM coupling
pinswl = pinswl + surfinswdir(isurf) * facearea(d)
ENDDO
!
!-- MRT direct irradiance
!$OMP PARALLEL DO PRIVATE (i, j, imrt) SCHEDULE (STATIC)
DO imrt = 1, nmrtbl
j = mrtbl(iy, imrt)
i = mrtbl(ix, imrt)
mrtinsw(imrt) = mrtinsw(imrt) + mrtdsit(imrt, isd) * rad_sw_in_dir(j,i) * &
sun_direct_factor / 4.0_wp ! Normal to sphere
ENDDO
ENDIF
!
!-- MRT first pass thermal
!$OMP PARALLEL DO PRIVATE (imrtf, imrt, isurfsrc, temp) SCHEDULE (STATIC)
DO imrtf = 1, nmrtf
imrt = mrtfsurf(1, imrtf)
isurfsrc = mrtfsurf(2, imrtf)
temp = mrtf(imrtf) * surfoutl(isurfsrc)
!$OMP ATOMIC
mrtinlw(imrt) = mrtinlw(imrt) + temp
ENDDO
!
!-- Absorption in each local plant canopy grid box from the first atmospheric pass of radiation
IF ( npcbl > 0 ) THEN
pcbinswdir(:) = 0.0_wp
pcbinswdif(:) = 0.0_wp
pcbinlw(:) = 0.0_wp
!$OMP PARALLEL DO PRIVATE (icsf, ipcgb, i, j, k, kk, isurfsrc, pc_abs_frac, pcrad, asrc) &
!$OMP& REDUCTION(+:pinswl, pinlwl, pabslwl, pemitlwl, pabs_pc_lwdifl, pcbinlw, surfinlg) SCHEDULE (STATIC)
DO icsf = 1, ncsfl
ipcgb = csfsurf(1, icsf)
i = pcbl(ix,ipcgb)
j = pcbl(iy,ipcgb)
k = pcbl(iz,ipcgb)
kk = k - topo_top_ind(j,i,0) ! lad arrays are defined flat
isurfsrc = csfsurf(2, icsf)
IF ( isurfsrc == -1 ) THEN
!
!-- Diffuse radiation from sky
pcbinswdif(ipcgb) = csf(1,icsf) * rad_sw_in_diff(j,i)
!
!-- Add to the sum of SW radiation energy
pinswl = pinswl + pcbinswdif(ipcgb)
!
!-- Absorbed diffuse LW radiation from sky minus emitted to sky
IF ( plant_lw_interact ) THEN
pcbinlw(ipcgb) = csf(1,icsf) * ( rad_lw_in_diff(j, i) - sigma_sb * &
( pt(k,j,i) * exner(k) )**4 )
pinlwl = pinlwl + csf(1,icsf) * rad_lw_in_diff(j,i)
pabslwl = pabslwl + csf(1,icsf) * rad_lw_in_diff(j,i)
pemitlwl = pemitlwl + csf(1,icsf) * sigma_sb * ( pt(k,j,i) * exner(k) )**4
pabs_pc_lwdifl = pabs_pc_lwdifl + csf(1,icsf) * rad_lw_in_diff(j,i)
ENDIF
!
!-- Direct solar radiation
IF ( cos_zenith > 0 ) THEN
!
!-- Estimate directed box absorption
pc_abs_frac = 1.0_wp - exp( pc_abs_eff * lad_s(kk,j,i) )
!
!-- isd has already been established, see (1)
pcbinswdir(ipcgb) = rad_sw_in_dir(j, i) * pc_box_area * pc_abs_frac * &
dsitransc(ipcgb, isd)
!
!-- Add to the sum of SW radiation energy
pinswl = pinswl + pcbinswdir(ipcgb)
ENDIF
ELSE
IF ( plant_lw_interact ) THEN
!
!-- Thermal emission from plan canopy towards respective face
pcrad = sigma_sb * ( pt(k,j,i) * exner(k) )**4 * csf(1,icsf)
surfinlg(isurfsrc) = surfinlg(isurfsrc) + pcrad
!
!-- Remove the flux above + absorb LW from first pass from surfaces
asrc = facearea(surf(id, isurfsrc))
pcbinlw(ipcgb) = pcbinlw(ipcgb) &
+ (csf(1,icsf) * surfoutl(isurfsrc) & ! Absorb from first pass surf emit
- pcrad) & ! Remove emitted heatflux
* asrc
pabslwl = pabslwl + csf(1,icsf) * surfoutl(isurfsrc) * asrc
pemitlwl = pemitlwl + pcrad * asrc
ENDIF
ENDIF
ENDDO
pcbinsw(:) = pcbinswdir(:) + pcbinswdif(:)
ENDIF
IF ( trace_fluxes_above >= 0.0_wp ) THEN
CALL radiation_print_debug_surf( 'surfinl after initial pass', surfinl )
CALL radiation_print_debug_surf( 'surfinlwdif after initial pass', surfinlwdif )
CALL radiation_print_debug_surf( 'surfinswdif after initial pass', surfinswdif )
CALL radiation_print_debug_surf( 'surfinswdir after initial pass', surfinswdir )
IF ( npcbl > 0 ) THEN
CALL radiation_print_debug_pcb( 'pcbinlw after initial pass', pcbinlw )
CALL radiation_print_debug_pcb( 'pcbinswdif after initial pass', pcbinswdif )
CALL radiation_print_debug_pcb( 'pcbinswdir after initial pass', pcbinswdir )
ENDIF
ENDIF
IF ( plant_lw_interact ) THEN
!
!-- Exchange incoming lw radiation from plant canopy
#if defined( __parallel )
CALL MPI_ALLREDUCE( MPI_IN_PLACE, surfinlg, nsurf, MPI_REAL, MPI_SUM, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE:', ierr
FLUSH( 9 )
ENDIF
surfinl(:) = surfinl(:) + surfinlg(surfstart(myid)+1:surfstart(myid+1))
#else
surfinl(:) = surfinl(:) + surfinlg(:)
#endif
ENDIF
IF ( trace_fluxes_above >= 0.0_wp ) THEN
CALL radiation_print_debug_surf( 'surfinl after PC emiss', surfinl )
ENDIF
surfins = surfinswdir + surfinswdif
surfinl = surfinl + surfinlwdif
surfinsw = surfins
surfinlw = surfinl
surfoutsw = 0.0_wp
surfoutlw = surfoutll
surfemitlwl = surfoutll
IF ( .NOT. surface_reflections ) THEN
!
!-- Set nrefsteps to 0 to disable reflections
nrefsteps = 0
surfoutsl = albedo_surf * surfins
surfoutll = ( 1.0_wp - emiss_surf ) * surfinl
surfoutsw = surfoutsw + surfoutsl
surfoutlw = surfoutlw + surfoutll
ENDIF
!
!-- Next passes of radiation interactions: Radiation reflections
DO refstep = 1, nrefsteps
surfoutsl = albedo_surf * surfins
!
!-- For non-transparent surfaces, longwave albedo is 1 - emissivity
surfoutll = ( 1.0_wp - emiss_surf ) * surfinl
IF ( trace_fluxes_above >= 0.0_wp ) THEN
CALL radiation_print_debug_surf( 'surfoutll before reflective pass', surfoutll, refstep )
CALL radiation_print_debug_surf( 'surfoutsl before reflective pass', surfoutsl, refstep )
ENDIF
#if defined( __parallel )
CALL MPI_ALLGATHERV( surfoutsl, nsurfl, MPI_REAL, surfouts, nsurfs, surfstart, MPI_REAL, &
comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHERV2:', ierr, SIZE( surfoutsl ), nsurfl, &
SIZE( surfouts ), nsurfs, surfstart
FLUSH( 9 )
ENDIF
CALL MPI_ALLGATHERV( surfoutll, nsurfl, MPI_REAL, surfoutl, nsurfs, surfstart, MPI_REAL, &
comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHERV3:', ierr, SIZE( surfoutll ), nsurfl, &
SIZE( surfoutl ), nsurfs, surfstart
FLUSH( 9 )
ENDIF
#else
surfouts = surfoutsl
surfoutl = surfoutll
#endif
!
!-- Reset for the input from next reflective pass
surfins = 0.0_wp
surfinl = 0.0_wp
!
!-- Reflected radiation
!$OMP PARALLEL DO PRIVATE (isvf, isurf, isurfsrc) SCHEDULE (STATIC)
DO isvf = 1, nsvfl
isurf = svfsurf(1, isvf)
isurfsrc = svfsurf(2, isvf)
surfins(isurf) = surfins(isurf) + svf(1,isvf) * svf(2,isvf) * surfouts(isurfsrc)
IF ( plant_lw_interact ) THEN
surfinl(isurf) = surfinl(isurf) + svf(1,isvf) * svf(2,isvf) * surfoutl(isurfsrc)
ELSE
surfinl(isurf) = surfinl(isurf) + svf(1,isvf) * surfoutl(isurfsrc)
ENDIF
ENDDO
!
!-- NOTE: PC absorbtion and MRT from reflected can both be done at once after all reflections
!-- if we do one more MPI_ALLGATHERV on surfout.
!-- Advantage: less local computation. Disadvantage: one more collective MPI call.
!
!-- Radiation absorbed by plant canopy
!$OMP PARALLEL DO PRIVATE (icsf, ipcgb, isurfsrc, asrc, temp) SCHEDULE (STATIC)
DO icsf = 1, ncsfl
ipcgb = csfsurf(1, icsf)
isurfsrc = csfsurf(2, icsf)
IF ( isurfsrc == -1 ) CYCLE ! sky->face only in 1st pass, not here
!
!-- Calculate source surface area. If the `surf' array is removed before timestepping starts
!-- (future version), then asrc must be stored within `csf'
asrc = facearea(surf(id, isurfsrc))
temp = csf(1,icsf) * surfouts(isurfsrc) * asrc
!$OMP ATOMIC
pcbinsw(ipcgb) = pcbinsw(ipcgb) + temp
IF ( plant_lw_interact ) THEN
temp = csf(1,icsf) * surfoutl(isurfsrc) * asrc
!$OMP ATOMIC
pcbinlw(ipcgb) = pcbinlw(ipcgb) + temp
ENDIF
ENDDO
!
!-- MRT reflected
!$OMP PARALLEL DO PRIVATE (imrtf, imrt, isurfsrc, temp) SCHEDULE (STATIC)
DO imrtf = 1, nmrtf
imrt = mrtfsurf(1, imrtf)
isurfsrc = mrtfsurf(2, imrtf)
temp = mrtft(imrtf) * surfouts(isurfsrc)
!$OMP ATOMIC
mrtinsw(imrt) = mrtinsw(imrt) + temp
temp = mrtf(imrtf) * surfoutl(isurfsrc)
!$OMP ATOMIC
mrtinlw(imrt) = mrtinlw(imrt) + temp
ENDDO
IF ( trace_fluxes_above >= 0.0_wp ) THEN
CALL radiation_print_debug_surf( 'surfinl after reflected pass', surfinl, refstep )
CALL radiation_print_debug_surf( 'surfins after reflected pass', surfins, refstep )
IF ( npcbl > 0 ) THEN
CALL radiation_print_debug_pcb( 'pcbinlw after reflected pass', pcbinlw, refstep )
CALL radiation_print_debug_pcb( 'pcbinsw after reflected pass', pcbinsw, refstep )
ENDIF
ENDIF
surfinsw = surfinsw + surfins
surfinlw = surfinlw + surfinl
surfoutsw = surfoutsw + surfoutsl
surfoutlw = surfoutlw + surfoutll
ENDDO ! refstep
!
!-- Push heat flux absorbed by plant canopy to respective 3D arrays and add absorbed SW radiation
!-- energy for RTM coupling variables
IF ( npcbl > 0 ) THEN
pcm_heating_rate(:,:,:) = 0.0_wp
!$OMP PARALLEL DO PRIVATE (ipcgb, i, j, k, kk) REDUCTION(+:pabsswl) SCHEDULE (STATIC)
DO ipcgb = 1, npcbl
j = pcbl(iy, ipcgb)
i = pcbl(ix, ipcgb)
k = pcbl(iz, ipcgb)
!
!-- Following expression equals former kk = k - nzb_s_inner(j,i)
kk = k - topo_top_ind(j,i,0) ! lad arrays are defined flat
pcm_heating_rate(kk, j, i) = ( pcbinsw(ipcgb) + pcbinlw(ipcgb) ) * pchf_prep(k) * &
pt(k, j, i) !-- = dT/dt
!
!-- Add the absorbed SW radiation energy by plant canopy
pabsswl = pabsswl + pcbinsw(ipcgb)
ENDDO
IF ( humidity .AND. plant_canopy_transpiration ) THEN
!-- Calculation of plant canopy transpiration rate and correspondidng latent heat rate
pcm_transpiration_rate(:,:,:) = 0.0_wp
pcm_latent_rate(:,:,:) = 0.0_wp
!$OMP PARALLEL DO PRIVATE (ipcgb, i, j, k, kk) SCHEDULE (STATIC)
DO ipcgb = 1, npcbl
i = pcbl(ix, ipcgb)
j = pcbl(iy, ipcgb)
k = pcbl(iz, ipcgb)
kk = k - topo_top_ind(j,i,0) ! lad arrays are defined flat
CALL pcm_calc_transpiration_rate( i, j, k, kk, pcbinsw(ipcgb), pcbinlw(ipcgb), &
pcm_transpiration_rate(kk,j,i), &
pcm_latent_rate(kk,j,i) )
ENDDO
ENDIF
ENDIF
!
!-- Calculate black body MRT (after all reflections)
IF ( nmrtbl > 0 ) THEN
IF ( mrt_include_sw ) THEN
mrt(:) = ( (mrtinsw(:) + mrtinlw(:) ) / sigma_sb)** 0.25_wp
ELSE
mrt(:) = ( mrtinlw(:) / sigma_sb )** 0.25_wp
ENDIF
ENDIF
!
!-- Transfer radiation arrays required for energy balance to the respective data types and
!-- claculate relevant radiation model-RTM coupling terms
mm = 1
!
!-- Following code depends on the order of the execution. Do not parallelize by OpenMP!
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Horizontal walls
DO l = 0, 1
!
!-- Urban
DO m = surf_usm_h(l)%start_index(j,i), surf_usm_h(l)%end_index(j,i)
surf_usm_h(l)%rad_sw_in(m) = surfinsw(mm)
surf_usm_h(l)%rad_sw_out(m) = surfoutsw(mm)
surf_usm_h(l)%rad_sw_dir(m) = surfinswdir(mm)
surf_usm_h(l)%rad_sw_dif(m) = surfinswdif(mm)
surf_usm_h(l)%rad_sw_ref(m) = surfinsw(mm) - surfinswdir(mm) - surfinswdif(mm)
surf_usm_h(l)%rad_sw_res(m) = surfins(mm)
surf_usm_h(l)%rad_lw_in(m) = surfinlw(mm)
surf_usm_h(l)%rad_lw_out(m) = surfoutlw(mm)
surf_usm_h(l)%rad_net(m) = surfinsw(mm) - surfoutsw(mm) + surfinlw(mm) - &
surfoutlw(mm)
surf_usm_h(l)%rad_net_l(m) = surf_usm_h(l)%rad_net(m)
surf_usm_h(l)%rad_lw_dif(m) = surfinlwdif(mm)
surf_usm_h(l)%rad_lw_ref(m) = surfinlw(mm) - surfinlwdif(mm)
surf_usm_h(l)%rad_lw_res(m) = surfinl(mm)
mm = mm + 1
ENDDO
!
!-- Land
DO m = surf_lsm_h(l)%start_index(j,i), surf_lsm_h(l)%end_index(j,i)
surf_lsm_h(l)%rad_sw_in(m) = surfinsw(mm)
surf_lsm_h(l)%rad_sw_out(m) = surfoutsw(mm)
surf_lsm_h(l)%rad_sw_dir(m) = surfinswdir(mm)
surf_lsm_h(l)%rad_sw_dif(m) = surfinswdif(mm)
surf_lsm_h(l)%rad_sw_ref(m) = surfinsw(mm) - surfinswdir(mm) - surfinswdif(mm)
surf_lsm_h(l)%rad_sw_res(m) = surfins(mm)
surf_lsm_h(l)%rad_lw_in(m) = surfinlw(mm)
surf_lsm_h(l)%rad_lw_out(m) = surfoutlw(mm)
surf_lsm_h(l)%rad_net(m) = surfinsw(mm) - surfoutsw(mm) + surfinlw(mm) - &
surfoutlw(mm)
surf_lsm_h(l)%rad_lw_dif(m) = surfinlwdif(mm)
surf_lsm_h(l)%rad_lw_ref(m) = surfinlw(mm) - surfinlwdif(mm)
surf_lsm_h(l)%rad_lw_res(m) = surfinl(mm)
mm = mm + 1
ENDDO
ENDDO
!
!-- Vertical walls
DO l = 0, 3
!
!-- Urban
DO m = surf_usm_v(l)%start_index(j,i), surf_usm_v(l)%end_index(j,i)
surf_usm_v(l)%rad_sw_in(m) = surfinsw(mm)
surf_usm_v(l)%rad_sw_out(m) = surfoutsw(mm)
surf_usm_v(l)%rad_sw_dir(m) = surfinswdir(mm)
surf_usm_v(l)%rad_sw_dif(m) = surfinswdif(mm)
surf_usm_v(l)%rad_sw_ref(m) = surfinsw(mm) - surfinswdir(mm) - surfinswdif(mm)
surf_usm_v(l)%rad_sw_res(m) = surfins(mm)
surf_usm_v(l)%rad_lw_in(m) = surfinlw(mm)
surf_usm_v(l)%rad_lw_out(m) = surfoutlw(mm)
surf_usm_v(l)%rad_net(m) = surfinsw(mm) - surfoutsw(mm) + surfinlw(mm) - &
surfoutlw(mm)
surf_usm_v(l)%rad_net_l(m) = surf_usm_v(l)%rad_net(m)
surf_usm_v(l)%rad_lw_dif(m) = surfinlwdif(mm)
surf_usm_v(l)%rad_lw_ref(m) = surfinlw(mm) - surfinlwdif(mm)
surf_usm_v(l)%rad_lw_res(m) = surfinl(mm)
mm = mm + 1
ENDDO
!
!-- Land
DO m = surf_lsm_v(l)%start_index(j,i), surf_lsm_v(l)%end_index(j,i)
surf_lsm_v(l)%rad_sw_in(m) = surfinsw(mm)
surf_lsm_v(l)%rad_sw_out(m) = surfoutsw(mm)
surf_lsm_v(l)%rad_sw_dir(m) = surfinswdir(mm)
surf_lsm_v(l)%rad_sw_dif(m) = surfinswdif(mm)
surf_lsm_v(l)%rad_sw_ref(m) = surfinsw(mm) - surfinswdir(mm) - surfinswdif(mm)
surf_lsm_v(l)%rad_sw_res(m) = surfins(mm)
surf_lsm_v(l)%rad_lw_in(m) = surfinlw(mm)
surf_lsm_v(l)%rad_lw_out(m) = surfoutlw(mm)
surf_lsm_v(l)%rad_net(m) = surfinsw(mm) - surfoutsw(mm) + surfinlw(mm) - &
surfoutlw(mm)
surf_lsm_v(l)%rad_lw_dif(m) = surfinlwdif(mm)
surf_lsm_v(l)%rad_lw_ref(m) = surfinlw(mm) - surfinlwdif(mm)
surf_lsm_v(l)%rad_lw_res(m) = surfinl(mm)
mm = mm + 1
ENDDO
ENDDO
ENDDO
ENDDO
!$OMP PARALLEL DO PRIVATE (i, d) REDUCTION(+:pabsswl, pabslwl, pemitlwl, pabs_surf_lwdifl) &
!$OMP& SCHEDULE (STATIC)
DO i = 1, nsurfl
d = surfl(id, i)
!
!-- RTM coupling terms
!-- Sum of absorbed SW & LW radiation energy
pabsswl = pabsswl + ( 1.0_wp - albedo_surf(i) ) * surfinsw(i) * facearea(d)
pabslwl = pabslwl + emiss_surf(i) * surfinlw(i) * facearea(d)
!
!-- Sum of emitted LW radiation energy
pemitlwl = pemitlwl + surfemitlwl(i) * facearea(d)
!
!-- emiss1
pabs_surf_lwdifl = pabs_surf_lwdifl + emiss_surf(i) * facearea(d) * surfinlwdif(i)
ENDDO
DO l = 0, 1
!$OMP PARALLEL DO PRIVATE (m) SCHEDULE (STATIC)
DO m = 1, surf_usm_h(l)%ns
surf_usm_h(l)%surfhf(m) = surf_usm_h(l)%rad_sw_in(m) + surf_usm_h(l)%rad_lw_in(m) - &
surf_usm_h(l)%rad_sw_out(m) - surf_usm_h(l)%rad_lw_out(m)
ENDDO
!$OMP PARALLEL DO PRIVATE (m) SCHEDULE (STATIC)
DO m = 1, surf_lsm_h(l)%ns
surf_lsm_h(l)%surfhf(m) = surf_lsm_h(l)%rad_sw_in(m) + surf_lsm_h(l)%rad_lw_in(m) - &
surf_lsm_h(l)%rad_sw_out(m) - surf_lsm_h(l)%rad_lw_out(m)
ENDDO
ENDDO
DO l = 0, 3
!
!-- Urban
!$OMP PARALLEL DO PRIVATE (m) SCHEDULE (STATIC)
DO m = 1, surf_usm_v(l)%ns
surf_usm_v(l)%surfhf(m) = surf_usm_v(l)%rad_sw_in(m) + surf_usm_v(l)%rad_lw_in(m) - &
surf_usm_v(l)%rad_sw_out(m) - surf_usm_v(l)%rad_lw_out(m)
ENDDO
!
!-- Land
!$OMP PARALLEL DO PRIVATE (m) SCHEDULE (STATIC)
DO m = 1, surf_lsm_v(l)%ns
surf_lsm_v(l)%surfhf(m) = surf_lsm_v(l)%rad_sw_in(m) + surf_lsm_v(l)%rad_lw_in(m) - &
surf_lsm_v(l)%rad_sw_out(m) - surf_lsm_v(l)%rad_lw_out(m)
ENDDO
ENDDO
!
!-- Gather all rad flux energy in all processors. In order to reduce the number of MPI calls
!-- (to reduce latencies), combine the required quantities in one array, sum it up, and
!-- subsequently re-distribute back to the respective quantities.
#if defined( __parallel )
combine_allreduce_l(1) = pinswl
combine_allreduce_l(2) = pinlwl
combine_allreduce_l(3) = pabsswl
combine_allreduce_l(4) = pabslwl
combine_allreduce_l(5) = pemitlwl
combine_allreduce_l(6) = pabs_surf_lwdifl
combine_allreduce_l(7) = pabs_pc_lwdifl
CALL MPI_ALLREDUCE( combine_allreduce_l, combine_allreduce, SIZE( combine_allreduce ), &
MPI_REAL, MPI_SUM, comm2d, ierr )
pinsw = combine_allreduce(1)
pinlw = combine_allreduce(2)
pabssw = combine_allreduce(3)
pabslw = combine_allreduce(4)
pemitlw = combine_allreduce(5)
pabs_surf_lwdif = combine_allreduce(6)
pabs_pc_lwdif = combine_allreduce(7)
#else
pinsw = pinswl
pinlw = pinlwl
pabssw = pabsswl
pabslw = pabslwl
pemitlw = pemitlwl
pabs_surf_lwdif = pabs_surf_lwdifl
pabs_pc_lwdif = pabs_pc_lwdifl
#endif
!
!-- Calculate the effective radiation surface parameters based on the parameterizations in Krc et
!-- al. 2020
!
!-- (1) Albedo Eq. * in Krc et al. 2020
IF ( pinsw /= 0.0_wp ) albedo_urb = ( pinsw - pabssw ) / pinsw
!
!-- (2) Emmsivity Eq. * in Krc et al. 2020
!-- emissivity_urb weighted average of surface and PC emissivity = absorbed LW
!-- in [surfaces + plant canopy] / pinlw
emissivity_urb = (pabs_surf_lwdif + pabs_pc_lwdif) / pinlw
!
!-- (3) Temperature
!-- effective horizontal area to account for the effect of vertical surfaces,
!-- Eq. * in Krc et al. 2020
area_norm = pinlw / rad_lw_in_diff(nyn,nxl)
!
!-- Temperature, Eq. * in Krc et al. 2020
t_rad_urb = ( ( pemitlw - pabslw + emissivity_urb * pinlw ) / &
( emissivity_urb * sigma_sb * area_norm ) )**0.25_wp
IF ( debug_output_timestep ) CALL debug_message( 'radiation_interaction', 'end' )
CONTAINS
!--------------------------------------------------------------------------------------------------!
!> Calculates radiation absorbed by box with given size and LAD.
!>
!> Simulates resol**2 rays (by equally spacing a bounding horizontal square conatining all possible
!> rays that would cross the box) and calculates average transparency per ray. Returns fraction of
!> absorbed radiation flux and area for which this fraction is effective.
!--------------------------------------------------------------------------------------------------!
PURE SUBROUTINE box_absorb( boxsize, resol, dens, uvec, area, absorb )
IMPLICIT NONE
INTEGER(iwp) :: i, j !<
INTEGER(iwp), INTENT(IN) :: resol !< No. of rays in x and y dimensions
REAL(wp) :: xshift, yshift, & !<
xmin, xmax, ymin, ymax, & !<
xorig, yorig, & !<
dx1, dy1, dz1, dx2, dy2, dz2, & !<
crdist, & !<
transp !<
REAL(wp), INTENT(IN) :: dens !< box density (e.g. Leaf Area Density)
REAL(wp), INTENT(OUT) :: area, & !< horizontal area for flux absorbtion
absorb !< fraction of absorbed flux
REAL(wp), DIMENSION(3), INTENT(IN) :: boxsize, & !< z, y, x size of box in m
uvec !< z, y, x unit vector of incoming flux
xshift = uvec(3) / uvec(1) * boxsize(1)
xmin = MIN( 0._wp, - xshift )
xmax = boxsize(3) + MAX( 0._wp, - xshift )
yshift = uvec(2) / uvec(1) * boxsize(1)
ymin = MIN( 0._wp, - yshift )
ymax = boxsize(2) + MAX( 0._wp, - yshift )
transp = 0._wp
DO i = 1, resol
xorig = xmin + ( xmax - xmin ) * ( i - .5_wp ) / resol
DO j = 1, resol
yorig = ymin + ( ymax - ymin ) * ( j - .5_wp ) / resol
dz1 = 0._wp
dz2 = boxsize(1) / uvec(1)
IF ( uvec(2) > 0._wp ) THEN
dy1 = - yorig / uvec(2) !< Crossing with y=0
dy2 = ( boxsize(2) - yorig ) / uvec(2) !< Crossing with y=boxsize(2)
ELSE ! uvec(2) == 0
dy1 = - HUGE( 1._wp )
dy2 = HUGE( 1._wp )
ENDIF
IF ( uvec(3) > 0._wp ) THEN
dx1 = - xorig / uvec(3) !< Crossing with x=0
dx2 = ( boxsize(3) - xorig ) / uvec(3) !< Crossing with x=boxsize(3)
ELSE ! uvec(3) == 0
dx1 = - HUGE( 1._wp )
dx2 = HUGE( 1._wp )
ENDIF
crdist = MAX( 0._wp, ( MIN( dz2, dy2, dx2 ) - MAX( dz1, dy1, dx1 ) ) )
transp = transp + EXP( - ext_coef * dens * crdist )
ENDDO
ENDDO
transp = transp / resol**2
area = ( boxsize(3) + xshift ) * ( boxsize(2) + yshift )
absorb = 1._wp - transp
END SUBROUTINE box_absorb
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> This subroutine splits direct and diffusion dw radiation for RTM processing.
!> It sould not be called in case the radiation model already does it.
!> It follows Boland, Ridley & Brown (2008)
!--------------------------------------------------------------------------------------------------!
SUBROUTINE calc_diffusion_radiation
USE palm_date_time_mod, &
ONLY: seconds_per_day
INTEGER(iwp) :: i !< grid index x-direction
INTEGER(iwp) :: j !< grid index y-direction
INTEGER(iwp) :: days_per_year !< days in the current year
REAL(wp), PARAMETER :: lowest_solarUp = 0.1_wp !< limit the sun elevation to protect stability of the calculation
REAL(wp) :: clearnessIndex !< clearness index
REAL(wp) :: corrected_solarUp !< corrected solar up radiation
REAL(wp) :: diff_frac !< diffusion fraction of the radiation
REAL(wp) :: etr !< extraterestrial radiation
REAL(wp) :: horizontalETR !< horizontal extraterestrial radiation
REAL(wp) :: second_of_year !< current second of the year
REAL(wp) :: year_angle !< angle
!
!-- Calculate current day and time based on the initial values and simulation time
CALL get_date_time( time_since_reference_point, second_of_year = second_of_year, &
days_per_year = days_per_year )
year_angle = second_of_year / ( REAL( days_per_year, KIND = wp ) * seconds_per_day ) * &
2.0_wp * pi
etr = solar_constant * ( 1.00011_wp + 0.034221_wp * COS(year_angle) + &
0.001280_wp * SIN(year_angle) + &
0.000719_wp * COS(2.0_wp * year_angle) + &
0.000077_wp * SIN(2.0_wp * year_angle) )
!
!-- Under a very low angle, we keep extraterestrial radiation at the last small value, therefore
!-- the clearness index will be pushed towards 0 while keeping full continuity.
IF ( cos_zenith <= lowest_solarUp ) THEN
corrected_solarUp = lowest_solarUp
ELSE
corrected_solarUp = cos_zenith
ENDIF
horizontalETR = etr * corrected_solarUp
DO i = nxl, nxr
DO j = nys, nyn
clearnessIndex = rad_sw_in(0,j,i) / horizontalETR
diff_frac = 1.0_wp / ( 1.0_wp + EXP( -5.0033_wp + 8.6025_wp * clearnessIndex ) )
rad_sw_in_diff(j,i) = rad_sw_in(0,j,i) * diff_frac
rad_sw_in_dir(j,i) = rad_sw_in(0,j,i) * ( 1.0_wp - diff_frac )
rad_lw_in_diff(j,i) = rad_lw_in(0,j,i)
ENDDO
ENDDO
END SUBROUTINE calc_diffusion_radiation
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Print consecutive radiative extremes if requested to trace early radiation interaction
!> instabilities.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_print_debug_surf( description, values, step )
CHARACTER(LEN=50) :: location !<
CHARACTER(LEN=1024) :: debug_string !<
CHARACTER(LEN=*), INTENT(IN) :: description !<
INTEGER :: isurf !<
INTEGER(iwp), INTENT(IN), OPTIONAL :: step !<
REAL(wp) :: x !<
REAL(wp), DIMENSION(:), INTENT(IN) :: values !<
isurf = MAXLOC( values, DIM = 1 )
x = values(isurf)
IF ( x < trace_fluxes_above ) RETURN
IF ( PRESENT( step ) ) THEN
WRITE( location, '(A," #",I0)' ) description, step
ELSE
location = description
ENDIF
WRITE( debug_string, '("Maximum of ",A50," = ",F12.1," at coords i=",I4,", j=",I4,", ' // &
'k=",I4,", d=",I1,". Alb=",F7.3,", emis=",F7.3)' ) &
location, x, surfl(ix,isurf), surfl(iy,isurf), surfl(iz,isurf), surfl(id,isurf), &
albedo_surf(isurf), emiss_surf(isurf)
CALL debug_message( debug_string, 'info' )
END SUBROUTINE
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> @Todo: Missing Subroutine Description!
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_print_debug_pcb( description, values, step )
CHARACTER(LEN=50) :: location !<
CHARACTER(LEN=1024) :: debug_string !<
CHARACTER(LEN=*), INTENT(IN) :: description !<
INTEGER :: ipcb !<
INTEGER(iwp), INTENT(IN), OPTIONAL :: step !<
REAL(wp) :: x !<
REAL(wp), DIMENSION(:), INTENT(in) :: values !<
IF ( npcbl <= 0 ) RETURN
ipcb = MAXLOC( values, DIM = 1 )
x = values(ipcb) / ( dx * dy * dz(1) )
IF ( x < trace_fluxes_above ) RETURN
IF ( PRESENT( step ) ) THEN
WRITE( location, '(A," #",I0)' ) description, step
ELSE
location = description
ENDIF
WRITE( debug_string, '("Maximum of ",A50," = ",F12.1," at coords i=",I4,", j=",I4,", k=",I4)' )&
location, x, pcbl(ix,ipcb), pcbl(iy,ipcb), pcbl(iz,ipcb)
CALL debug_message( debug_string, 'info' )
END SUBROUTINE
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> @Todo: Missing Subroutine Description!
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_print_debug_horz( description, values, step )
CHARACTER(LEN=50) :: location !<
CHARACTER(LEN=1024) :: debug_string !<
CHARACTER(LEN=*), INTENT(IN) :: description !<
INTEGER(iwp), INTENT(IN), OPTIONAL :: step !<
INTEGER, DIMENSION(2) :: ji !<
REAL(wp) :: x !<
REAL(wp), DIMENSION(:,:), INTENT(IN) :: values !<
ji = MAXLOC( values )
x = values( ji(1), ji(2) )
IF ( x < trace_fluxes_above ) RETURN
IF ( PRESENT( step ) ) THEN
WRITE( location, '(A," #",I0)' ) description, step
ELSE
location = description
ENDIF
WRITE( debug_string, '("Maximum of ",A50," = ",F12.1," at coords i=",I4,", j=",I4)' ) &
location, x, ji(2), ji(1)
CALL debug_message( debug_string, 'info' )
END SUBROUTINE
END SUBROUTINE radiation_interaction
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> This subroutine initializes structures needed for Radiative Transfer Model (RTM). This model
!> calculates transformation processes of the radiation inside urban and land canopy layer. The
!> module includes also the interaction of the radiation with the resolved plant canopy.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_interaction_init
USE control_parameters, &
ONLY: dz_stretch_level_start
USE plant_canopy_model_mod, &
ONLY: lad_s
IMPLICIT NONE
INTEGER(iwp) :: i, j, k, l, m, d !<
INTEGER(iwp) :: icol !< flat column number (in (y,x) fortran order)
INTEGER(iwp) :: isurf, ipcgb, imrt !<
INTEGER(iwp) :: k_topo !< vertical index indicating topography top for given (j,i)
INTEGER(iwp) :: nzptl, nzubl, nzutl !<
REAL(wp) :: mrl !<
!
!-- Precalculate face areas for different face directions using normal vector
DO d = 0, nsurf_type
facearea(d) = 1._wp
IF ( idir(d) == 0 ) facearea(d) = facearea(d) * dx
IF ( jdir(d) == 0 ) facearea(d) = facearea(d) * dy
IF ( kdir(d) == 0 ) facearea(d) = facearea(d) * dz(1)
ENDDO
!
!-- Find nz_urban_b, nz_urban_t, nz_urban via wall_flag_0 array (nzb_s_inner will be removed later).
!-- The following contruct finds the lowest / largest index for any upward-facing wall (see bit 12).
nzubl = MINVAL( topo_top_ind(nys:nyn,nxl:nxr,0) )
nzutl = MAXVAL( topo_top_ind(nys:nyn,nxl:nxr,5) )
nzubl = MAX( nzubl, nzb )
IF ( plant_canopy ) THEN
!
!-- Allocate needed arrays
ALLOCATE( pct(nys:nyn,nxl:nxr) )
ALLOCATE( pch(nys:nyn,nxl:nxr) )
!
!-- Calculate plant canopy height
npcbl = 0
pct = 0
pch = 0
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Find topography top index
k_topo = topo_top_ind(j,i,0)
DO k = nzt+1, 1, -1
IF ( lad_s(k,j,i) > 0.0_wp ) THEN
!
!-- We are at the top of the pcs
pct(j,i) = k + k_topo
pch(j,i) = k
npcbl = npcbl + COUNT( lad_s(1:k,j,i) > 0.0_wp )
EXIT
ENDIF
ENDDO
ENDDO
ENDDO
nzutl = MAX( nzutl, MAXVAL( pct ) )
nzptl = MAXVAL( pct )
prototype_lad = MAXVAL( lad_s ) * .9_wp !< Better be *1.0 if lad is either 0 or maxval(lad) everywhere
IF ( prototype_lad <= 0._wp ) prototype_lad = .3_wp
!WRITE(message_string, '(a,f6.3)') 'Precomputing effective box optical ' &
! // 'depth using prototype leaf area density = ', prototype_lad
!CALL message('radiation_interaction_init', 'PA0520', 0, 0, -1, 6, 0)
ENDIF
nzutl = MIN( nzutl + nzut_free, nzt )
#if defined( __parallel )
CALL MPI_ALLREDUCE( nzubl, nz_urban_b, 1, MPI_INTEGER, MPI_MIN, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE11:', ierr, nzubl, nz_urban_b
FLUSH( 9 )
ENDIF
CALL MPI_ALLREDUCE( nzutl, nz_urban_t, 1, MPI_INTEGER, MPI_MAX, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE12:', ierr, nzutl, nz_urban_t
FLUSH( 9 )
ENDIF
CALL MPI_ALLREDUCE( nzptl, nz_plant_t, 1, MPI_INTEGER, MPI_MAX, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLREDUCE13:', ierr, nzptl, nz_plant_t
FLUSH( 9 )
ENDIF
#else
nz_urban_b = nzubl
nz_urban_t = nzutl
nz_plant_t = nzptl
#endif
!
!-- Stretching (non-uniform grid spacing) is not considered in the radiation model. Therefore,
!-- vertical stretching has to be applied above the area where the parts of the radiation model
!-- which assume constant grid spacing are active. ABS (...) is required because the default value
!-- of dz_stretch_level_start is -9999999.9_wp (negative).
IF ( ABS( dz_stretch_level_start(1) ) <= zw(nz_urban_t) ) THEN
WRITE( message_string, * ) 'The lowest level where vertical stretching is applied have ' // &
'to be greater than ', zw(nz_urban_t)
CALL message( 'radiation_interaction_init', 'PA0496', 1, 2, 0, 6, 0 )
ENDIF
!
!-- Global number of urban and plant layers
nz_urban = nz_urban_t - nz_urban_b + 1
nz_plant = nz_plant_t - nz_urban_b + 1
!
!-- Check max_raytracing_dist relative to urban surface layer height
mrl = 2.0_wp * nz_urban * dz(1)
!
!-- Set max_raytracing_dist to double the urban surface layer height, if not set
IF ( max_raytracing_dist == -999.0_wp ) THEN
max_raytracing_dist = mrl
ENDIF
! Check if max_raytracing_dist is set too low (here we only warn the user. Other option is to
!-- correct the value again to double the urban surface layer height)
IF ( max_raytracing_dist < mrl ) THEN
WRITE( message_string, '(a,f6.1)' ) 'Max_raytracing_dist is set less than double the ' // &
'urban surface layer height, i.e. ', mrl
CALL message( 'radiation_interaction_init', 'PA0521', 0, 0, 0, 6, 0 )
ENDIF
! IF ( max_raytracing_dist <= mrl ) THEN
! IF ( max_raytracing_dist /= -999.0_wp ) THEN
! !- max_raytracing_dist too low
! WRITE(message_string, '(a,f6.1)') 'Max_raytracing_dist too low, ' &
! // 'override to value ', mrl
! CALL message('radiation_interaction_init', 'PA0521', 0, 0, -1, 6, 0)
! ENDIF
! max_raytracing_dist = mrl
! ENDIF
!
!-- Allocate urban surfaces grid
!-- Calc number of surfaces in local proc
IF ( debug_output ) CALL debug_message( 'calculation of indices for surfaces', 'info' )
nsurfl = 0
!
!-- Number of horizontal surfaces including land- and roof surfaces in both USM and LSM. Note that
!-- all horizontal surface elements are already counted in surface_mod.
DO l = 0, 1
nsurfl = nsurfl + surf_usm_h(l)%ns + surf_lsm_h(l)%ns
ENDDO
!
!-- Number of vertical surfaces in both USM and LSM. Note that all vertical surface elements are
!-- already counted in surface_mod.
DO l = 0,3
nsurfl = nsurfl + surf_usm_v(l)%ns + surf_lsm_v(l)%ns
ENDDO
!
!-- Fill gridpcbl and pcbl
IF ( npcbl > 0 ) THEN
ALLOCATE( pcbl(iz:ix, 1:npcbl) )
ALLOCATE( gridpcbl(nz_urban_b:nz_plant_t,nys:nyn,nxl:nxr) )
pcbl = -1
gridpcbl(:,:,:) = 0
ipcgb = 0
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Find topography top index
k_topo = topo_top_ind(j,i,0)
DO k = k_topo + 1, pct(j,i)
IF ( lad_s(k-k_topo,j,i) > 0.0_wp ) THEN
ipcgb = ipcgb + 1
gridpcbl(k,j,i) = ipcgb
pcbl(:,ipcgb) = (/ k, j, i /)
ENDIF
ENDDO
ENDDO
ENDDO
ALLOCATE( pcbinsw( 1:npcbl ) )
ALLOCATE( pcbinswdir( 1:npcbl ) )
ALLOCATE( pcbinswdif( 1:npcbl ) )
ALLOCATE( pcbinlw( 1:npcbl ) )
ENDIF
!
!-- Allocate and calculate auxiliary indices needed for MPI exchanges
!-- Numbers of xy grid elements for individual PE and corresponding displacements
ALLOCATE( nnxy(0:numprocs-1), nnxyd(0:numprocs-1) )
k = 0
DO i = 0, npex-1
DO j = 0, npey-1
nnxy(k) = (nxr_pe(i) - nxl_pe(i) + 1) * (nyn_pe(j) - nys_pe(j) + 1)
k = k + 1
ENDDO
ENDDO
nnxyd(0) = 0
DO i = 1, numprocs-1
nnxyd(i) = nnxyd(i-1) + nnxy(i-1)
ENDDO
!
!-- Indices of PE numbers along x a y axis
ALLOCATE( ipx(0:nx), ipy(0:ny) )
DO i = 0, npex-1
ipx(nxl_pe(i):nxr_pe(i)) = i
ENDDO
DO j = 0, npey-1
ipy(nys_pe(j):nyn_pe(j)) = j
ENDDO
!
!-- Allocate and fill surfl and surfl_col_start. The ordering of local surfaces
!-- given by the following cycles must not be altered, certain file input
!-- routines may depend on it.
!
!-- We allocate the array as linear and then use a two-dimensional pointer
!-- into it, because some MPI implementations crash with 2D-allocated arrays.
ALLOCATE(surfl_linear(nidx_surf*nsurfl))
surfl(1:nidx_surf,1:nsurfl) => surfl_linear(1:nidx_surf*nsurfl)
ALLOCATE( surfl_col_start(0:nnx*nny-1) )
!
!-- Add horizontal and vertical surface elements (land and urban surfaces) ordered by x,y column
!-- (y most varying)
!-- TODO: remove the hard coding of l = 0 to l = idirection
isurf = 0
icol = 0
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Save column start
surfl_col_start(icol) = isurf + 1
icol = icol + 1
!
!-- Horizontal surfaces
DO l = 0, 1
DO m = surf_usm_h(l)%start_index(j,i), surf_usm_h(l)%end_index(j,i)
k = surf_usm_h(l)%k(m)
isurf = isurf + 1
surfl(:,isurf) = (/dirint_h(l),k,j,i/)
ENDDO
DO m = surf_lsm_h(l)%start_index(j,i), surf_lsm_h(l)%end_index(j,i)
k = surf_lsm_h(l)%k(m)
isurf = isurf + 1
surfl(:,isurf) = (/dirint_h(l),k,j,i/)
ENDDO
ENDDO
!
!-- Vertical surfaces
DO l = 0, 3
DO m = surf_usm_v(l)%start_index(j,i), surf_usm_v(l)%end_index(j,i)
k = surf_usm_v(l)%k(m)
isurf = isurf + 1
surfl(:,isurf) = (/dirint_v(l),k,j,i/)
ENDDO
DO m = surf_lsm_v(l)%start_index(j,i), surf_lsm_v(l)%end_index(j,i)
k = surf_lsm_v(l)%k(m)
isurf = isurf + 1
surfl(:,isurf) = (/dirint_v(l),k,j,i/)
ENDDO
ENDDO
ENDDO
ENDDO
!
!-- Add local MRT boxes for the specified number of levels
!-- !!!! NEEDS TO RETHINK AGAIN - With full 3D structure, only the one of the upward faced
!-- !!!! horizontal surfaces should be taken (the lowest one = ground?). mrt_nlevels number of air
!-- !!!! grid boxes might not be available in case of overhanging structures!
nmrtbl = 0
IF ( mrt_nlevels > 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
!
!-- Skip roof if requested
IF ( mrt_skip_roof .AND. surf_usm_h(0)%isroof_surf(m) ) CYCLE
!
!-- Cycle over specified no of levels
nmrtbl = nmrtbl + mrt_nlevels
ENDDO
!
!-- Ditto for LSM
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
nmrtbl = nmrtbl + mrt_nlevels
ENDDO
ENDDO
ENDDO
ALLOCATE( mrtbl(iz:ix,nmrtbl), mrtsky(nmrtbl), mrtskyt(nmrtbl), mrtinsw(nmrtbl), &
mrtinlw(nmrtbl), mrt(nmrtbl) )
imrt = 0
DO i = nxl, nxr
DO j = nys, nyn
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
!
!-- Skip roof if requested
IF ( mrt_skip_roof .AND. surf_usm_h(0)%isroof_surf(m) ) CYCLE
!
!-- Cycle over specified no of levels
l = surf_usm_h(0)%k(m)
DO k = l, l + mrt_nlevels - 1
imrt = imrt + 1
mrtbl(:,imrt) = (/k,j,i/)
ENDDO
ENDDO
!
!-- Dtto for LSM
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
l = surf_lsm_h(0)%k(m)
DO k = l, l + mrt_nlevels - 1
imrt = imrt + 1
mrtbl(:,imrt) = (/k,j,i/)
ENDDO
ENDDO
ENDDO
ENDDO
ENDIF
!
!-- Broadband albedo of the land, roof and wall surface for domain border and sky set artifically
!-- to 1.0 what allows us to calculate heat flux leaving over side and top borders of the domain
ALLOCATE( albedo_surf(nsurfl) )
albedo_surf = 1.0_wp
!
!-- Also allocate further array for emissivity with identical order of surface elements as radiation
!-- arrays.
ALLOCATE( emiss_surf(nsurfl) )
!
!-- Global array surf of indices of surfaces and displacement index array surfstart
ALLOCATE( nsurfs(0:numprocs-1) )
#if defined( __parallel )
CALL MPI_ALLGATHER( nsurfl, 1, MPI_INTEGER, nsurfs, 1, MPI_INTEGER, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHER1:', ierr, nsurfl, nsurfs
FLUSH( 9 )
ENDIF
#else
nsurfs(0) = nsurfl
#endif
ALLOCATE( surfstart(0:numprocs) )
k = 0
DO i = 0, numprocs-1
surfstart(i) = k
k = k + nsurfs(i)
ENDDO
surfstart(numprocs) = k
nsurf = k
!
!-- We allocate the array as linear and then use a two-dimensional pointer into it, because some MPI
!-- implementations crash with 2D-allocated arrays.
ALLOCATE( surf_linear(nidx_surf*nsurf) )
surf(1:nidx_surf,1:nsurf) => surf_linear(1:nidx_surf*nsurf)
#if defined( __parallel )
CALL MPI_ALLGATHERV( surfl_linear, nsurfl * nidx_surf, MPI_INTEGER, surf_linear, &
nsurfs * nidx_surf, surfstart(0:numprocs-1) * nidx_surf, MPI_INTEGER, &
comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHERV4:', ierr, SIZE( surfl_linear ), nsurfl * nidx_surf, &
SIZE( surf_linear ), nsurfs * nidx_surf, surfstart(0:numprocs-1) * nidx_surf
FLUSH( 9 )
ENDIF
#else
surf = surfl
#endif
!
!-- Allocate and gather global column start indices surfg_col_start
ALLOCATE( surfg_col_start(0:(nx+1)*(ny+1)) )
#if defined( __parallel )
CALL MPI_ALLGATHERV( surfl_col_start, nnx*nny, MPI_INTEGER, &
surfg_col_start, nnxy, nnxyd, MPI_INTEGER, comm2d, ierr)
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHER1b:', ierr, surfl_col_start, surfg_col_start
FLUSH( 9 )
ENDIF
!
!-- Convert local indices (->surfl) to global (->surf)
DO i = 0, numprocs-1
surfg_col_start(nnxyd(i):nnxyd(i)+nnxy(i)-1) = &
surfg_col_start(nnxyd(i):nnxyd(i)+nnxy(i)-1) + surfstart(i)
ENDDO
#else
surfg_col_start(0:(nx+1)*(ny+1)-1) = surfl_col_start(0:(nx+1)*(ny+1)-1)
#endif
surfg_col_start((nx+1)*(ny+1)) = nsurf+1
!
!-- Allocation of the arrays for direct and diffusion radiation
IF ( debug_output ) CALL debug_message( 'allocation of radiation arrays', 'info' )
!-- rad_sw_in, rad_lw_in are computed in radiation model, splitting of direct and diffusion part is
!-- done in calc_diffusion_radiation for now
ALLOCATE( rad_sw_in_dir(nysg:nyng,nxlg:nxrg) )
ALLOCATE( rad_sw_in_diff(nysg:nyng,nxlg:nxrg) )
ALLOCATE( rad_lw_in_diff(nysg:nyng,nxlg:nxrg) )
rad_sw_in_dir = 0.0_wp
rad_sw_in_diff = 0.0_wp
rad_lw_in_diff = 0.0_wp
!
!-- Allocate radiation arrays
ALLOCATE( surfins(nsurfl) )
ALLOCATE( surfinl(nsurfl) )
ALLOCATE( surfinsw(nsurfl) )
ALLOCATE( surfinlw(nsurfl) )
ALLOCATE( surfinswdir(nsurfl) )
ALLOCATE( surfinswdif(nsurfl) )
ALLOCATE( surfinlwdif(nsurfl) )
ALLOCATE( surfoutsl(nsurfl) )
ALLOCATE( surfoutll(nsurfl) )
ALLOCATE( surfoutsw(nsurfl) )
ALLOCATE( surfoutlw(nsurfl) )
ALLOCATE( surfouts(nsurf) )
ALLOCATE( surfoutl(nsurf) )
ALLOCATE( surfinlg(nsurf) )
ALLOCATE( skyvf(nsurfl) )
ALLOCATE( skyvft(nsurfl) )
ALLOCATE( surfemitlwl(nsurfl) )
!
!-- In case of average_radiation, aggregated surface albedo and emissivity, also set initial value
!-- for t_rad_urb.
!-- For now set an arbitrary initial value.
IF ( average_radiation ) THEN
albedo_urb = 0.1_wp
emissivity_urb = 0.9_wp
t_rad_urb = pt_surface
ENDIF
END SUBROUTINE radiation_interaction_init
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Calculates shape view factors (SVF), plant sink canopy factors (PCSF), sky-view factors,
!> discretized path for direct solar radiation, MRT factors and other preprocessed data needed for
!> radiation_interaction inside RTM. This subroutine is called only once at the beginning of the
!> simulation. The resulting factors can be stored to files and reused with other simulations
!> utilizing the same surface and plant canopy structure.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_calc_svf
IMPLICIT NONE
INTEGER(iwp) :: i, j, k, ip, jp !<
INTEGER(iwp) :: isvf, ksvf, icsf, kcsf, npcsfl, isvf_surflt, imrt, imrtf, ipcgb !<
INTEGER(iwp) :: iaz, izn !< azimuth, zenith counters
INTEGER(iwp) :: isurf, isurflt, isurfs, isurflt_prev !<
INTEGER(iwp) :: itarg0, itarg1 !<
INTEGER(iwp) :: max_track_len !< maximum 2d track length
INTEGER(iwp) :: naz, nzn !< azimuth, zenith num of steps
INTEGER(idp) :: ray_skip_maxdist, ray_skip_minval !< skipped raytracing counts
INTEGER(iwp) :: sd, td !<
INTEGER(iwp) :: udim !<
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: itarget !< face indices of detected obstacles
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: icsflt !<
INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET :: kcsflt_l,kpcsflt_l !<
INTEGER(iwp), DIMENSION(:,:), POINTER :: kcsflt,kpcsflt !<
LOGICAL :: visible !<
REAL(wp) :: az0, zn0 !< starting azimuth/zenith
REAL(wp) :: azs, zns !< azimuth/zenith cycle step
REAL(wp) :: az1, az2 !< relative azimuth of section borders
REAL(wp) :: azmid !< ray (center) azimuth
REAL(wp) :: difvf !< differential view factor
REAL(wp) :: transparency, rirrf, sqdist, svfsum !<
REAL(wp) :: yxlen !< |yxdir|
REAL(wp), DIMENSION(2) :: yxdir !< y,x *unit* vector of ray direction (in grid units)
REAL(wp), DIMENSION(3) :: sa, ta !< real coordinates z,y,x of source and target
REAL(wp), DIMENSION(3) :: uv !<
REAL(wp), DIMENSION(:), ALLOCATABLE :: vffrac !< view factor fractions for individual rays
REAL(wp), DIMENSION(:), ALLOCATABLE :: vffrac0 !< dtto (original values)
REAL(wp), DIMENSION(:), ALLOCATABLE :: zdirs !< directions in z (tangent of elevation)
REAL(wp), DIMENSION(:), ALLOCATABLE :: zcent !< zenith angle centers
REAL(wp), DIMENSION(:), ALLOCATABLE :: zbdry !< zenith angle boundaries
REAL(wp), DIMENSION(:), ALLOCATABLE :: ztransp !< array of transparency in z steps
REAL(wp),DIMENSION(:), ALLOCATABLE,TARGET :: csflt_l, pcsflt_l !<
REAL(wp),DIMENSION(:,:), POINTER :: csflt, pcsflt !<
#if defined( __parallel )
INTEGER(iwp) :: minfo !< MPI RMA window info handle
INTEGER(KIND=MPI_ADDRESS_KIND) :: size_lad_rma !<
INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET :: nzterrtl_l !<
INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET :: nzterrbl_l !<
INTEGER(iwp), DIMENSION(:,:), POINTER :: nzterrtl !<
INTEGER(iwp), DIMENSION(:,:), POINTER :: nzterrbl !<
REAL(wp), DIMENSION(:), POINTER, SAVE :: lad_s_rma !< fortran 1D pointer
INTEGER(iwp), DIMENSION(:), POINTER, SAVE :: gridsurf_rma !< fortran pointer, but lower bounds are 1
TYPE(c_ptr) :: lad_s_rma_p !< allocated c pointer
TYPE(c_ptr) :: gridsurf_rma_p !< allocated c pointer
#endif
!
INTEGER(iwp), DIMENSION(0:svfnorm_report_num) :: svfnorm_counts !<
!
!-- Calculation of the SVF
CALL location_message( 'calculating view factors for radiation interaction', 'start' )
!
!-- Initialize variables and temporary arrays for calculation of svf and csf
nsvfl = 0
ncsfl = 0
nsvfla = gasize
msvf = 1
ALLOCATE( asvf1(nsvfla) )
asvf => asvf1
IF ( plant_canopy ) THEN
ncsfla = gasize
mcsf = 1
ALLOCATE( acsf1(ncsfla) )
acsf => acsf1
ENDIF
nmrtf = 0
IF ( mrt_nlevels > 0 ) THEN
nmrtfa = gasize
mmrtf = 1
ALLOCATE( amrtf1(nmrtfa) )
amrtf => amrtf1
ENDIF
ray_skip_maxdist = 0
ray_skip_minval = 0
!
!-- Initialize temporary terrain and plant canopy height arrays (global 2D array!)
ALLOCATE( nzterrt(0:(nx+1)*(ny+1)-1) )
ALLOCATE( nzterrb(0:(nx+1)*(ny+1)-1) )
#if defined( __parallel )
ALLOCATE( nzterrtl_l((nyn-nys+1)*(nxr-nxl+1)) )
ALLOCATE( nzterrbl_l((nyn-nys+1)*(nxr-nxl+1)) )
nzterrtl(nys:nyn,nxl:nxr) => nzterrtl_l(1:(nyn-nys+1)*(nxr-nxl+1))
nzterrbl(nys:nyn,nxl:nxr) => nzterrbl_l(1:(nyn-nys+1)*(nxr-nxl+1))
nzterrtl = topo_top_ind(nys:nyn,nxl:nxr,5)
nzterrbl = topo_top_ind(nys:nyn,nxl:nxr,0)
CALL MPI_ALLGATHERV( nzterrtl_l, nnx*nny, MPI_INTEGER, nzterrt, nnxy, nnxyd, MPI_INTEGER, &
comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHER1t:', ierr, SIZE( nzterrtl_l ), nnx*nny, SIZE( nzterrt ),&
nnx*nny
FLUSH(9)
ENDIF
CALL MPI_ALLGATHERV( nzterrbl_l, nnx*nny, MPI_INTEGER, nzterrb, nnxy, nnxyd, MPI_INTEGER, &
comm2d, ierr)
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHER1b:', ierr, SIZE( nzterrbl_l ), nnx*nny, SIZE( nzterrb ),&
nnx*nny
FLUSH( 9 )
ENDIF
DEALLOCATE( nzterrtl_l )
DEALLOCATE( nzterrbl_l )
#else
nzterrt = RESHAPE( topo_top_ind(nys:nyn,nxl:nxr,5), (/(nx+1)*(ny+1)/) )
nzterrb = RESHAPE( topo_top_ind(nys:nyn,nxl:nxr,0), (/(nx+1)*(ny+1)/) )
#endif
IF ( plant_canopy ) THEN
ALLOCATE( plantt(0:(nx+1)*(ny+1)-1) )
maxboxesg = nx + ny + nz_plant + 1
max_track_len = nx + ny + 1
!
!-- Temporary arrays storing values for csf calculation during raytracing
ALLOCATE( boxes(3,maxboxesg) )
ALLOCATE( crlens(maxboxesg) )
#if defined( __parallel )
CALL MPI_ALLGATHERV( pct, nnx*nny, MPI_INTEGER, plantt, nnxy, nnxyd, MPI_INTEGER, comm2d, &
ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHER2:', ierr, SIZE( pct ), nnx*nny, SIZE( plantt ), &
nnx*nny
FLUSH( 9 )
ENDIF
!
!-- Temporary arrays storing values for csf calculation during raytracing
ALLOCATE( lad_ip(maxboxesg) )
ALLOCATE( lad_disp(maxboxesg) )
IF ( raytrace_mpi_rma ) THEN
ALLOCATE( lad_s_ray(maxboxesg) )
!
!-- Set conditions for RMA communication
CALL MPI_INFO_CREATE( minfo, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_CREATE2:', ierr
FLUSH( 9 )
ENDIF
CALL MPI_INFO_SET( minfo, 'accumulate_ordering', 'none', ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_SET5:', ierr
FLUSH( 9 )
ENDIF
CALL MPI_INFO_SET( minfo, 'accumulate_ops', 'same_op', ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_SET6:', ierr
FLUSH( 9 )
ENDIF
IF ( .NOT. non_uniform_subdomain ) THEN
CALL MPI_INFO_SET(minfo, 'same_size', 'true', ierr)
IF ( ierr /= 0 ) THEN
WRITE(9,*) 'Error MPI_INFO_SET7:', ierr
FLUSH(9)
ENDIF
ENDIF
CALL MPI_INFO_SET( minfo, 'same_disp_unit', 'true', ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_SET8:', ierr
FLUSH( 9 )
ENDIF
!-- Allocate and initialize the MPI RMA window, must be in accordance with allocation of
!-- lad_s in plant_canopy_model, optimization of memory should be done.
!-- Argument X of function STORAGE_SIZE(X) needs arbitrary REAL(wp) value, set to 1.0_wp
!-- for now.
size_lad_rma = STORAGE_SIZE( 1.0_wp ) / 8 * nnx * nny * nz_plant
CALL MPI_WIN_ALLOCATE( size_lad_rma, STORAGE_SIZE( 1.0_wp ) / 8, minfo, comm2d, &
lad_s_rma_p, win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_ALLOCATE2:', ierr, size_lad_rma, &
STORAGE_SIZE( 1.0_wp ) / 8, win_lad
FLUSH( 9 )
ENDIF
CALL C_F_POINTER( lad_s_rma_p, lad_s_rma, (/ nz_plant*nny*nnx /) )
sub_lad(nz_urban_b:nz_plant_t, nys:nyn, nxl:nxr) => lad_s_rma(1:nz_plant*nny*nnx)
ELSE
ALLOCATE( sub_lad(nz_urban_b:nz_plant_t, nys:nyn, nxl:nxr) )
ENDIF
#else
plantt = RESHAPE( pct(nys:nyn,nxl:nxr), (/(nx+1)*(ny+1)/) )
ALLOCATE( sub_lad(nz_urban_b:nz_plant_t, nys:nyn, nxl:nxr) )
#endif
plantt_max = MAXVAL( plantt )
ALLOCATE( rt2_track(2, max_track_len), rt2_track_lad(nz_urban_b:plantt_max, max_track_len),&
rt2_track_dist(0:max_track_len), rt2_dist(plantt_max-nz_urban_b+2) )
sub_lad(:,:,:) = 0._wp
DO i = nxl, nxr
DO j = nys, nyn
k = topo_top_ind(j,i,0)
sub_lad(k:nz_plant_t, j, i) = lad_s(0:nz_plant_t-k, j, i)
ENDDO
ENDDO
#if defined( __parallel )
IF ( raytrace_mpi_rma ) THEN
CALL MPI_INFO_FREE( minfo, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_FREE2:', ierr
FLUSH( 9 )
ENDIF
CALL MPI_WIN_LOCK_ALL( 0, win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_LOCK_ALL1:', ierr, win_lad
FLUSH( 9 )
ENDIF
ELSE
ALLOCATE( sub_lad_g(0:(nx+1)*(ny+1)*nz_plant-1) )
CALL MPI_ALLGATHERV( sub_lad, nnx*nny*nz_plant, MPI_REAL, sub_lad_g, nnxy*nz_plant, &
nnxyd*nz_plant, MPI_REAL, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_ALLGATHER3:', ierr, SIZE( sub_lad ), nnx*nny*nz_plant, &
SIZE( sub_lad_g ), nnx*nny*nz_plant
FLUSH( 9 )
ENDIF
ENDIF
#endif
ENDIF
IF ( rad_angular_discretization ) THEN
!
!-- Allocate and fill the reverse indexing array gridsurf
#if defined( __parallel )
!
!-- raytrace_mpi_rma is asserted
CALL MPI_INFO_CREATE( minfo, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_CREATE1:', ierr
FLUSH( 9 )
ENDIF
CALL MPI_INFO_SET( minfo, 'accumulate_ordering', 'none', ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_SET1:', ierr
FLUSH( 9 )
ENDIF
CALL MPI_INFO_SET( minfo, 'accumulate_ops', 'same_op', ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_SET2:', ierr
FLUSH( 9 )
ENDIF
IF ( .NOT. non_uniform_subdomain ) THEN
CALL MPI_INFO_SET(minfo, 'same_size', 'true', ierr)
IF ( ierr /= 0 ) THEN
WRITE(9,*) 'Error MPI_INFO_SET3:', ierr
FLUSH(9)
ENDIF
ENDIF
CALL MPI_INFO_SET( minfo, 'same_disp_unit', 'true', ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_SET4:', ierr
FLUSH( 9 )
ENDIF
CALL MPI_WIN_ALLOCATE( INT( STORAGE_SIZE( 1_iwp ) / 8 * nsurf_type_u * nz_urban * nny * nnx,&
KIND = MPI_ADDRESS_KIND ), STORAGE_SIZE( 1_iwp ) / 8, minfo, comm2d, &
gridsurf_rma_p, win_gridsurf, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_ALLOCATE1:', ierr, &
INT( STORAGE_SIZE( 1_iwp ) / 8 * nsurf_type_u * nz_urban * nny * nnx, &
KIND = MPI_ADDRESS_KIND ), STORAGE_SIZE( 1_iwp ) / 8, win_gridsurf
FLUSH(9)
ENDIF
CALL MPI_INFO_FREE( minfo, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_INFO_FREE1:', ierr
FLUSH( 9 )
ENDIF
!
!-- On Intel compilers, calling C_F_POINTER to transform a C pointer directly to a
!-- multi-dimensional Fotran pointer leads to strange errors on dimension boundaries. However,
!-- transforming to a 1D pointer and then redirecting a multidimensional pointer to it works fine.
CALL C_F_POINTER( gridsurf_rma_p, gridsurf_rma, (/ nsurf_type_u * nz_urban * nny * nnx /) )
gridsurf(0:nsurf_type_u-1, nz_urban_b:nz_urban_t, nys:nyn, nxl:nxr) => &
gridsurf_rma(1:nsurf_type_u * nz_urban * nny * nnx)
#else
ALLOCATE( gridsurf(0:nsurf_type_u-1,nz_urban_b:nz_urban_t,nys:nyn,nxl:nxr) )
#endif
gridsurf(:,:,:,:) = -999
!
!-- Populate gridsurf with reverse global indices (->surf)
DO isurf = 1, nsurfl
gridsurf(surfl(id,isurf),surfl(iz,isurf), surfl(iy,isurf),surfl(ix,isurf)) = isurf + &
surfstart(myid)
ENDDO
#if defined( __parallel )
!
!-- Prepare the MPI_Win for collecting the surface indices from the reverse index arrays gridsurf
!-- from processors of target surfaces
!-- raytrace_mpi_rma is asserted
CALL MPI_WIN_LOCK_ALL( 0, win_gridsurf, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_LOCK_ALL2:', ierr, win_gridsurf
FLUSH( 9 )
ENDIF
#endif
ENDIF ! rad_angular_discretization
!
!-- Directions opposite to face normals are not even calculated, they must be preset to 0
dsitrans(:,:) = 0._wp
DO isurflt = 1, nsurfl
!
!-- Determine face centers
td = surfl(id, isurflt)
ta = (/ REAL( surfl(iz, isurflt), wp ) - 0.5_wp * kdir(td), &
REAL( surfl(iy, isurflt), wp ) - 0.5_wp * jdir(td), &
REAL( surfl(ix, isurflt), wp ) - 0.5_wp * idir(td) /)
!
!-- Calculate sky view factor and raytrace DSI paths
skyvf(isurflt) = 0._wp
skyvft(isurflt) = 0._wp
!
!-- Select a proper half-sphere for 2D raytracing
SELECT CASE ( td )
CASE ( iup )
az0 = 0._wp
naz = raytrace_discrete_azims
azs = 2._wp * pi / REAL( naz, wp )
zn0 = 0._wp
nzn = raytrace_discrete_elevs / 2
zns = pi / 2._wp / REAL( nzn, wp )
CASE ( idown )
az0 = 0._wp
naz = raytrace_discrete_azims
azs = 2._wp * pi / REAL( naz, wp )
zn0 = pi / 2._wp
nzn = raytrace_discrete_elevs / 2
zns = pi / 2._wp / REAL( nzn, wp )
CASE ( isouth )
az0 = pi / 2._wp
naz = raytrace_discrete_azims / 2
azs = pi / REAL( naz, wp )
zn0 = 0._wp
nzn = raytrace_discrete_elevs
zns = pi / REAL( nzn, wp )
CASE ( inorth )
az0 = - pi / 2._wp
naz = raytrace_discrete_azims / 2
azs = pi / REAL( naz, wp )
zn0 = 0._wp
nzn = raytrace_discrete_elevs
zns = pi / REAL( nzn, wp )
CASE ( iwest )
az0 = pi
naz = raytrace_discrete_azims / 2
azs = pi / REAL( naz, wp )
zn0 = 0._wp
nzn = raytrace_discrete_elevs
zns = pi / REAL( nzn, wp )
CASE ( ieast )
az0 = 0._wp
naz = raytrace_discrete_azims / 2
azs = pi / REAL( naz, wp )
zn0 = 0._wp
nzn = raytrace_discrete_elevs
zns = pi / REAL( nzn, wp )
CASE DEFAULT
WRITE( message_string, * ) 'ERROR: the surface type ', td, 'is not supported for ' // &
'calculating SVF'
CALL message( 'radiation_calc_svf', 'PA0488', 1, 2, 0, 6, 0 )
END SELECT
ALLOCATE( zdirs(1:nzn), zcent(1:nzn), zbdry(0:nzn), vffrac(1:nzn*naz), ztransp(1:nzn*naz), &
itarget(1:nzn*naz) )
itarg0 = 1
itarg1 = nzn
zcent(:) = (/( zn0 + ( REAL( izn, wp ) - .5_wp ) * zns, izn = 1, nzn )/)
zbdry(:) = (/( zn0 + REAL( izn, wp ) * zns, izn = 0, nzn )/)
IF ( td == iup ) THEN
vffrac(1:nzn) = ( COS( 2 * zbdry(0:nzn-1) ) - COS( 2 * zbdry(1:nzn) ) ) / 2._wp / &
REAL( naz, wp )
!
!-- For horizontal target, vf fractions are constant per azimuth
DO iaz = 1, naz-1
vffrac(iaz*nzn+1:(iaz+1)*nzn) = vffrac(1:nzn)
ENDDO
!
!-- Sum of whole vffrac equals 1, verified
ELSEIF ( td == idown ) THEN
vffrac(1:nzn) = - ( COS( 2 * zbdry(0:nzn-1) ) - COS( 2 * zbdry(1:nzn) ) ) / 2._wp / &
REAL( naz, wp )
DO iaz = 1, naz-1
vffrac(iaz*nzn+1:(iaz+1)*nzn) = vffrac(1:nzn)
ENDDO
!
!-- Sum of whole vffrac equals 1, verified
ENDIF
!
!-- Calculate sky-view factor and direct solar visibility using 2D raytracing
DO iaz = 1, naz
azmid = az0 + ( REAL( iaz, wp ) - .5_wp ) * azs
IF ( td /= iup .AND. td /= idown ) THEN
az2 = REAL( iaz, wp ) * azs - pi / 2._wp
az1 = az2 - azs
!
!-- TODO precalculate after 1st line
vffrac(itarg0:itarg1) = ( SIN( az2 ) - SIN( az1 ) ) * (zbdry(1:nzn) - zbdry(0:nzn-1) +&
SIN( zbdry(0:nzn-1) ) * COS( zbdry(0:nzn-1) ) - &
SIN( zbdry(1:nzn) ) * COS( zbdry(1:nzn) ) ) / ( 2._wp * pi )
!
!-- Sum of whole vffrac equals 1, verified
ENDIF
yxdir(:) = (/ COS( azmid ) / dy, SIN( azmid ) / dx /)
yxlen = SQRT( SUM( yxdir(:)**2 ) )
zdirs(:) = COS( zcent(:)) / (dz(1) * yxlen * SIN( zcent(:) ) )
yxdir(:) = yxdir(:) / yxlen
CALL raytrace_2d( ta, yxdir, nzn, zdirs, surfstart(myid) + isurflt, facearea(td), &
vffrac(itarg0:itarg1), .TRUE., .TRUE., .FALSE., ztransp(itarg0:itarg1),&
itarget(itarg0:itarg1) )
skyvf(isurflt) = skyvf(isurflt) + SUM( vffrac(itarg0:itarg1), &
MASK = ( itarget(itarg0:itarg1) < 0 ) )
skyvft(isurflt) = skyvft(isurflt) + SUM( ztransp(itarg0:itarg1) * vffrac(itarg0:itarg1), &
MASK = ( itarget(itarg0:itarg1) < 0 ) )
!
!-- Save direct solar transparency
j = MODULO( NINT( azmid / ( 2._wp * pi ) * REAL( raytrace_discrete_azims, KIND = wp ) &
- 0.5_wp, iwp ), raytrace_discrete_azims )
!
!-- For down direction there is no direct irradiance, otherwise az0=0
IF ( td /= idown ) THEN
DO k = 1, raytrace_discrete_elevs/2
i = dsidir_rev(k-1, j)
IF ( i /= -1 .AND. itarget(itarg0+k-1) < 0 ) &
dsitrans(isurflt, i) = ztransp(itarg0+k-1)
ENDDO
ENDIF
!
!-- Advance itarget indices
itarg0 = itarg1 + 1
itarg1 = itarg1 + nzn
ENDDO
IF ( rad_angular_discretization ) THEN
!
!-- Sort itarget by face id
CALL quicksort_itarget( itarget, vffrac, ztransp, 1, nzn*naz )
!
!-- For aggregation, we need fractions multiplied by transmissivities
ztransp(:) = vffrac(:) * ztransp(:)
!
!-- Find the first valid position
itarg0 = 1
DO WHILE ( itarg0 <= nzn*naz )
IF ( itarget(itarg0) >= 0 ) EXIT
itarg0 = itarg0 + 1
ENDDO
DO i = itarg0, nzn*naz
!
!-- For duplicate values, only sum up vf fraction value
IF ( i < nzn*naz ) THEN
IF ( itarget(i+1) == itarget(i) ) THEN
vffrac(i+1) = vffrac(i+1) + vffrac(i)
ztransp(i+1) = ztransp(i+1) + ztransp(i)
CYCLE
ENDIF
ENDIF
!
!-- Write to the svf array
nsvfl = nsvfl + 1
!
!-- Check dimmension of asvf array and enlarge it if needed
IF ( nsvfla < nsvfl ) THEN
k = CEILING( REAL( nsvfla, KIND = wp ) * grow_factor )
IF ( msvf == 0 ) THEN
msvf = 1
ALLOCATE( asvf1(k) )
asvf => asvf1
asvf1(1:nsvfla) = asvf2
DEALLOCATE( asvf2 )
ELSE
msvf = 0
ALLOCATE( asvf2(k) )
asvf => asvf2
asvf2(1:nsvfla) = asvf1
DEALLOCATE( asvf1 )
ENDIF
IF ( debug_output ) THEN
WRITE( debug_string, '(A,3I12)' ) 'Grow asvf:', nsvfl, nsvfla, k
CALL debug_message( debug_string, 'info' )
ENDIF
nsvfla = k
ENDIF
!
!-- Write svf values into the array
asvf(nsvfl)%isurflt = isurflt
asvf(nsvfl)%isurfs = itarget(i)
asvf(nsvfl)%rsvf = vffrac(i)
asvf(nsvfl)%rtransp = ztransp(i) / vffrac(i)
END DO
ENDIF ! rad_angular_discretization
DEALLOCATE( zdirs, zcent, zbdry, vffrac, ztransp, itarget ) ! FIXME itarget shall be allocated only
! in case of rad_angular_discretization
!
!-- Following calculations only required for surface_reflections
IF ( surface_reflections .AND. .NOT. rad_angular_discretization ) THEN
DO isurfs = 1, nsurf
IF ( .NOT. surface_facing( surfl(ix, isurflt), surfl(iy, isurflt), &
surfl(iz, isurflt), surfl(id, isurflt), surf(ix, isurfs), surf(iy, isurfs), &
surf(iz, isurfs), surf(id, isurfs) ) ) THEN
CYCLE
ENDIF
sd = surf(id, isurfs)
sa = (/ REAL( surf(iz,isurfs), wp ) - 0.5_wp * kdir(sd), &
REAL( surf(iy,isurfs), wp ) - 0.5_wp * jdir(sd), &
REAL( surf(ix,isurfs), wp ) - 0.5_wp * idir(sd) /)
!
!-- Unit vector source -> target
uv = (/ ( ta(1) - sa(1) ) * dz(1), ( ta(2) - sa(2) ) * dy, ( ta(3) - sa(3) ) * dx /)
sqdist = SUM( uv(:)**2 )
uv = uv / SQRT( sqdist )
!
!-- Reject raytracing above max distance
IF ( SQRT( sqdist ) > max_raytracing_dist ) THEN
ray_skip_maxdist = ray_skip_maxdist + 1
CYCLE
ENDIF
difvf = DOT_PRODUCT( (/ kdir(sd), jdir(sd), idir(sd) /), uv ) & ! Cosine of source normal and direction
* DOT_PRODUCT( (/ kdir(td), jdir(td), idir(td) /), - uv ) & ! Cosine of target normal and reverse direction
/ ( pi * sqdist ) ! Square of distance between centers
!
!-- Irradiance factor (our unshaded shape view factor) = view factor per
!-- differential target area * source area
rirrf = difvf * facearea(sd)
!
!-- Reject raytracing for potentially too small view factor values
IF ( rirrf < min_irrf_value ) THEN
ray_skip_minval = ray_skip_minval + 1
CYCLE
ENDIF
!
!-- Raytrace + process plant canopy sinks within
CALL raytrace( sa, ta, isurfs, difvf, facearea(td), .TRUE., visible, transparency )
IF ( .NOT. visible ) CYCLE
! rsvf = rirrf * transparency
!
!-- Write to the svf array
nsvfl = nsvfl + 1
!
!-- Check dimension of asvf array and enlarge it if needed
IF ( nsvfla < nsvfl ) THEN
k = CEILING( REAL( nsvfla, KIND = wp ) * grow_factor )
IF ( msvf == 0 ) THEN
msvf = 1
ALLOCATE( asvf1(k) )
asvf => asvf1
asvf1(1:nsvfla) = asvf2
DEALLOCATE( asvf2 )
ELSE
msvf = 0
ALLOCATE( asvf2(k) )
asvf => asvf2
asvf2(1:nsvfla) = asvf1
DEALLOCATE( asvf1 )
ENDIF
IF ( debug_output ) THEN
WRITE( debug_string, '(A,3I12)' ) 'Grow asvf:', nsvfl, nsvfla, k
CALL debug_message( debug_string, 'info' )
ENDIF
nsvfla = k
ENDIF
!
!-- Write svf values into the array
asvf(nsvfl)%isurflt = isurflt
asvf(nsvfl)%isurfs = isurfs
asvf(nsvfl)%rsvf = rirrf ! We postopne multiplication by transparency
asvf(nsvfl)%rtransp = transparency ! a.k.a. Direct Irradiance Factor
ENDDO
ENDIF
ENDDO
!
!-- Raytrace to canopy boxes to fill dsitransc
!-- TODO: consider replacing by DSI rays toward surfaces
dsitransc(:,:) = 0._wp
az0 = 0._wp
naz = raytrace_discrete_azims
azs = 2._wp * pi / REAL( naz, wp )
zn0 = 0._wp
nzn = raytrace_discrete_elevs / 2
zns = pi / 2._wp / REAL( nzn, wp )
ALLOCATE( zdirs(1:nzn), zcent(1:nzn), vffrac(1:nzn), ztransp(1:nzn), itarget(1:nzn) )
zcent(:) = (/ ( zn0 + ( REAL( izn, wp ) - .5_wp ) * zns, izn = 1, nzn ) /)
vffrac(:) = 0._wp
DO ipcgb = 1, npcbl
ta = (/ REAL( pcbl(iz,ipcgb), wp ), &
REAL( pcbl(iy,ipcgb), wp ), &
REAL( pcbl(ix,ipcgb), wp ) /)
!
!-- Calculate direct solar visibility using 2D raytracing
DO iaz = 1, naz
azmid = az0 + ( REAL( iaz, wp ) - .5_wp ) * azs
yxdir(:) = (/ COS( azmid ) / dy, SIN( azmid ) / dx /)
yxlen = SQRT( SUM( yxdir(:)**2 ) )
zdirs(:) = COS( zcent(:) ) / ( dz(1) * yxlen * SIN( zcent(:) ) )
yxdir(:) = yxdir(:) / yxlen
CALL raytrace_2d( ta, yxdir, nzn, zdirs, -999, -999._wp, vffrac, .FALSE., .FALSE., &
.TRUE., ztransp, itarget )
!
!-- Save direct solar transparency
j = MODULO( NINT( azmid / ( 2._wp * pi ) * REAL( raytrace_discrete_azims, KIND = wp ) &
- 0.5_wp, iwp ), raytrace_discrete_azims )
DO k = 1, raytrace_discrete_elevs / 2
i = dsidir_rev(k-1, j)
IF ( i /= -1 .AND. itarget(k) < 0 ) dsitransc(ipcgb, i) = ztransp(k)
ENDDO
ENDDO
ENDDO
DEALLOCATE( zdirs, zcent, vffrac, ztransp, itarget )
!
!-- Raytrace to MRT boxes
IF ( nmrtbl > 0 ) THEN
mrtdsit(:,:) = 0._wp
mrtsky(:) = 0._wp
mrtskyt(:) = 0._wp
az0 = 0._wp
naz = raytrace_discrete_azims
azs = 2._wp * pi / REAL( naz, wp )
zn0 = 0._wp
nzn = raytrace_discrete_elevs
zns = pi / REAL( nzn, wp )
ALLOCATE( zdirs(1:nzn), zcent(1:nzn), zbdry(0:nzn), vffrac(1:nzn*naz), vffrac0(1:nzn), &
ztransp(1:nzn*naz), itarget(1:nzn*naz) )
zcent(:) = (/ ( zn0 + ( REAL( izn, wp ) - .5_wp ) * zns, izn = 1, nzn ) /)
zbdry(:) = (/ ( zn0 + REAL( izn, wp ) * zns, izn = 0, nzn ) /)
vffrac0(:) = ( COS( zbdry(0:nzn-1) ) - COS( zbdry(1:nzn) ) ) / 2._wp / REAL( naz, wp )
!
!-- Modify direction weights to simulate human body (lower weight for irradiance from zenith,
!-- higher from sides) depending on selection.
!-- For mrt_geom=0, no weighting is done (simulates spherical globe thermometer).
SELECT CASE ( mrt_geom )
CASE ( 1 )
vffrac0(:) = vffrac0(:) * MAX( 0._wp, SIN( zcent(:) ) * mrt_geom_params(2) &
+ COS( zcent(:) ) * mrt_geom_params(1) )
vffrac0(:) = vffrac0(:) / ( SUM( vffrac0 ) * REAL( naz, wp ) )
CASE ( 2 )
vffrac0(:) = vffrac0(:) * SQRT( ( mrt_geom_params(1) * COS( zcent(:) ) )** 2 + &
( mrt_geom_params(2) * SIN( zcent(:) ) )** 2 )
vffrac0(:) = vffrac0(:) / ( SUM( vffrac0 ) * REAL( naz, wp ) )
END SELECT
DO imrt = 1, nmrtbl
ta = (/ REAL( mrtbl(iz,imrt), wp ), &
REAL( mrtbl(iy,imrt), wp ), &
REAL( mrtbl(ix,imrt), wp ) /)
!
!-- vf fractions are constant per azimuth
DO iaz = 0, naz-1
vffrac(iaz*nzn+1:(iaz+1)*nzn) = vffrac0(:)
ENDDO
!
!-- Sum of whole vffrac equals 1, verified
itarg0 = 1
itarg1 = nzn
!
!-- Calculate sky-view factor and direct solar visibility using 2D raytracing
DO iaz = 1, naz
azmid = az0 + ( REAL( iaz, wp ) - .5_wp ) * azs
yxdir(:) = (/ COS( azmid ) / dy, SIN( azmid ) / dx /)
yxlen = SQRT( SUM( yxdir(:)**2 ) )
zdirs(:) = COS( zcent(:) ) / ( dz(1) * yxlen * SIN( zcent(:) ) )
yxdir(:) = yxdir(:) / yxlen
CALL raytrace_2d( ta, yxdir, nzn, zdirs, -999, -999._wp, vffrac(itarg0:itarg1), &
.TRUE., .FALSE., .TRUE., ztransp(itarg0:itarg1), &
itarget(itarg0:itarg1) )
!
!-- Sky view factors for MRT
mrtsky(imrt) = mrtsky(imrt) + SUM( vffrac(itarg0:itarg1), &
MASK = ( itarget(itarg0:itarg1) < 0 ) )
mrtskyt(imrt) = mrtskyt(imrt) + SUM( ztransp(itarg0:itarg1) * vffrac(itarg0:itarg1), &
MASK = ( itarget(itarg0:itarg1) < 0 ) )
!
!-- Direct solar transparency for MRT
j = MODULO( NINT( azmid / ( 2._wp * pi ) * REAL( raytrace_discrete_azims, KIND = wp ) &
- 0.5_wp, iwp ), raytrace_discrete_azims )
DO k = 1, raytrace_discrete_elevs/2
i = dsidir_rev(k-1, j)
IF ( i /= -1 .AND. itarget(itarg0+k-1) < 0 ) &
mrtdsit(imrt, i) = ztransp(itarg0+k-1)
ENDDO
!
!-- Advance itarget indices
itarg0 = itarg1 + 1
itarg1 = itarg1 + nzn
ENDDO
!
!-- Sort itarget by face id
CALL quicksort_itarget( itarget, vffrac, ztransp, 1, nzn * naz )
!
!-- For aggregation, we need fractions multiplied by transmissivities
ztransp(:) = vffrac(:) * ztransp(:)
!
!-- Find the first valid position
itarg0 = 1
DO WHILE ( itarg0 <= nzn * naz )
IF ( itarget(itarg0) >= 0 ) EXIT
itarg0 = itarg0 + 1
ENDDO
DO i = itarg0, nzn*naz
!
!-- For duplicate values, only sum up vf fraction value
IF ( i < nzn * naz ) THEN
IF ( itarget(i+1) == itarget(i) ) THEN
vffrac(i+1) = vffrac(i+1) + vffrac(i)
ztransp(i+1) = ztransp(i+1) + ztransp(i)
CYCLE
ENDIF
ENDIF
!
!-- Some MRT geometries might contain directions with zero weight, they need to be
!-- skipped here. This check may be removed if such geometries are also removed.
IF ( vffrac(i) <= 0.0_wp ) CYCLE
!
!-- Write to the mrtf array
nmrtf = nmrtf + 1
!
!-- Check dimmension of mrtf array and enlarge it if needed
IF ( nmrtfa < nmrtf ) THEN
k = CEILING( REAL( nmrtfa, KIND = wp ) * grow_factor )
IF ( mmrtf == 0 ) THEN
mmrtf = 1
ALLOCATE( amrtf1(k) )
amrtf => amrtf1
amrtf1(1:nmrtfa) = amrtf2
DEALLOCATE( amrtf2 )
ELSE
mmrtf = 0
ALLOCATE( amrtf2(k) )
amrtf => amrtf2
amrtf2(1:nmrtfa) = amrtf1
DEALLOCATE( amrtf1 )
ENDIF
IF ( debug_output ) THEN
WRITE( debug_string, '(A,3I12)' ) 'Grow amrtf:', nmrtf, nmrtfa, k
CALL debug_message( debug_string, 'info' )
ENDIF
nmrtfa = k
ENDIF
!
!-- Write mrtf values into the array
amrtf(nmrtf)%isurflt = imrt
amrtf(nmrtf)%isurfs = itarget(i)
amrtf(nmrtf)%rsvf = vffrac(i)
amrtf(nmrtf)%rtransp = ztransp(i) / vffrac(i)
ENDDO ! itarg
ENDDO ! imrt
DEALLOCATE( zdirs, zcent, zbdry, vffrac, vffrac0, ztransp, itarget )
!
!-- Move MRT factors to final arrays
ALLOCATE( mrtf(nmrtf), mrtft(nmrtf), mrtfsurf(2,nmrtf) )
DO imrtf = 1, nmrtf
mrtf(imrtf) = amrtf(imrtf)%rsvf
mrtft(imrtf) = amrtf(imrtf)%rsvf * amrtf(imrtf)%rtransp
mrtfsurf(:,imrtf) = (/amrtf(imrtf)%isurflt, amrtf(imrtf)%isurfs /)
ENDDO
IF ( ALLOCATED( amrtf1 ) ) DEALLOCATE( amrtf1 )
IF ( ALLOCATED( amrtf2 ) ) DEALLOCATE( amrtf2 )
ENDIF ! nmrtbl > 0
IF ( rad_angular_discretization ) THEN
#if defined( __parallel )
!
!-- Finalize MPI_RMA communication established to get global index of the surface from grid
!-- indices.
!-- Flush all MPI window pending requests.
CALL MPI_WIN_FLUSH_ALL( win_gridsurf, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_FLUSH_ALL1:', ierr, win_gridsurf
FLUSH( 9 )
ENDIF
!
!-- Unlock MPI window
CALL MPI_WIN_UNLOCK_ALL( win_gridsurf, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_UNLOCK_ALL1:', ierr, win_gridsurf
FLUSH( 9 )
ENDIF
!
!-- Free MPI window
CALL MPI_WIN_FREE( win_gridsurf, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_FREE1:', ierr, win_gridsurf
FLUSH( 9 )
ENDIF
#else
DEALLOCATE( gridsurf )
#endif
ENDIF
IF ( debug_output ) CALL debug_message( 'waiting for completion of SVF and CSF ' // &
'calculation in all processes', 'info' )
!
!-- Deallocate temporary global arrays
DEALLOCATE( nzterrt, nzterrb )
IF ( plant_canopy ) THEN
!
!-- Finalize mpi_rma communication and deallocate temporary arrays
#if defined( __parallel )
IF ( raytrace_mpi_rma ) THEN
CALL MPI_WIN_FLUSH_ALL( win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_FLUSH_ALL2:', ierr, win_lad
FLUSH( 9 )
ENDIF
!
!-- Unlock MPI window
CALL MPI_WIN_UNLOCK_ALL( win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_UNLOCK_ALL2:', ierr, win_lad
FLUSH( 9 )
ENDIF
!
!-- Free MPI window
CALL MPI_WIN_FREE( win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_FREE2:', ierr, win_lad
FLUSH( 9 )
ENDIF
!
!-- Deallocate temporary arrays storing values for csf calculation during raytracing
DEALLOCATE( lad_s_ray )
!
!-- sub_lad is the pointer to lad_s_rma in case of raytrace_mpi_rma and must not be
!-- deallocated here
ELSE
DEALLOCATE( sub_lad )
DEALLOCATE( sub_lad_g )
ENDIF
#else
DEALLOCATE( sub_lad )
#endif
DEALLOCATE( boxes )
DEALLOCATE( crlens )
DEALLOCATE( plantt )
DEALLOCATE( rt2_track, rt2_track_lad, rt2_track_dist, rt2_dist )
ENDIF
IF ( debug_output ) CALL debug_message( 'calculation of the complete SVF array', 'info' )
IF ( rad_angular_discretization ) THEN
IF ( debug_output ) THEN
WRITE( debug_string, '("Load ",I0," SVFs from the structure array to plain arrays")' ) &
nsvfl
CALL debug_message( debug_string, 'info' )
ENDIF
ALLOCATE( svf(ndsvf,nsvfl) )
ALLOCATE( svfsurf(idsvf,nsvfl) )
DO isvf = 1, nsvfl
svf(:, isvf) = (/ asvf(isvf)%rsvf, asvf(isvf)%rtransp /)
svfsurf(:, isvf) = (/ asvf(isvf)%isurflt, asvf(isvf)%isurfs /)
ENDDO
ELSE
IF ( debug_output ) CALL debug_message( 'Start SVF sort', 'info' )
!
!-- Sort svf ( a version of quicksort )
CALL quicksort_svf( asvf, 1, nsvfl )
!
!-- Load svf from the structure array to plain arrays
IF ( debug_output ) THEN
WRITE( debug_string, '("Load ",I0," SVFs from the structure array to plain arrays")' ) &
nsvfl
CALL debug_message( debug_string, 'info' )
ENDIF
ALLOCATE( svf(ndsvf,nsvfl) )
ALLOCATE( svfsurf(idsvf,nsvfl) )
svfnorm_counts(:) = 0._wp
isurflt_prev = -1
ksvf = 1
svfsum = 0._wp
DO isvf = 1, nsvfl
!
!-- Normalize svf per target face
IF ( asvf(ksvf)%isurflt /= isurflt_prev ) THEN
IF ( isurflt_prev /= -1 .AND. svfsum /= 0._wp ) THEN
!
!-- Update histogram of logged svf normalization values
i = searchsorted( svfnorm_report_thresh, svfsum / &
( 1._wp - skyvf( isurflt_prev ) ) )
svfnorm_counts(i) = svfnorm_counts(i) + 1
svf(1, isvf_surflt:isvf-1) = svf(1, isvf_surflt:isvf-1) / &
svfsum * ( 1._wp - skyvf( isurflt_prev ) )
ENDIF
isurflt_prev = asvf(ksvf)%isurflt
isvf_surflt = isvf
svfsum = asvf(ksvf)%rsvf !?? / asvf(ksvf)%rtransp
ELSE
svfsum = svfsum + asvf(ksvf)%rsvf !?? / asvf(ksvf)%rtransp
ENDIF
svf(:, isvf) = (/ asvf(ksvf)%rsvf, asvf(ksvf)%rtransp /)
svfsurf(:, isvf) = (/ asvf(ksvf)%isurflt, asvf(ksvf)%isurfs /)
!
!-- Next element
ksvf = ksvf + 1
ENDDO
IF ( isurflt_prev /= -1 .AND. svfsum /= 0._wp ) THEN
i = searchsorted( svfnorm_report_thresh, svfsum / ( 1._wp - skyvf( isurflt_prev ) ) )
svfnorm_counts(i) = svfnorm_counts(i) + 1
svf(1, isvf_surflt:nsvfl) = svf(1, isvf_surflt:nsvfl) / svfsum * &
( 1._wp - skyvf(isurflt_prev) )
ENDIF
WRITE( 9, * ) 'SVF normalization histogram: ', svfnorm_counts, ' on thresholds: ', &
svfnorm_report_thresh(1:svfnorm_report_num), ' (val < thresh <= val)'
!
!-- TODO we should be able to deallocate skyvf, from now on we only need skyvft
ENDIF ! rad_angular_discretization
!
!-- Deallocate temporary asvf array
!-- DEALLOCATE(asvf) - ifort has a problem with deallocation of allocatable target via pointing
!-- pointer - we need to test original targets
IF ( ALLOCATED( asvf1 ) ) THEN
DEALLOCATE( asvf1 )
ENDIF
IF ( ALLOCATED( asvf2 ) ) THEN
DEALLOCATE( asvf2 )
ENDIF
npcsfl = 0
IF ( plant_canopy ) THEN
IF ( debug_output ) CALL debug_message( 'Calculation of the complete CSF array', 'info' )
!
!-- Sort and merge csf for the last time, keeping the array size to minimum
CALL merge_and_grow_csf( - 1 )
!
!-- Aggregate csb among processors.
!-- Allocate necessary arrays.
udim = MAX( ncsfl, 1 )
ALLOCATE( csflt_l(ndcsf*udim) )
csflt(1:ndcsf,1:udim) => csflt_l(1:ndcsf*udim)
ALLOCATE( kcsflt_l(kdcsf*udim) )
kcsflt(1:kdcsf,1:udim) => kcsflt_l(1:kdcsf*udim)
ALLOCATE( icsflt(0:numprocs-1) )
!-- Fill out arrays of csf values and arrays of number of elements and displacements for
!-- particular precessors.
icsflt = 0
ip = -1
j = -1
DO kcsf = 1, ncsfl
j = j + 1
IF ( acsf(kcsf)%ip /= ip ) THEN
!
!-- New block of the processor number of elements of previous block
IF ( ip >= 0 ) icsflt(ip) = j
!
!-- Blank blocks
DO jp = ip+1, acsf(kcsf)%ip-1
!
!-- Number of elements is zero, displacement is equal to previous
icsflt(jp) = 0
ENDDO
!
!-- The actual block
ip = acsf(kcsf)%ip
j = 0
ENDIF
csflt(1,kcsf) = acsf(kcsf)%rcvf
!
!-- Fill out integer values of itz,ity,itx,isurfs
kcsflt(1,kcsf) = acsf(kcsf)%itz
kcsflt(2,kcsf) = acsf(kcsf)%ity
kcsflt(3,kcsf) = acsf(kcsf)%itx
kcsflt(4,kcsf) = acsf(kcsf)%isurfs
ENDDO
!
!-- Last blank blocks at the end of array
j = j+1
IF ( ip >= 0 ) icsflt(ip) = j
DO jp = ip+1, numprocs-1
!
!-- Number of elements is zero, displacement is equal to previous
icsflt(jp) = 0
ENDDO
!
!-- Deallocate temporary acsf array
!-- DEALLOCATE(acsf) - ifort has a problem with deallocation of allocatable target via pointing
!-- pointer - we need to test original targets
IF ( ALLOCATED( acsf1 ) ) THEN
DEALLOCATE( acsf1 )
ENDIF
IF ( ALLOCATED( acsf2 ) ) THEN
DEALLOCATE( acsf2 )
ENDIF
#if defined( __parallel )
!
!-- Exchange csf fields between processors
IF ( debug_output ) CALL debug_message( 'Exchange CSF fields between processors', 'start' )
CALL radiation_exchange_alltoall( icsflt, kdcsf, ndcsf, kcsflt_l, csflt_l, npcsfl, &
kpcsflt_l, pcsflt_l )
pcsflt(1:ndcsf,1:npcsfl) => pcsflt_l(0:ndcsf*npcsfl-1)
kpcsflt(1:kdcsf,1:npcsfl) => kpcsflt_l(0:kdcsf*npcsfl-1)
IF ( debug_output ) CALL debug_message( 'Exchange CSF fields between processors', 'end' )
#else
npcsfl = ncsfl
ALLOCATE( pcsflt(ndcsf,MAX( npcsfl, ndcsf )) )
ALLOCATE( kpcsflt(kdcsf,MAX( npcsfl,kdcsf )) )
pcsflt = csflt
kpcsflt = kcsflt
!
!-- Just silence compiler warning about unused variable
IF ( bufsize_alltoall <= 0 ) bufsize_alltoall = 0
#endif
!
!-- Deallocate temporary arrays
DEALLOCATE( csflt_l )
DEALLOCATE( kcsflt_l )
DEALLOCATE( icsflt )
!
!-- Sort csf ( a version of quicksort )
IF ( debug_output ) CALL debug_message( 'Sort csf', 'info' )
CALL quicksort_csf2( kpcsflt, pcsflt, 1, npcsfl )
!
!-- Aggregate canopy sink factor records with identical box & source againg across all values
!-- from all processors
IF ( debug_output ) CALL debug_message( 'Aggregate canopy sink factor records with ' // &
'identical box', 'info' )
IF ( npcsfl > 0 ) THEN
icsf = 1 !< reading index
kcsf = 1 !< writing index
DO WHILE ( icsf < npcsfl )
!
!-- Here kpcsf(kcsf) already has values from kpcsf(icsf)
IF ( kpcsflt(3,icsf) == kpcsflt(3,icsf+1) .AND. &
kpcsflt(2,icsf) == kpcsflt(2,icsf+1) .AND. &
kpcsflt(1,icsf) == kpcsflt(1,icsf+1) .AND. &
kpcsflt(4,icsf) == kpcsflt(4,icsf+1) ) THEN
pcsflt(1,kcsf) = pcsflt(1,kcsf) + pcsflt(1,icsf+1)
!
!-- Advance reading index, keep writing index
icsf = icsf + 1
ELSE
!
!-- Not identical, just advance and copy
icsf = icsf + 1
kcsf = kcsf + 1
kpcsflt(:,kcsf) = kpcsflt(:,icsf)
pcsflt(:,kcsf) = pcsflt(:,icsf)
ENDIF
ENDDO
!
!-- Last written item is now also the last item in valid part of array
npcsfl = kcsf
ENDIF
ncsfl = npcsfl
IF ( ncsfl > 0 ) THEN
ALLOCATE( csf(ndcsf,ncsfl) )
ALLOCATE( csfsurf(idcsf,ncsfl) )
DO icsf = 1, ncsfl
csf(:,icsf) = pcsflt(:,icsf)
csfsurf(1,icsf) = gridpcbl(kpcsflt(1,icsf),kpcsflt(2,icsf),kpcsflt(3,icsf))
csfsurf(2,icsf) = kpcsflt(4,icsf)
ENDDO
ENDIF
!
!-- Deallocation of temporary arrays
IF ( npcbl > 0 ) DEALLOCATE( gridpcbl )
DEALLOCATE( pcsflt_l )
DEALLOCATE( kpcsflt_l )
IF ( debug_output ) THEN
WRITE( debug_string, '("Finished aggregating ",I0," CSFs.")' ) ncsfl
CALL debug_message( debug_string, 'info' )
ENDIF
ENDIF
#if defined( __parallel )
CALL MPI_BARRIER( comm2d, ierr )
#endif
CALL location_message( 'calculating view factors for radiation interaction', 'finished' )
RETURN ! Todo: remove
! WRITE( message_string, * ) &
! 'I/O error when processing shape view factors / ', &
! 'plant canopy sink factors / direct irradiance factors.'
! CALL message( 'init_urban_surface', 'PA0502', 2, 2, 0, 6, 0 )
END SUBROUTINE radiation_calc_svf
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Raytracing for detecting obstacles and calculating compound canopy sink factors for RTM.
!> (A simple obstacle detection would only need to process faces in 3 dimensions without any
!> ordering.)
!> Assumtions:
!> -----------
!> 1. The ray always originates from a face midpoint (only one coordinate equals *.5, i.e. wall)
!> and doesn't travel parallel to the surface (that would mean shape factor=0). Therefore, the
!> ray may never travel exactly along a face or an edge.
!> 2. From grid bottom to urban surface top the grid has to be *equidistant* within each of the
!> dimensions, including vertical (but the resolution doesn't need to be the same in all three
!> dimensions).
!--------------------------------------------------------------------------------------------------!
SUBROUTINE raytrace( src, targ, isrc, difvf, atarg, create_csf, visible, transparency )
IMPLICIT NONE
INTEGER(iwp) :: ig !< 1D index of gridbox in global 2D array
INTEGER(iwp) :: i, k, d !<
INTEGER(iwp) :: maxboxes !< max no of gridboxes visited
INTEGER(iwp) :: ncsb !< no of written plant canopy sinkboxes
INTEGER(iwp) :: seldim !< dimension to be incremented
INTEGER(iwp), INTENT(IN) :: isrc !< index of source face for csf
INTEGER(iwp), DIMENSION(3) :: box !< gridbox being crossed
INTEGER(iwp), DIMENSION(3) :: dimnext !< next dimension increments along path
INTEGER(iwp), DIMENSION(3) :: dimdelta !< dimension direction = +- 1
LOGICAL, INTENT(IN) :: create_csf !< whether to generate new CSFs during raytracing
LOGICAL, INTENT(OUT) :: visible !<
REAL(wp) :: crmid !< midpoint of crossing
REAL(wp) :: cursink !< sink factor for current canopy box
REAL(wp) :: crlen !< length of gridbox crossing
REAL(wp) :: distance !< euclidean along path
REAL(wp) :: lastdist !< beginning of current crossing
REAL(wp) :: nextdist !< end of current crossing
REAL(wp) :: realdist !< distance in meters per unit distance
REAL(wp) :: eps = 1E-10_wp !< epsilon for value comparison
REAL(wp) :: lad_s_target !< recieved lad_s of particular grid box
REAL(wp), INTENT(IN) :: atarg !< target surface area for csf
REAL(wp), INTENT(IN) :: difvf !< differential view factor for csf
REAL(wp), INTENT(OUT) :: transparency !< along whole path
REAL(wp), DIMENSION(3) :: delta !< path vector
REAL(wp), DIMENSION(3) :: dimnextdist !< distance for each dimension increments
REAL(wp), DIMENSION(3) :: uvect !< unit vector
REAL(wp), DIMENSION(3), INTENT(IN) :: src, targ !< real coordinates z,y,x
!
!-- Maximum number of gridboxes visited equals maximum number of boundaries crossed in each
!-- dimension plus one. That's also the maximum number of plant canopy boxes written. We grow the
!-- acsf array accordingly using exponential factor.
maxboxes = SUM( ABS( NINT( targ, iwp ) - NINT( src, iwp ) ) ) + 1
IF ( plant_canopy .AND. ncsfl + maxboxes > ncsfla ) THEN
!
!-- Use this code for growing by fixed exponential increments (equivalent to case where ncsfl
!-- always increases by 1)
!-- k = CEILING(grow_factor ** real(CEILING(log(real(ncsfl + maxboxes, kind=wp)) &
!-- / log(grow_factor)), kind=wp))
!-- Or use this code to simply always keep some extra space after growing
k = CEILING( REAL( ncsfl + maxboxes, KIND = wp ) * grow_factor )
CALL merge_and_grow_csf( k )
ENDIF
transparency = 1._wp
ncsb = 0
delta(:) = targ(:) - src(:)
distance = SQRT( SUM( delta(:)**2 ) )
IF ( distance == 0._wp ) THEN
visible = .TRUE.
RETURN
ENDIF
uvect(:) = delta(:) / distance
realdist = SQRT( SUM( ( uvect(:) * (/ dz(1), dy, dx /) )**2 ) )
lastdist = 0._wp
!
!-- Since all face coordinates have values *.5 and we'd like to use integers, all these have .5
!-- added
DO d = 1, 3
IF ( uvect(d) == 0._wp ) THEN
dimnext(d) = 999999999
dimdelta(d) = 999999999
dimnextdist(d) = 1.0E20_wp
ELSE IF ( uvect(d) > 0._wp ) THEN
dimnext(d) = CEILING( src(d) + .5_wp )
dimdelta(d) = 1
dimnextdist(d) = ( dimnext(d) - .5_wp - src(d) ) / uvect(d)
ELSE
dimnext(d) = FLOOR( src(d) + .5_wp )
dimdelta(d) = -1
dimnextdist(d) = ( dimnext(d) - .5_wp - src(d) ) / uvect(d)
ENDIF
ENDDO
DO
!
!-- Along what dimension will the next wall crossing be?
seldim = MINLOC( dimnextdist, 1 )
nextdist = dimnextdist(seldim)
IF ( nextdist > distance ) nextdist = distance
crlen = nextdist - lastdist
IF ( crlen > .001_wp ) THEN
crmid = ( lastdist + nextdist ) * .5_wp
box = NINT( src(:) + uvect(:) * crmid, iwp )
!
!-- Calculate index of the grid with global indices (box(2),box(3)) in the array nzterr and
!-- plantt and id of the coresponding processor
CALL radiation_calc_global_offset( box(3), box(2), 0, 1, offs_glob = ig )
IF ( box(1) <= nzterrb(ig) ) THEN
visible = .FALSE.
RETURN
ENDIF
IF ( plant_canopy ) THEN
IF ( box(1) <= plantt(ig) ) THEN
ncsb = ncsb + 1
boxes(:,ncsb) = box
crlens(ncsb) = crlen
#if defined( __parallel )
CALL radiation_calc_global_offset( box(3), box(2), box(1) - nz_urban_b, &
nz_plant, iproc = lad_ip(ncsb), &
offs_proc = lad_disp(ncsb) )
#endif
ENDIF
ENDIF
ENDIF
IF ( ABS( distance - nextdist ) < eps ) EXIT
lastdist = nextdist
dimnext(seldim) = dimnext(seldim) + dimdelta(seldim)
dimnextdist(seldim) = ( dimnext(seldim) - .5_wp - src(seldim) ) / uvect(seldim)
ENDDO
IF ( plant_canopy ) THEN
#if defined( __parallel )
IF ( raytrace_mpi_rma ) THEN
!
!-- Send requests for lad_s to appropriate processor
CALL cpu_log( log_point_s(77), 'rad_rma_lad', 'start' )
DO i = 1, ncsb
CALL MPI_GET( lad_s_ray(i), 1, MPI_REAL, lad_ip(i), lad_disp(i), 1, MPI_REAL, &
win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_GET1:', ierr, lad_s_ray(i), lad_ip(i), lad_disp(i), &
win_lad
FLUSH( 9 )
ENDIF
ENDDO
!
!-- Wait for all pending local requests to complete
CALL MPI_WIN_FLUSH_LOCAL_ALL( win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_FLUSH_LOCAL_ALL1:', ierr, win_lad
FLUSH( 9 )
ENDIF
CALL cpu_log( log_point_s(77), 'rad_rma_lad', 'stop' )
ENDIF
#endif
!
!-- Calculate csf and transparency
DO i = 1, ncsb
#if defined( __parallel )
IF ( raytrace_mpi_rma ) THEN
lad_s_target = lad_s_ray(i)
ELSE
lad_s_target = sub_lad_g(lad_ip(i)*nnx*nny*nz_plant+lad_disp(i))
ENDIF
#else
lad_s_target = sub_lad(boxes(1,i),boxes(2,i),boxes(3,i))
#endif
IF ( lad_s_target <= 0.0_wp ) CYCLE ! Under LAD top, but LAD=0
cursink = 1._wp - EXP( - ext_coef * lad_s_target * crlens(i) * realdist )
IF ( create_csf ) THEN
!
!-- Write svf values into the array
ncsfl = ncsfl + 1
acsf(ncsfl)%ip = lad_ip(i)
acsf(ncsfl)%itx = boxes(3,i)
acsf(ncsfl)%ity = boxes(2,i)
acsf(ncsfl)%itz = boxes(1,i)
acsf(ncsfl)%isurfs = isrc
acsf(ncsfl)%rcvf = cursink * transparency * difvf * atarg
ENDIF !< create_csf
transparency = transparency * ( 1._wp - cursink )
ENDDO
ENDIF
visible = .TRUE.
END SUBROUTINE raytrace
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> A new, more efficient version of ray tracing algorithm that processes a whole arc instead of a
!> single ray (new in RTM version 2.5).
!>
!> In all comments, horizon means tangent of horizon angle, i.e. vertical_delta /
!> horizontal_distance
!--------------------------------------------------------------------------------------------------!
SUBROUTINE raytrace_2d( origin, yxdir, nrays, zdirs, iorig, aorig, vffrac, calc_svf, create_csf, &
skip_1st_pcb, transparency, itarget )
IMPLICIT NONE
INTEGER(iwp) :: i, k, l, d !<
INTEGER(iwp) :: iray !< index into zdirs
INTEGER(iwp) :: isurf !< index into surf(l)
INTEGER(iwp) :: ip !< number of processor where gridbox reside
INTEGER(iwp) :: ip_last !< previous number of processor where gridbox reside
INTEGER(iwp) :: ig !< 1D index of grid column in global 2D array
INTEGER(iwp) :: ig_last !< 1D index of previous column in global 2D array
INTEGER(iwp) :: kz !<
INTEGER(iwp) :: lastdir !< wall direction before hitting this column
INTEGER(iwp) :: lowest_free_ray !< index into zdirs
INTEGER(iwp) :: lowest_mixed_ray !< index into zdirs
INTEGER(iwp) :: maxboxes !< max no of CSF created
INTEGER(iwp) :: nrays !< number of rays (z directions) to raytrace
INTEGER(iwp) :: nly !< maximum plant canopy height
INTEGER(iwp) :: ntrack !<
INTEGER(iwp) :: zb0 !<
INTEGER(iwp) :: zb1 !<
INTEGER(iwp) :: nz !<
INTEGER(iwp) :: seldim !< dimension to be incremented
INTEGER(iwp) :: zsgn !<
INTEGER(iwp), INTENT(IN) :: iorig !< index of origin face for csf
INTEGER(iwp), DIMENSION(2) :: column !< grid column being crossed
INTEGER(iwp), DIMENSION(2) :: dimnext !< next dimension increments along path
INTEGER(iwp), DIMENSION(2) :: dimdelta !< dimension direction = +- 1
INTEGER(iwp), DIMENSION(2) :: lastcolumn !<
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: down_col !< downward oriented surfaces in current column
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: up_col !< upward oriented surfaces in current column
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: vert_col !< vertical faces from previous to current column
INTEGER(iwp), DIMENSION(nrays), INTENT(OUT) :: itarget !< global indices of target faces for zdirs or <0 for sky
LOGICAL :: is_mixed_col !< whether current column contains full-3D geometry
LOGICAL, INTENT(IN) :: calc_svf !< whether to calculate SFV (identify obstacle surfaces)
LOGICAL, INTENT(IN) :: create_csf !< whether to create canopy sink factors
LOGICAL, INTENT(IN) :: skip_1st_pcb !< whether to skip first plant canopy box during raytracing
REAL(wp) :: crmid !< midpoint of crossing
REAL(wp) :: bdydim !< boundary for current dimension
REAL(wp) :: distance !< euclidean along path
REAL(wp) :: full_horizon !< highest full horizon found after raytracing (z/hdist)
REAL(wp) :: horz_full_entry !< full horizon at entry to column
REAL(wp) :: horz_full_exit !< full horizon at exit from column
REAL(wp) :: horz_mixed_entry !< mixed horizon at entry to column
REAL(wp) :: horz_mixed_exit !< mixed horizon at exit from column
REAL(wp) :: lastdist !< beginning of current crossing
REAL(wp) :: nextdist !< end of current crossing
REAL(wp), INTENT(IN) :: aorig !< origin face area for csf
REAL(wp), DIMENSION(2) :: crossdist !< distances to boundary for dimensions
REAL(wp), DIMENSION(2) :: dimnextdist !< distance for each dimension increments
REAL(wp), DIMENSION(2) :: yxorigin !< horizontal copy of origin (y,x)
REAL(wp), DIMENSION(2), INTENT(IN) :: yxdir !< y,x *unit* vector of ray direction (in grid units)
REAL(wp), DIMENSION(3), INTENT(IN) :: origin !< z,y,x coordinates of ray origin
REAL(wp), DIMENSION(nrays), INTENT(IN) :: vffrac !< view factor fractions of each ray for csf
REAL(wp), DIMENSION(nrays), INTENT(IN) :: zdirs !< list of z directions to raytrace (z/hdist, grid, zenith->nadir)
REAL(wp), DIMENSION(nrays), INTENT(OUT) :: transparency !< transparencies of zdirs paths
#if defined( __parallel )
INTEGER(iwp) :: lowest_lad !< lowest column cell for which we need LAD
INTEGER(iwp) :: wcount !< RMA window item count
INTEGER(MPI_ADDRESS_KIND) :: wdisp !< RMA window displacement
#endif
REAL(wp) :: curtrans !< transparency of current PC box crossing
REAL(wp) :: dxxyy !< square of real horizontal distance
REAL(wp) :: eps = 1E-10_wp !< epsilon for value comparison
REAL(wp) :: qdist !< ratio of real distance to z coord difference
REAL(wp) :: zbottom, ztop !< urban surface boundary in real numbers
REAL(wp) :: zorig !< z coordinate of ray column entry
REAL(wp) :: zexit !< z coordinate of ray column exit
yxorigin(:) = origin(2:3)
transparency(:) = 1._wp !-- Pre-set the all rays to transparent before reducing
full_horizon = - HUGE( 1._wp )
lowest_mixed_ray = nrays
lowest_free_ray = nrays
IF ( rad_angular_discretization ) THEN
ALLOCATE( target_surfl(nrays) )
target_surfl(:) = -1
lastdir = -999
lastcolumn(:) = -999
ALLOCATE( vert_col(nz_urban_b:nz_urban_t) )
ALLOCATE( up_col(nz_urban_b:nz_urban_t) )
ALLOCATE( down_col(nz_urban_b:nz_urban_t) )
ENDIF
!
!-- Determine distance to boundary (in 2D xy)
IF ( yxdir(1) > 0._wp ) THEN
bdydim = ny + .5_wp !< North global boundary
crossdist(1) = ( bdydim - yxorigin(1) ) / yxdir(1)
ELSEIF ( yxdir(1) == 0._wp ) THEN
crossdist(1) = HUGE( 1._wp )
ELSE
bdydim = - .5_wp !< South global boundary
crossdist(1) = ( bdydim - yxorigin(1) ) / yxdir(1)
ENDIF
IF ( yxdir(2) > 0._wp ) THEN
bdydim = nx + .5_wp !< East global boundary
crossdist(2) = ( bdydim - yxorigin(2) ) / yxdir(2)
ELSEIF ( yxdir(2) == 0._wp ) THEN
crossdist(2) = HUGE( 1._wp )
ELSE
bdydim = -.5_wp !< West global boundary
crossdist(2) = ( bdydim - yxorigin(2) ) / yxdir(2)
ENDIF
distance = MINVAL( crossdist, 1 )
IF ( plant_canopy ) THEN
rt2_track_dist(0) = 0._wp
rt2_track_lad(:,:) = 0._wp
nly = plantt_max - nz_urban_b + 1
ENDIF
ip_last = -1
ig_last = -1
lastdist = 0._wp
!-- Since all face coordinates have values *.5 and we'd like to use integers, all these have
!-- .5 added
DO d = 1, 2
IF ( yxdir(d) == 0._wp ) THEN
dimnext(d) = HUGE( 1_iwp )
dimdelta(d) = HUGE( 1_iwp )
dimnextdist(d) = HUGE( 1._wp )
ELSE IF ( yxdir(d) > 0._wp ) THEN
dimnext(d) = FLOOR( yxorigin(d) + .5_wp ) + 1
dimdelta(d) = 1
dimnextdist(d) = ( dimnext(d) - .5_wp - yxorigin(d) ) / yxdir(d)
ELSE
dimnext(d) = CEILING( yxorigin(d) + .5_wp ) - 1
dimdelta(d) = -1
dimnextdist(d) = ( dimnext(d) - .5_wp - yxorigin(d) ) / yxdir(d)
ENDIF
ENDDO
ntrack = 0
DO
!
!-- Along what dimension will the next wall crossing be?
seldim = MINLOC( dimnextdist, 1 )
nextdist = dimnextdist(seldim)
IF ( nextdist > distance ) nextdist = distance
IF ( nextdist > lastdist ) THEN
ntrack = ntrack + 1
crmid = ( lastdist + nextdist ) * .5_wp
column = NINT( yxorigin(:) + yxdir(:) * crmid, iwp )
!
!-- Calculate index of the grid with global indices (column(1),column(2)) in the array
!-- nzterrt/b and plantt and id of the coresponding processor
CALL radiation_calc_global_offset( column(2), column(1), 0, 1, iproc = ip, &
offs_glob = ig )
IF ( ip_last < 0 ) THEN
horz_full_entry = - HUGE( 1._wp )
horz_mixed_entry = - HUGE( 1._wp )
ELSE
horz_full_entry = ( REAL( nzterrb(ig), wp ) + .5_wp - origin(1) ) / lastdist
horz_mixed_entry = ( REAL( nzterrt(ig), wp ) + .5_wp - origin(1) ) / lastdist
ENDIF
horz_full_exit = ( REAL( nzterrb(ig), wp ) + .5_wp - origin(1) ) / nextdist
horz_mixed_exit = ( REAL( nzterrt(ig), wp ) + .5_wp - origin(1) ) / nextdist
is_mixed_col = ( nzterrt(ig) /= nzterrb(ig) )
IF ( rad_angular_discretization ) THEN
!
!-- Identify vertical full obstacles hit by rays in current column, mixed rays need to be
!-- checked if they are already obstructed.
DO WHILE ( lowest_mixed_ray > lowest_free_ray )
IF ( zdirs(lowest_mixed_ray) > horz_full_entry ) EXIT
!
!-- This may only happen after 1st column, so lastdir and lastcolumn are valid
IF ( target_surfl(lowest_mixed_ray) < 0 ) THEN
CALL request_itarget( lastdir, CEILING( - 0.5_wp + origin(1) + &
zdirs(lowest_mixed_ray) * lastdist ), &
lastcolumn(1), lastcolumn(2), &
target_surfl(lowest_mixed_ray) )
ENDIF
lowest_mixed_ray = lowest_mixed_ray - 1
ENDDO
!
!-- Identify vertical full obstacles hit by rays in current column, free rays need no
!-- individual checks.
DO WHILE ( lowest_mixed_ray > 0 )
IF ( zdirs(lowest_mixed_ray) > horz_full_entry ) EXIT
!
!-- This may only happen after 1st column, so lastdir and lastcolumn are valid
CALL request_itarget( lastdir, CEILING( - 0.5_wp + origin(1) + &
zdirs(lowest_mixed_ray) * lastdist ), &
lastcolumn(1), lastcolumn(2), target_surfl(lowest_mixed_ray) )
lowest_mixed_ray = lowest_mixed_ray - 1
ENDDO
IF ( lowest_free_ray > lowest_mixed_ray ) lowest_free_ray = lowest_mixed_ray
!
!-- Identify targets for vertical mixed obstacles.
!-- lowest_mixed_ray now points to bottom of vertical mixed obstacles.
IF ( is_mixed_col .AND. ip_last >= 0 ) THEN
!
!-- Load vertical surfaces belonging to previous column
vert_col(:) = -999
DO isurf = surfg_col_start(ig_last), surfg_col_start(ig_last+1)-1
IF ( surf(id, isurf) == lastdir ) THEN
vert_col(surf(iz, isurf)) = isurf
ENDIF
ENDDO
!
!-- Previously mixed rays need to be checked whether they are obstructed
DO iray = lowest_mixed_ray, lowest_free_ray+1, -1
IF ( zdirs(iray) > horz_mixed_entry ) EXIT
IF ( target_surfl(iray) >= 0 ) CYCLE
target_surfl(iray) = vert_col( CEILING( - 0.5_wp + origin(1) + &
zdirs(iray) * lastdist) ) ! Contains -999 if missing surface
ENDDO
!
!-- Previously free rays cannot be obstructed yet
DO iray = lowest_free_ray, 1, -1
IF ( zdirs(iray) > horz_mixed_entry ) THEN
!
!-- Extend mixed rays by raising the lowest_free ray (remains unchanged if this is
!-- hit in 1st iteration)
lowest_free_ray = iray
EXIT
ENDIF
target_surfl(iray) = vert_col( CEILING( - 0.5_wp + origin(1) + zdirs(iray) * &
lastdist ) ) ! Contains -999 if missing surface
ENDDO
ENDIF ! End of mixed horizon
!
!-- Identify horizontal full obstacles hit by rays in current column, mixed rays need to be
!-- checked if they are already obstructed.
DO WHILE ( lowest_mixed_ray > lowest_free_ray )
IF ( zdirs(lowest_mixed_ray) > horz_full_exit ) EXIT
IF ( target_surfl(lowest_mixed_ray) < 0 ) THEN
CALL request_itarget( iup, nzterrb(ig)+1, column(1), column(2), &
target_surfl(lowest_mixed_ray) )
ENDIF
lowest_mixed_ray = lowest_mixed_ray - 1
ENDDO
!
!-- Identify horizontal full obstacles hit by rays in current column, free rays need no
!-- individual checks.
DO WHILE ( lowest_mixed_ray > 0 )
IF ( zdirs(lowest_mixed_ray) > horz_full_exit ) EXIT
CALL request_itarget( iup, nzterrb(ig)+1, column(1), column(2), &
target_surfl(lowest_mixed_ray) )
lowest_mixed_ray = lowest_mixed_ray - 1
ENDDO
IF ( lowest_free_ray > lowest_mixed_ray ) lowest_free_ray = lowest_mixed_ray
!
!-- Identify targets for horizontal mixed obstacles.
!-- lowest_mixed_ray now points _above_ horizontal full obstacles.
IF ( is_mixed_col ) THEN
!
!-- Load horizontal surfaces corresponding to current column
up_col(:) = - 999
down_col(:) = - 999
DO isurf = surfg_col_start(ig), surfg_col_start(ig+1)-1
SELECT CASE ( surf(id, isurf) )
CASE ( iup )
up_col(surf(iz, isurf)) = isurf
CASE ( idown )
down_col(surf(iz, isurf)) = isurf
ENDSELECT
ENDDO
!
!-- Previously mixed rays need to be checked whether they are obstructed
DO iray = lowest_mixed_ray, lowest_free_ray+1, -1
IF ( zdirs(iray) > MAX( horz_mixed_entry, horz_mixed_exit ) ) EXIT
IF ( target_surfl(iray) >= 0 ) CYCLE
IF ( zdirs(iray) <= 0._wp ) THEN
!
!-- Downward pointed ray, cycle k down from entry to exit, search for upward
!-- oriented faces
DO k = FLOOR( 0.5_wp + origin(1) + zdirs(iray) * lastdist ), &
CEILING( - 0.5_wp + origin(1) + zdirs(iray) * nextdist ) + 1, - 1
target_surfl(iray) = up_col(k) ! Contains -999 if missing surface
IF ( target_surfl(iray) >= 0 ) EXIT
ENDDO
ELSE
!
!-- Upward pointed ray, cycle k up from entry to exit, search for downward
!-- oriented faces
DO k = CEILING( - 0.5_wp + origin(1) + zdirs(iray) * lastdist ), &
FLOOR( 0.5_wp + origin(1) + zdirs(iray) * nextdist ) - 1
target_surfl(iray) = down_col(k) ! Contains -999 if missing surface
IF ( target_surfl(iray) >= 0 ) EXIT
ENDDO
ENDIF
ENDDO
!
!-- Previously free rays cannot be obstructed yet
DO iray = lowest_free_ray, 1, -1
IF ( zdirs(iray) > MAX( horz_mixed_entry, horz_mixed_exit ) ) THEN
!
!-- Extend mixed rays by raising the lowest_free ray (remains unchanged if this is
!-- hit in 1st iteration)
lowest_free_ray = iray
EXIT
ENDIF
IF ( zdirs(iray) <= 0._wp ) THEN
!
!-- Downward pointed ray, cycle k down from entry to exit, search upward oriented
!-- faces
DO k = FLOOR( 0.5_wp + origin(1) + zdirs(iray) * lastdist ), &
CEILING( - 0.5_wp + origin(1) + zdirs(iray) * nextdist) + 1, - 1
target_surfl(iray) = up_col(k) ! Contains -999 if missing surface
IF ( target_surfl(iray) >= 0 ) EXIT
ENDDO
ELSE
!
!-- Upward pointed ray, cycle k up from entry to exit, search downward oriented
!-- faces
DO k = CEILING( - 0.5_wp + origin(1) + zdirs(iray) * lastdist ), &
FLOOR( 0.5_wp + origin(1) + zdirs(iray) * nextdist ) - 1
target_surfl(iray) = down_col(k) ! Contains -999 if missing surface
IF ( target_surfl(iray) >= 0 ) EXIT
ENDDO
ENDIF
ENDDO
ENDIF ! End of mixed horizon
ENDIF ! rad_angular_discretization
full_horizon = MAX( full_horizon, horz_full_entry, horz_full_exit )
IF ( plant_canopy ) THEN
rt2_track(:, ntrack) = column(:)
rt2_track_dist(ntrack) = nextdist
ENDIF
ENDIF
IF ( nextdist + eps >= distance ) EXIT
IF ( rad_angular_discretization ) THEN
!
!-- Save wall direction of coming building column (= this air column)
IF ( seldim == 1 ) THEN
IF ( dimdelta(seldim) == 1 ) THEN
lastdir = isouth
ELSE
lastdir = inorth
ENDIF
ELSE
IF ( dimdelta(seldim) == 1 ) THEN
lastdir = iwest
ELSE
lastdir = ieast
ENDIF
ENDIF
lastcolumn = column
ENDIF
ip_last = ip
ig_last = ig
lastdist = nextdist
dimnext(seldim) = dimnext(seldim) + dimdelta(seldim)
dimnextdist(seldim) = ( dimnext(seldim) - .5_wp - yxorigin(seldim) ) / yxdir(seldim)
ENDDO
IF ( plant_canopy ) THEN
!
!-- Request LAD WHERE applicable
#if defined( __parallel )
IF ( raytrace_mpi_rma ) THEN
!
!-- Send requests for lad_s to appropriate processor
!CALL cpu_log( log_point_s(77), 'usm_init_rma', 'start' )
DO i = 1, ntrack
CALL radiation_calc_global_offset( rt2_track(2,i), rt2_track(1,i), 0, 1, &
offs_glob = ig )
IF ( rad_angular_discretization .AND. calc_svf ) THEN
!
!-- For fixed view resolution, we need plant canopy even for rays to opposing surfaces
lowest_lad = nzterrb(ig) + 1
ELSE
!
!-- We only need LAD for rays directed above full horizon (to sky)
lowest_lad = CEILING( - 0.5_wp + origin(1) + &
MIN( full_horizon * rt2_track_dist(i-1), & ! Entry
full_horizon * rt2_track_dist(i) ) ) ! Exit
ENDIF
!
!-- Skip asking for LAD where all plant canopy is under requested level
IF ( plantt(ig) < lowest_lad ) CYCLE
CALL radiation_calc_global_offset( rt2_track(2,i), rt2_track(1,i), &
lowest_lad - nz_urban_b, nz_plant, iproc = ip, &
offs_proc = wdisp )
wcount = plantt(ig) - lowest_lad + 1
!
!-- TODO: send request ASAP - even during raytracing
CALL MPI_GET( rt2_track_lad(lowest_lad:plantt(ig), i), wcount, MPI_REAL, ip, wdisp, &
wcount, MPI_REAL, win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_GET2:', ierr, rt2_track_lad(lowest_lad:plantt(ig), i), &
wcount, ip, wdisp, win_lad
FLUSH( 9 )
ENDIF
ENDDO
!
!-- Wait for all pending local requests to complete
!-- TODO: Wait selectively for each column later when needed
CALL MPI_WIN_FLUSH_LOCAL_ALL( win_lad, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_FLUSH_LOCAL_ALL2:', ierr, win_lad
FLUSH( 9 )
ENDIF
!CALL cpu_log( log_point_s(77), 'usm_init_rma', 'stop' )
ELSE ! raytrace_mpi_rma = .F.
DO i = 1, ntrack
CALL radiation_calc_global_offset( rt2_track(2,i), rt2_track(1,i), 0, nz_plant, &
offs_glob = ig )
rt2_track_lad(nz_urban_b:plantt_max, i) = sub_lad_g(ig:ig+nly-1)
ENDDO
ENDIF
#else
DO i = 1, ntrack
rt2_track_lad(nz_urban_b:plantt_max, i) = sub_lad(rt2_track(1,i), rt2_track(2,i), &
nz_urban_b:plantt_max)
ENDDO
#endif
ENDIF ! plant_canopy
IF ( rad_angular_discretization ) THEN
#if defined( __parallel )
!
!-- Wait for all gridsurf requests to complete
CALL MPI_WIN_FLUSH_LOCAL_ALL( win_gridsurf, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_WIN_FLUSH_LOCAL_ALL3:', ierr, win_gridsurf
FLUSH( 9 )
ENDIF
#endif
itarget(:) = target_surfl(:)
DEALLOCATE( target_surfl )
ELSE
iray = nrays
DO WHILE ( iray > 0 )
IF ( zdirs(iray) > full_horizon ) EXIT
itarget(iray) = HUGE( 1_iwp )
iray = iray - 1
ENDDO
itarget(1:iray) = -1
ENDIF ! rad_angular_discretization
IF ( plant_canopy ) THEN
!
!-- Skip the PCB around origin if requested (for MRT, the PCB might not be there)
IF ( skip_1st_pcb .AND. NINT( origin(1) ) <= plantt_max ) THEN
rt2_track_lad( NINT( origin(1), iwp ), 1 ) = 0._wp
ENDIF
!
!-- Assert that we have space allocated for CSFs
maxboxes = ( ntrack + MAX( CEILING( origin(1) - .5_wp ) - nz_urban_b, nz_urban_t - &
CEILING( origin(1) - .5_wp ) ) ) * nrays
IF ( calc_svf ) maxboxes = maxboxes * 2 ! Two passes for each ray
IF ( ncsfl + maxboxes > ncsfla ) THEN
!
!-- Use this code for growing by fixed exponential increments (equivalent to case where ncsfl
!-- always increases by 1)
!-- k = CEILING(grow_factor ** real(CEILING(log(real(ncsfl + maxboxes, kind=wp)) &
!-- / log(grow_factor)), kind=wp))
!-- Or use this code to simply always keep some extra space after growing
k = CEILING( REAL( ncsfl + maxboxes, KIND = wp ) * grow_factor )
CALL merge_and_grow_csf(k)
ENDIF
!
!-- Calculate transparencies and store new CSFs
zbottom = REAL( nz_urban_b, wp ) - .5_wp
ztop = REAL( plantt_max, wp ) + .5_wp
!
!-- Reverse direction of radiation (face->sky), only when calc_svf
IF ( calc_svf ) THEN
DO i = 1, ntrack ! For each column
dxxyy = ( ( dy * yxdir(1) )**2 + ( dx * yxdir(2) )**2 ) * &
( rt2_track_dist(i) - rt2_track_dist(i-1) )**2
CALL radiation_calc_global_offset( rt2_track(2,i), rt2_track(1,i), 0, 1, iproc = ip )
DO k = 1, nrays ! For each ray
!
!-- NOTE 6778:
!-- With traditional svf discretization, CSFs under the horizon (i.e. for surface to
!-- surface radiation) are created in raytrace(). With rad_angular_discretization, we
!-- must create CSFs under horizon only for one direction, otherwise we would have
!-- duplicate amount of energy. Although we could choose either of the two directions
!-- (they differ only by discretization error with no bias), we choose the backward
!-- direction, because it tends to cumulate high canopy sink factors closer to raytrace
!-- origin, i.e. it should potentially cause less moiree.
IF ( .NOT. rad_angular_discretization ) THEN
!
!-- TODO: remove tradiational discretization (incompatible with full 3D)
IF ( zdirs(k) <= full_horizon ) CYCLE
ENDIF
zorig = origin(1) + zdirs(k) * rt2_track_dist(i-1)
IF ( zorig <= zbottom .OR. zorig >= ztop ) CYCLE
zsgn = INT( SIGN( 1._wp, zdirs(k) ), iwp )
rt2_dist(1) = 0._wp
IF ( zdirs(k) == 0._wp ) THEN ! Ray is exactly horizontal
nz = 2
rt2_dist(nz) = SQRT( dxxyy )
kz = CEILING( - .5_wp + zorig, iwp )
ELSE
zexit = MIN( MAX( origin(1) + zdirs(k) * rt2_track_dist(i), zbottom ), ztop )
zb0 = FLOOR( zorig * zsgn - .5_wp ) + 1 ! Because it must be greater than orig
zb1 = CEILING( zexit * zsgn - .5_wp ) - 1 ! Because it must be smaller than exit
nz = MAX( zb1 - zb0 + 3, 2 )
rt2_dist(nz) = SQRT( ( (zexit - zorig ) * dz(1) )**2 + dxxyy )
qdist = rt2_dist(nz) / ( zexit - zorig )
rt2_dist(2:nz-1) = (/ ( ( ( REAL( l, wp ) + .5_wp ) * zsgn - zorig ) * qdist, &
l = zb0, zb1 ) /)
kz = zb0 * zsgn
ENDIF
DO l = 2, nz
IF ( rt2_track_lad(kz, i) > 0._wp ) THEN
curtrans = EXP( - ext_coef * rt2_track_lad(kz, i) * ( rt2_dist(l) - &
rt2_dist(l-1) ) )
IF ( create_csf ) THEN
ncsfl = ncsfl + 1
acsf(ncsfl)%ip = ip
acsf(ncsfl)%itx = rt2_track(2,i)
acsf(ncsfl)%ity = rt2_track(1,i)
acsf(ncsfl)%itz = kz
acsf(ncsfl)%isurfs = iorig
acsf(ncsfl)%rcvf = ( 1._wp - curtrans ) * transparency(k) * vffrac(k)
ENDIF
transparency(k) = transparency(k) * curtrans
ENDIF
kz = kz + zsgn
ENDDO ! l = 1, nz - 1
ENDDO ! k = 1, nrays
ENDDO ! i = 1, ntrack
!
!-- Reset rays above horizon to transparent (see NOTE 6778)
WHERE( itarget < 0 ) transparency = 1.0_wp
ENDIF
!
!-- Forward direction of radiation (sky->face), always
DO i = ntrack, 1, -1 ! For each column backwards
dxxyy = ( ( dy * yxdir(1) )**2 + ( dx * yxdir(2) )**2 ) * &
( rt2_track_dist(i) - rt2_track_dist(i-1) )**2
CALL radiation_calc_global_offset( rt2_track(2,i), rt2_track(1,i), 0, 1, iproc = ip )
DO k = 1, nrays ! For each ray
!
!-- See NOTE 6778 above
IF ( itarget(k) >= 0 ) CYCLE
zexit = origin(1) + zdirs(k) * rt2_track_dist(i-1)
IF ( zexit <= zbottom .OR. zexit >= ztop ) CYCLE
zsgn = - INT( SIGN( 1._wp, zdirs(k) ), iwp )
rt2_dist(1) = 0._wp
IF ( zdirs(k) == 0._wp ) THEN ! Ray is exactly horizontal
nz = 2
rt2_dist(nz) = SQRT( dxxyy )
kz = NINT( zexit, iwp )
ELSE
zorig = MIN( MAX( origin(1) + zdirs(k) * rt2_track_dist(i), zbottom ), ztop )
zb0 = FLOOR( zorig * zsgn - .5_wp ) + 1 ! Because it must be greater than orig
zb1 = CEILING( zexit * zsgn - .5_wp ) - 1 ! Because it must be smaller than exit
nz = MAX( zb1 - zb0 + 3, 2 )
rt2_dist(nz) = SQRT( ( ( zexit - zorig ) * dz(1) )**2 + dxxyy )
qdist = rt2_dist(nz) / ( zexit - zorig )
rt2_dist(2:nz-1) = (/ ( ( ( REAL( l, wp ) + .5_wp ) * zsgn - zorig ) * qdist, &
l = zb0, zb1 ) /)
kz = zb0 * zsgn
ENDIF
DO l = 2, nz
IF ( rt2_track_lad(kz, i) > 0._wp ) THEN
curtrans = EXP( - ext_coef * rt2_track_lad(kz, i) * &
( rt2_dist(l) - rt2_dist(l-1) ) )
IF ( create_csf ) THEN
ncsfl = ncsfl + 1
acsf(ncsfl)%ip = ip
acsf(ncsfl)%itx = rt2_track(2,i)
acsf(ncsfl)%ity = rt2_track(1,i)
acsf(ncsfl)%itz = kz
acsf(ncsfl)%isurfs = -1
acsf(ncsfl)%rcvf = ( 1._wp - curtrans ) * transparency(k) * aorig * vffrac(k)
ENDIF ! create_csf
transparency(k) = transparency(k) * curtrans
ENDIF
kz = kz + zsgn
ENDDO ! l = 1, nz - 1
ENDDO ! k = 1, nrays
ENDDO ! i = 1, ntrack
ENDIF ! plant_canopy
CONTAINS
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> @Todo: Missing subroutine description!
!--------------------------------------------------------------------------------------------------!
SUBROUTINE request_itarget( d, z, y, x, isurfl )
INTEGER(iwp), INTENT(IN) :: d, z, y, x !<
INTEGER(iwp), TARGET, INTENT(OUT) :: isurfl !<
#if defined( __parallel )
INTEGER(iwp) :: iproc !<
INTEGER(KIND=MPI_ADDRESS_KIND) :: target_displ !< index of the grid in the local gridsurf array
!
!-- Calculate target processor and index in the remote local target gridsurf array
CALL radiation_calc_global_offset( x, y, ( z - nz_urban_b ) * nsurf_type_u + d, &
nz_urban * nsurf_type_u, iproc = iproc, &
offs_proc = target_displ )
!
!-- Send MPI_Get request to obtain index target_surfl(i)
CALL MPI_GET( isurfl, 1, MPI_INTEGER, iproc, target_displ, 1, MPI_INTEGER, win_gridsurf, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error MPI_GET3:', ierr, isurfl, iproc, target_displ, win_gridsurf
FLUSH( 9 )
ENDIF
#else
!
!-- Set index target_surfl(i)
isurfl = gridsurf(d,z,y,x)
#endif
END SUBROUTINE request_itarget
END SUBROUTINE raytrace_2d
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Calculates apparent solar positions for all timesteps and stores discretized positions for RTM.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_presimulate_solar_pos
USE control_parameters, &
ONLY: rotation_angle
IMPLICIT NONE
INTEGER(iwp) :: it, i, j !< loop indices
REAL(wp), DIMENSION(:,:), ALLOCATABLE :: dsidir_tmp !< dsidir_tmp[:,i] = unit vector of i-th
!< appreant solar direction
ALLOCATE( dsidir_rev(0:raytrace_discrete_elevs/2-1,0:raytrace_discrete_azims-1) )
dsidir_rev(:,:) = -1
ALLOCATE( dsidir_tmp(3, raytrace_discrete_elevs/2*raytrace_discrete_azims) )
ndsidir = 0
sun_direction = .TRUE.
!
!-- Process spinup time if configured
IF ( spinup_time > 0._wp ) THEN
DO it = 0, CEILING( spinup_time / dt_spinup )
CALL simulate_pos( it * dt_spinup - spinup_time )
ENDDO
ENDIF
!
!-- Process simulation time
DO it = 0, CEILING( ( end_time - spinup_time ) / dt_radiation )
CALL simulate_pos( it * dt_radiation )
ENDDO
!
!-- Allocate global vars which depend on ndsidir
ALLOCATE( dsidir ( 3, ndsidir ) )
dsidir(:,:) = dsidir_tmp(:, 1:ndsidir)
DEALLOCATE( dsidir_tmp )
ALLOCATE( dsitrans(nsurfl, ndsidir) )
ALLOCATE( dsitransc(npcbl, ndsidir) )
IF ( nmrtbl > 0 ) ALLOCATE( mrtdsit(nmrtbl, ndsidir) )
WRITE( message_string, * ) 'Precalculated', ndsidir, ' solar positions from ', it, ' timesteps.'
CALL message( 'radiation_presimulate_solar_pos', 'UI0013', 0, 0, 0, 6, 0 )
CONTAINS
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Simuates a single position
!--------------------------------------------------------------------------------------------------!
SUBROUTINE simulate_pos( time_since_reference_local )
REAL(wp) :: solar_azim !< solar azimuth in rotated model coordinates
REAL(wp), INTENT(IN) :: time_since_reference_local !< local time since reference
!
!-- Update apparent solar position based on modified t_s_r_p
CALL get_date_time( time_since_reference_local, day_of_year = day_of_year, &
second_of_day = second_of_day )
CALL calc_zenith( day_of_year, second_of_day )
IF ( cos_zenith > 0 ) THEN
!
!-- Identify solar direction vector (discretized number) 1)
solar_azim = ATAN2( sun_dir_lon, sun_dir_lat ) * ( 180.0_wp / pi ) - rotation_angle
i = MODULO( NINT( solar_azim / 360.0_wp * REAL( raytrace_discrete_azims, KIND = wp ) &
- 0.5_wp, iwp ), raytrace_discrete_azims )
j = FLOOR( ACOS( cos_zenith ) / pi * REAL( raytrace_discrete_elevs, KIND = wp ) )
IF ( dsidir_rev(j, i) == -1 ) THEN
ndsidir = ndsidir + 1
dsidir_tmp(:, ndsidir) = &
(/ COS( (REAL( j, wp ) + .5_wp ) * pi / REAL( raytrace_discrete_elevs, wp ) ), &
SIN( (REAL( j, wp ) + .5_wp ) * pi / REAL( raytrace_discrete_elevs, wp ) ) &
* COS( (REAL( i, wp ) + .5_wp ) * 2_wp*pi / REAL( raytrace_discrete_azims, wp ) ), &
SIN( (REAL( j, wp ) + .5_wp ) * pi / REAL( raytrace_discrete_elevs, wp ) ) &
* SIN( (REAL( i, wp ) + .5_wp ) * 2_wp*pi / REAL( raytrace_discrete_azims, wp ) ) /)
dsidir_rev(j, i) = ndsidir
ENDIF
ENDIF
END SUBROUTINE simulate_pos
END SUBROUTINE radiation_presimulate_solar_pos
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Determines whether two faces are oriented towards each other in RTM. Since the surfaces follow
!> the gird box surfaces, it checks first whether the two surfaces are directed in the same
!> direction, then it checks if the two surfaces are located in confronted direction but facing away
!> from each other, e.g. <--| |-->
!--------------------------------------------------------------------------------------------------!
PURE LOGICAL FUNCTION surface_facing( x, y, z, d, x2, y2, z2, d2 )
IMPLICIT NONE
INTEGER(iwp),INTENT(IN) :: x, y, z, d, x2, y2, z2, d2 !<
surface_facing = .FALSE.
!
!-- First check: are the two surfaces directed in the same direction
IF ( d == iup .AND. d2 == iup ) RETURN
IF ( d == isouth .AND. d2 == isouth ) RETURN
IF ( d == inorth .AND. d2 == inorth ) RETURN
IF ( d == iwest .AND. d2 == iwest ) RETURN
IF ( d == ieast .AND. d2 == ieast ) RETURN
!
!-- Second check: are surfaces facing away from each other
SELECT CASE (d)
CASE (iup) !< Upward facing surfaces
IF ( z2 < z ) RETURN
CASE (isouth) !< Southward facing surfaces
IF ( y2 > y ) RETURN
CASE (inorth) !< Northward facing surfaces
IF ( y2 < y ) RETURN
CASE (iwest) !< Westward facing surfaces
IF ( x2 > x ) RETURN
CASE (ieast) !< Eastward facing surfaces
IF ( x2 < x ) RETURN
END SELECT
SELECT CASE (d2)
CASE (iup) !< Ground, roof
IF ( z < z2 ) RETURN
CASE (isouth) !< South facing
IF ( y > y2 ) RETURN
CASE (inorth) !< North facing
IF ( y < y2 ) RETURN
CASE (iwest) !< West facing
IF ( x > x2 ) RETURN
CASE (ieast) !< East facing
IF ( x < x2 ) RETURN
CASE (-1)
CONTINUE
END SELECT
surface_facing = .TRUE.
END FUNCTION surface_facing
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Reads svf, svfsurf, csf, csfsurf and mrt factors data from saved file. This allows to skip their
!> calculation during of RTM init phase. SVF means sky view factors and CSF means canopy sink
!> factors.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_read_svf
IMPLICIT NONE
CHARACTER(rad_version_len) :: rad_version_field !<
CHARACTER(LEN=64) :: rad_version_in !< rad version on file
INTEGER(iwp) :: i !<
INTEGER(iwp) :: ndsidir_bin_file = 0 !<
INTEGER(iwp) :: nmrtbl_bin_file = 0 !<
INTEGER(iwp) :: npcbl_bin_file = 0 !<
INTEGER(iwp) :: nsurfl_bin_file = 0 !<
INTEGER(idp) :: ncsfl_tot !<
INTEGER(idp) :: ndsidir_from_file = 0 !<
INTEGER(idp) :: ndsidir_tot !<
INTEGER(idp) :: nmrtbl_from_file = 0 !<
INTEGER(idp) :: nmrtbl_tot !<
INTEGER(idp) :: nmrtf_tot !<
INTEGER(idp) :: npcbl_from_file = 0 !<
INTEGER(idp) :: npcbl_tot !<
INTEGER(idp) :: nsurfl_from_file = 0 !<
INTEGER(idp) :: nsurfl_tot !<
INTEGER(idp) :: nsvfl_tot !< total (sum across all PEs) counter for the different IO variables
INTEGER(idp), DIMENSION(4) :: global_sum !<
INTEGER(idp), DIMENSION(4) :: local_sum !< variables to compute total counter
INTEGER(idp), DIMENSION(nys:nyn,nxl:nxr) :: global_end !< global end index (I8)
INTEGER(idp), DIMENSION(nys:nyn,nxl:nxr) :: global_start !< global start index (I8)
INTEGER(iwp), DIMENSION(nys:nyn,nxl:nxr) :: end_index !< local end index
INTEGER(iwp), DIMENSION(nys:nyn,nxl:nxr) :: start_index !< local start index
LOGICAL :: data_to_read !< flag indicating if data is available for current variable
LOGICAL :: save_include_total_domain_boundaries !< save value of include_total_domain_boundaries
REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: tmp !<
IF ( TRIM( restart_data_format_input ) == 'fortran_binary' ) THEN
CALL location_message( 'reading sky view factors in ' // &
'Fortran binary format', 'start' )
DO i = 0, io_blocks-1
IF ( i == io_group ) THEN
!
!-- numprocs_previous_run is only known in case of reading restart data. If a new initial
!-- run which reads svf data is started the following query will be skipped.
IF ( initializing_actions == 'read_restart_data' ) THEN
IF ( numprocs_previous_run /= numprocs ) THEN
WRITE( message_string, * ) 'A different number of processors between the run ', &
'that has written the svf data and the one that ', &
'will read it is not allowed'
CALL message( 'check_open', 'PA0491', 1, 2, 0, 6, 0 )
ENDIF
ENDIF
!
!-- Open binary file
CALL check_open( 88 )
!
!-- Read and check version
READ ( 88 ) rad_version_field
IF ( TRIM( rad_version_field ) /= TRIM( rad_version ) ) THEN
WRITE( message_string, * ) 'Version of binary SVF file "', &
TRIM( rad_version_field ), '" does not match ', &
'the version of model "', TRIM( rad_version ), '"'
CALL message( 'radiation_read_svf', 'PA0482', 1, 2, 0, 6, 0 )
ENDIF
!
!-- Read nsvfl, ncsfl, nsurfl, nmrtf
READ ( 88 ) nsvfl, ncsfl, nsurfl_bin_file, npcbl_bin_file, ndsidir_bin_file, &
nmrtbl_bin_file, nmrtf
IF ( nsvfl < 0 .OR. ncsfl < 0 ) THEN
WRITE( message_string, * ) 'Wrong number of SVF or CSF'
CALL message( 'radiation_read_svf', 'PA0483', 1, 2, 0, 6, 0 )
ELSE
WRITE(debug_string,*) 'Number of SVF, CSF, and nsurfl to read', nsvfl, ncsfl, &
nsurfl_bin_file
IF ( debug_output ) CALL debug_message( debug_string, 'info' )
ENDIF
IF ( nsurfl_bin_file /= nsurfl ) THEN
WRITE( message_string, * ) 'nsurfl from SVF file does not match calculated ', &
'nsurfl from radiation_interaction_init'
CALL message( 'radiation_read_svf', 'PA0490', 1, 2, 0, 6, 0 )
ENDIF
IF ( npcbl_bin_file /= npcbl ) THEN
WRITE( message_string, * ) 'npcbl from SVF file does not match calculated npcbl', &
' from radiation_interaction_init'
CALL message( 'radiation_read_svf', 'PA0493', 1, 2, 0, 6, 0 )
ENDIF
IF ( ndsidir_bin_file /= ndsidir ) THEN
WRITE( message_string, * ) 'ndsidir from SVF file does not match calculated ', &
'ndsidir from radiation_presimulate_solar_pos'
CALL message( 'radiation_read_svf', 'PA0494', 1, 2, 0, 6, 0 )
ENDIF
IF ( nmrtbl_bin_file /= nmrtbl ) THEN
WRITE( message_string, * ) 'nmrtbl from SVF file does not match calculated ', &
'nmrtbl from radiation_interaction_init'
CALL message( 'radiation_read_svf', 'PA0494', 1, 2, 0, 6, 0 )
ELSE
WRITE( debug_string, * ) 'Number of nmrtf to read ', nmrtf
IF ( debug_output ) CALL debug_message( debug_string, 'info' )
ENDIF
!
!-- Arrays skyvf, skyvft, dsitrans and dsitransc are allready allocated in
!-- radiation_interaction_init and radiation_presimulate_solar_pos
IF ( nsurfl > 0 ) THEN
READ( 88 ) skyvf
READ( 88 ) skyvft
READ( 88 ) dsitrans
ENDIF
IF ( plant_canopy .AND. npcbl > 0 ) THEN
READ( 88 ) dsitransc
ENDIF
!
!-- The allocation of svf, svfsurf, csf, csfsurf, mrtf, mrtft, and mrtfsurf happens in
!-- routine radiation_calc_svf which is not called if the program enters
!-- radiation_read_svf. Therefore these arrays have to be allocated in the following.
IF ( nsvfl > 0 ) THEN
ALLOCATE( svf(ndsvf,nsvfl) )
ALLOCATE( svfsurf(idsvf,nsvfl) )
READ( 88 ) svf
READ( 88 ) svfsurf
ENDIF
IF ( plant_canopy .AND. ncsfl > 0 ) THEN
ALLOCATE( csf(ndcsf,ncsfl) )
ALLOCATE( csfsurf(idcsf,ncsfl) )
READ( 88 ) csf
READ( 88 ) csfsurf
ENDIF
IF ( nmrtbl > 0 ) THEN
READ( 88 ) mrtsky
READ( 88 ) mrtskyt
READ( 88 ) mrtdsit
ENDIF
IF ( nmrtf > 0 ) THEN
ALLOCATE( mrtf(nmrtf) )
ALLOCATE( mrtft(nmrtf) )
ALLOCATE( mrtfsurf(2,nmrtf) )
READ( 88 ) mrtf
READ( 88 ) mrtft
READ( 88 ) mrtfsurf
ENDIF
!
!-- Close binary file
CALL close_file( 88 )
ENDIF
#if defined( __parallel )
CALL MPI_BARRIER( comm2d, ierr )
#endif
ENDDO
CALL location_message( 'reading sky view factors in Fortran binary format', 'finished' )
ELSEIF ( restart_data_format_input(1:3) == 'mpi' ) THEN
!
!-- In case of MPI-IO data is treated like surface data and the respective routines from
!-- restart_data_mpi_io_mod are used for reading. Contrary to restart data, the virtual processor
!-- grid can not be changed between writing and reading svf data.
CALL location_message( 'reading sky view factors in ' // &
'MPI-IO format', 'start' )
!
!-- SVF files must not contain outer boundaries
save_include_total_domain_boundaries = include_total_domain_boundaries
include_total_domain_boundaries = .FALSE.
!
!-- Open MPI-IO svf file for reading the global data.
CALL rd_mpi_io_open( 'READ', 'SVFIN' // TRIM( coupling_char ), &
open_for_global_io_only = .TRUE. )
!
!-- Check general header.
IF ( tgh%pes_along_x /= npex .OR. tgh%pes_along_y /= npey ) THEN
!
!-- Force re-calculation of svfs.
read_svf = .FALSE.
WRITE( message_string, '(A,I7,A,I7,A,I7,A,I7,A)' ) &
'virtual PE grid has changed between previous and current run &npex_prev = ', &
tgh%pes_along_x, ' npey_prev = ', tgh%pes_along_y, ' npex_new = ', npex, &
' npey_new = ', npey, '&svf wil be re-calculated'
CALL message( 'radiation_read_svf', 'PA0517', 0, 0, 0, 6, 0 )
RETURN
ENDIF
!
!-- Read global variables
CALL rrd_mpi_io( 'rad_version', rad_version_in )
CALL rrd_mpi_io( 'nsvfl', nsvfl_tot )
CALL rrd_mpi_io( 'ncsfl', ncsfl_tot )
CALL rrd_mpi_io( 'nsurfl', nsurfl_from_file )
CALL rrd_mpi_io( 'npcbl', npcbl_from_file )
CALL rrd_mpi_io( 'ndsidir', ndsidir_from_file )
CALL rrd_mpi_io( 'nmrtbl', nmrtbl_from_file )
CALL rrd_mpi_io( 'nmrtf', nmrtf_tot )
CALL rd_mpi_io_close
!
!-- Compute global values of local counters.
local_sum(1) = nsurfl
local_sum(2) = npcbl
local_sum(3) = ndsidir
local_sum(4) = nmrtbl
#if defined( __parallel )
CALL MPI_ALLREDUCE( local_sum, global_sum, SIZE(local_sum), MPI_INTEGER8, MPI_SUM, comm2d, &
ierr)
#else
global_sum = local_sum
#endif
nsurfl_tot = global_sum(1)
npcbl_tot = global_sum(2)
ndsidir_tot = global_sum(3)
nmrtbl_tot = global_sum(4)
!
!-- Check for errors.
nx_on_file = tgh%total_nx-1
ny_on_file = tgh%total_ny-1
IF ( nx_on_file /= nx .OR. ny_on_file /= ny ) THEN
WRITE( message_string, '(A,4(A,I7))' ) &
'total number of grid points along x and y in file SVFIN do not match current run', &
'&nx_on_file = ', nx_on_file, ' ny_on_file = ', ny_on_file, ' nx = ', nx, ' ny = ', &
ny
CALL message( 'radiation_read_svf', 'PA0518', 1, 2, 0, 6, 0 )
ENDIF
IF ( TRIM( rad_version_in ) /= TRIM( rad_version ) ) THEN
WRITE( message_string, * ) 'Version of binary SVF file "', TRIM( rad_version_field ), &
'" does not match the version of model "', &
TRIM( rad_version ), '"'
CALL message( 'radiation_read_svf', 'PA0482', 1, 2, 0, 6, 0 )
ENDIF
IF ( nsvfl_tot < 0 .OR. ncsfl_tot < 0 ) THEN
WRITE( message_string, * ) 'Wrong number of SVF or CSF'
CALL message( 'radiation_read_svf', 'PA0483', 1, 2, 0, 6, 0 )
ELSE
WRITE(debug_string,*) 'Number of SVF, CSF, and nsurfl to read', nsvfl_tot, ncsfl_tot, &
nsurfl_tot
IF ( debug_output ) CALL debug_message( debug_string, 'info' )
ENDIF
IF ( nsurfl_from_file /= nsurfl_tot ) THEN
WRITE( message_string, * ) 'nsurfl from SVF file does not match calculated ', &
'nsurfl from radiation_interaction_init'
CALL message( 'radiation_read_svf', 'PA0490', 1, 2, 0, 6, 0 )
ENDIF
IF ( npcbl_from_file /= npcbl_tot ) THEN
WRITE( message_string, * ) 'npcbl from SVF file does not match calculated npcbl ', &
'from radiation_interaction_init'
CALL message( 'radiation_read_svf', 'PA0493', 1, 2, 0, 6, 0 )
ENDIF
IF ( ndsidir_from_file /= ndsidir_tot ) THEN
WRITE( message_string, * ) 'ndsidir from SVF file does not match calculated ', &
'ndsidir from radiation_presimulate_solar_pos'
CALL message( 'radiation_read_svf', 'PA0494', 1, 2, 0, 6, 0 )
ENDIF
IF ( nmrtbl_from_file /= nmrtbl_tot ) THEN
WRITE( message_string, * ) 'nmrtbl from SVF file does not match calculated nmrtbl ', &
'from radiation_interaction_init'
CALL message( 'radiation_read_svf', 'PA0494', 1, 2, 0, 6, 0 )
ELSE
WRITE( debug_string, * ) 'Number of nmrtf to read ', nmrtf_tot
IF ( debug_output ) CALL debug_message( debug_string, 'info' )
ENDIF
!
!-- Open MPI-IO SVF file for read local data.
CALL rd_mpi_io_open( 'READ', 'SVFIN' // TRIM( coupling_char ) )
IF ( nsurfl_tot > 0 ) THEN
!
!-- Read global indices.
CALL rrd_mpi_io( 'nsurfl_global_start', global_start )
CALL rrd_mpi_io( 'nsurfl_global_end', global_end )
!
!-- Set file types of variables and compute local indices.
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_read, global_start, &
global_end )
nsurfl = end_index(nyn,nxr)
IF ( data_to_read ) THEN
CALL rrd_mpi_io_surface( 'skyvf', skyvf )
CALL rrd_mpi_io_surface( 'skyvft', skyvft )
!
!-- To avoid another overlay of rrd_mpi_io_surface, dsitrans is read as REAL tmp array.
!-- The order of dimensions of dsitrans is different to the order expected by
!-- rrd_mpi_io_surface. Therefor a tranpose of tmp is required.
ALLOCATE( tmp(SIZE(dsitrans,2),SIZE(dsitrans,1)) )
CALL rrd_mpi_io_surface( 'dsitrans', tmp )
dsitrans = TRANSPOSE( tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( npcbl_tot > 0 ) THEN
CALL rrd_mpi_io( 'npcbl_global_start', global_start )
CALL rrd_mpi_io( 'npcbl_global_end', global_end )
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_read, global_start, &
global_end )
npcbl = end_index(nyn,nxr)
IF ( data_to_read ) THEN
ALLOCATE( tmp(SIZE(dsitransc,2),SIZE(dsitransc,1)) )
CALL rrd_mpi_io_surface( 'dsitransc', tmp )
dsitransc = TRANSPOSE( tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( nsvfl_tot > 0 ) THEN
CALL rrd_mpi_io( 'nsvfl_global_start', global_start )
CALL rrd_mpi_io( 'nsvfl_global_end', global_end )
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_read, global_start, &
global_end )
nsvfl = end_index(nyn,nxr)
IF ( .NOT. ALLOCATED( svf ) ) ALLOCATE( svf(ndsvf,nsvfl) )
IF ( .NOT. ALLOCATED( svfsurf ) ) ALLOCATE( svfsurf(idsvf,nsvfl) )
IF ( data_to_read ) THEN
CALL rrd_mpi_io_surface( 'svf', svf )
ALLOCATE( tmp(SIZE(svfsurf,1),SIZE(svfsurf,2)) )
CALL rrd_mpi_io_surface( 'svfsurf', tmp )
svfsurf = tmp
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( plant_canopy ) THEN
IF ( ncsfl_tot > 0 ) THEN
CALL rrd_mpi_io( 'ncsfl_global_start', global_start )
CALL rrd_mpi_io( 'ncsfl_global_end', global_end )
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_read, global_start, &
global_end )
ncsfl = end_index(nyn,nxr)
IF ( .NOT. ALLOCATED( csf ) ) ALLOCATE( csf(ndcsf,ncsfl) )
IF ( .NOT. ALLOCATED( csfsurf ) ) ALLOCATE( csfsurf(idcsf,ncsfl) )
IF ( data_to_read ) THEN
CALL rrd_mpi_io_surface( 'csf', csf )
ALLOCATE( tmp(SIZE(csfsurf,1),SIZE(csfsurf,2)) )
CALL rrd_mpi_io_surface( 'csfsurf', tmp )
csfsurf = tmp
DEALLOCATE( tmp )
ENDIF
ENDIF
ENDIF
IF ( nmrtbl_tot > 0 ) THEN
CALL rrd_mpi_io( 'nmrtbl_global_start', global_start )
CALL rrd_mpi_io( 'nmrtbl_global_end', global_end )
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_read, global_start, &
global_end )
nmrtbl = end_index(nyn,nxr)
IF ( data_to_read ) THEN
CALL rrd_mpi_io_surface( 'mrtsky', mrtsky )
CALL rrd_mpi_io_surface( 'mrtskyt', mrtskyt )
ALLOCATE( tmp(SIZE(mrtdsit,2),SIZE(mrtdsit,1)) )
CALL rrd_mpi_io_surface( 'mrtdsit', tmp )
mrtdsit = TRANSPOSE( tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( nmrtf_tot > 0 ) THEN
CALL rrd_mpi_io( 'nmrtf_global_start', global_start )
CALL rrd_mpi_io( 'nmrtf_global_end', global_end )
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_read, global_start, &
global_end )
nmrtf = end_index(nyn,nxr)
IF ( .NOT. ALLOCATED( mrtf ) ) ALLOCATE( mrtf(nmrtf) )
IF ( .NOT. ALLOCATED( mrtft ) ) ALLOCATE( mrtft(nmrtf) )
IF ( .NOT. ALLOCATED( mrtfsurf ) ) ALLOCATE( mrtfsurf(2,nmrtf) )
IF ( data_to_read ) THEN
CALL rrd_mpi_io_surface( 'mrtf', mrtf )
CALL rrd_mpi_io_surface( 'mrtft', mrtft )
ALLOCATE( tmp(SIZE(mrtfsurf,1),SIZE(mrtfsurf,2)) )
CALL rrd_mpi_io_surface( 'mrtfsurf', tmp )
mrtfsurf = tmp
DEALLOCATE( tmp )
ENDIF
ENDIF
CALL rd_mpi_io_close
!
!-- Reset switch to its original value to be used for other than SVF I/O.
include_total_domain_boundaries = save_include_total_domain_boundaries
CALL location_message( 'reading sky view factors in MPI-IO format', 'finished' )
ENDIF
END SUBROUTINE radiation_read_svf
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Subroutine stores svf, svfsurf, csf, csfsurf and mrt data to a file. The stored factors can be
!> reused in future simulation with the same geometry structure of the surfaces and resolved plant
!> canopy.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_write_svf
IMPLICIT NONE
CHARACTER(LEN=16), DIMENSION(7) :: counter_name !< names of sky view factor counter
INTEGER(iwp), PARAMETER :: max_i4_value = 2147483647 !< maximum positive INTEGER(4) value, 2**31 - 1
INTEGER(iwp) :: i !<
INTEGER(iwp) :: ic !<
#if defined( __parallel )
INTEGER(iwp) :: ierr !<
#endif
INTEGER(iwp) :: ind !<
INTEGER(iwp) :: ipcgb !<
INTEGER(iwp) :: isurf !<
INTEGER(iwp) :: j !<
INTEGER(iwp) :: jc !<
INTEGER(idp) :: ncsfl_tot !<
INTEGER(idp) :: ndsidir_tot !<
INTEGER(idp) :: nmrtbl_tot !<
INTEGER(idp) :: nmrtf_tot !<
INTEGER(idp) :: npcbl_tot !<
INTEGER(idp) :: nsurfl_tot !<
INTEGER(idp) :: nsvfl_tot !< total (sum over all PEs) counter for the different IO variables
INTEGER(idp), DIMENSION(7) :: global_sum !< idp to allow check, if total number of values > 2G
INTEGER(idp), DIMENSION(7) :: local_sum !< variables to compute total counter
INTEGER(iwp), DIMENSION(nys:nyn,nxl:nxr) :: end_index !< local end index
INTEGER(idp), DIMENSION(nys:nyn,nxl:nxr) :: global_end !< global end index
INTEGER(idp), DIMENSION(nys:nyn,nxl:nxr) :: global_start !< global start index
INTEGER(iwp), DIMENSION(nys:nyn,nxl:nxr) :: lo_no !< local number of values
INTEGER(iwp), DIMENSION(nys:nyn,nxl:nxr) :: start_index !< local start index
LOGICAL :: data_to_write !< flag indicating if data is available for writing
LOGICAL :: save_include_total_domain_boundaries !< save value of include_total_domain_boundaries
REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: tmp !<
IF ( TRIM( restart_data_format_output ) == 'fortran_binary' ) THEN
CALL location_message( 'writing sky view factors in Fortran binary format', 'start' )
DO i = 0, io_blocks-1
IF ( i == io_group ) THEN
!
!-- Open binary file
CALL check_open( 89 )
WRITE( 89 ) rad_version
WRITE( 89 ) nsvfl, ncsfl, nsurfl, npcbl, ndsidir, nmrtbl, nmrtf
IF ( nsurfl > 0 ) THEN
WRITE( 89 ) skyvf
WRITE( 89 ) skyvft
WRITE( 89 ) dsitrans
ENDIF
IF ( npcbl > 0 ) THEN
WRITE( 89 ) dsitransc
ENDIF
IF ( nsvfl > 0 ) THEN
WRITE( 89 ) svf
WRITE( 89 ) svfsurf
ENDIF
IF ( plant_canopy .AND. ncsfl > 0 ) THEN
WRITE( 89 ) csf
WRITE( 89 ) csfsurf
ENDIF
IF ( nmrtbl > 0 ) THEN
WRITE( 89 ) mrtsky
WRITE( 89 ) mrtskyt
WRITE( 89 ) mrtdsit
ENDIF
IF ( nmrtf > 0 ) THEN
WRITE( 89 ) mrtf
WRITE( 89 ) mrtft
WRITE( 89 ) mrtfsurf
ENDIF
!
!-- Close binary file
CALL close_file( 89 )
ENDIF
#if defined( __parallel )
CALL MPI_BARRIER( comm2d, ierr )
#endif
ENDDO
CALL location_message( 'writing sky view factors in Fortran binary format', 'finished' )
ELSEIF ( restart_data_format_output(1:3) == 'mpi' ) THEN
!
!-- Sky view factor data is treated like surface data and the respective routines from
!-- restart_data_mpi_io_mod are used for writing. In contrary to restart data, the virtual
!-- processor grid can not be changed between writing and reading svf data.
CALL location_message( 'writing sky view factors in MPI-IO format', 'start' )
!
!-- SVF files must not contain outer boundaries
save_include_total_domain_boundaries = include_total_domain_boundaries
include_total_domain_boundaries = .FALSE.
!
!-- Open MPI-IO svf file
CALL rd_mpi_io_open( 'write', 'SVFOUT' // TRIM( coupling_char ) )
!
!-- Write global variables.
CALL wrd_mpi_io( 'rad_version', rad_version )
!
!-- Set names of sky view counters
counter_name(1) = 'nsvfl '
counter_name(2) = 'ncsfl '
counter_name(3) = 'nsurfl '
counter_name(4) = 'npcbl '
counter_name(5) = 'ndsidir '
counter_name(6) = 'nmrtbl '
counter_name(7) = 'nmrtf '
!
!-- Sum local number of skyview factor values on all PEs.
local_sum(1) = nsvfl
local_sum(2) = ncsfl
local_sum(3) = nsurfl
local_sum(4) = npcbl
local_sum(5) = ndsidir
local_sum(6) = nmrtbl
local_sum(7) = nmrtf
#if defined( __parallel )
CALL MPI_ALLREDUCE( local_sum, global_sum, SIZE( local_sum ), MPI_INTEGER8, MPI_SUM, &
comm2d, ierr)
#else
global_sum = local_sum
#endif
!
!-- Check, if total number of respective skyview values do not exceed 2**31-1
DO i = 1, 7
IF ( global_sum(i) > max_i4_value ) THEN
WRITE( message_string, '(A,A,I12,A)' ) 'number of sky view factor values for ', &
TRIM( counter_name(i) ) // ' = ', global_sum(i),' is > 2**31-1'
CALL message( 'radiation_write_svf', 'PA0733', 0, 0, 0, 6, 0 )
ENDIF
ENDDO
nsvfl_tot = global_sum(1)
ncsfl_tot = global_sum(2)
nsurfl_tot = global_sum(3)
npcbl_tot = global_sum(4)
ndsidir_tot = global_sum(5)
nmrtbl_tot = global_sum(6)
nmrtf_tot = global_sum(7)
!
!-- Write total counters in header section of MPI-IO file.
CALL wrd_mpi_io( 'nsvfl', nsvfl_tot )
CALL wrd_mpi_io( 'ncsfl', ncsfl_tot )
CALL wrd_mpi_io( 'nsurfl', nsurfl_tot )
CALL wrd_mpi_io( 'npcbl', npcbl_tot )
CALL wrd_mpi_io( 'ndsidir', ndsidir_tot )
CALL wrd_mpi_io( 'nmrtbl', nmrtbl_tot )
CALL wrd_mpi_io( 'nmrtf', nmrtf_tot )
!
!-- Write local data.
!-- All svf values are treated as surface values and use the respective routines from
!-- restart_data_mpi_io_mod.
IF ( nsurfl > 0 ) THEN
lo_no = 0
!
!-- Count surface values on individual grid cells
DO isurf = 1, nsurfl
jc = surfl(iy, isurf)
ic = surfl(ix, isurf)
lo_no(jc,ic) = lo_no(jc,ic) + 1
ENDDO
!
!-- Create local index array similar to surface routines.
ind = 1
DO i = nxl, nxr
DO j = nys, nyn
start_index(j,i) = ind
end_index(j,i) = start_index(j,i) + lo_no(j,i) - 1
ind = ind + lo_no(j,i)
ENDDO
ENDDO
ELSE
start_index = 1
end_index = 0
ENDIF
!
!-- Each PE has to call the next block, therefore nsurfl_tot is used.
!-- This is required to use MPI_FILE_WRITE_All for writing.
IF ( nsurfl_tot > 0 ) THEN
!
!-- Set file types of variables for this block and compute global indices.
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_write, global_start, &
global_end )
CALL wrd_mpi_io( 'nsurfl_global_start', global_start )
CALL wrd_mpi_io( 'nsurfl_global_end', global_end )
IF ( data_to_write ) THEN
CALL wrd_mpi_io_surface( 'skyvf', skyvf )
CALL wrd_mpi_io_surface( 'skyvft', skyvft )
!
!-- To avoid another overlay of rrd_mpi_io_surface, dsitrans is written as REAL tmp array.
!-- The order of dimensions of dsitrans is different to the order expected by
!-- rrd_mpi_io_surface. Therefor a tranpose of tmp is required.
ALLOCATE( tmp(SIZE(dsitrans,2),SIZE(dsitrans,1)) )
tmp = TRANSPOSE( dsitrans )
CALL wrd_mpi_io_surface( 'dsitrans', tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( npcbl > 0 ) THEN
lo_no = 0
DO isurf = 1, npcbl
jc = pcbl(iy,isurf)
ic = pcbl(ix,isurf)
lo_no(jc,ic) = lo_no(jc,ic) + 1
ENDDO
ind = 1
DO i = nxl, nxr
DO j = nys, nyn
start_index(j,i) = ind
end_index(j,i) = start_index(j,i) + lo_no(j,i) - 1
ind = ind+lo_no(j,i)
ENDDO
ENDDO
ELSE
start_index = 1
end_index = 0
ENDIF
IF ( npcbl_tot > 0 ) THEN
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_write, global_start, &
global_end )
CALL wrd_mpi_io( 'npcbl_global_start', global_start )
CALL wrd_mpi_io( 'npcbl_global_end', global_end )
IF ( data_to_write ) THEN
ALLOCATE( tmp(SIZE(dsitransc,2),SIZE(dsitransc,1)) )
tmp = TRANSPOSE( dsitransc )
CALL wrd_mpi_io_surface( 'dsitransc', tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( nsvfl > 0 ) THEN
lo_no = 0
DO j = 1, SIZE( svfsurf, 2 )
isurf = svfsurf(1,j)
jc = surfl(iy,isurf)
ic = surfl(ix,isurf)
lo_no(jc,ic) = lo_no(jc,ic) + 1
ENDDO
ind = 1
DO i = nxl, nxr
DO j = nys, nyn
start_index(j,i) = ind
end_index(j,i) = start_index(j,i) + lo_no(j,i) - 1
ind = ind+lo_no(j,i)
ENDDO
ENDDO
ELSE
start_index = 1
end_index = 0
ENDIF
IF ( nsvfl_tot > 0 ) THEN
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_write, global_start, &
global_end )
CALL wrd_mpi_io( 'nsvfl_global_start', global_start )
CALL wrd_mpi_io( 'nsvfl_global_end', global_end )
IF ( data_to_write ) THEN
CALL wrd_mpi_io_surface( 'svf', svf )
ALLOCATE( tmp(SIZE(svfsurf,1),SIZE(svfsurf,2)) )
tmp(:,:) = svfsurf(:,:)
CALL wrd_mpi_io_surface( 'svfsurf', tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( plant_canopy ) THEN
lo_no = 0
IF ( ncsfl > 0 ) THEN
DO j = 1, ncsfl
ipcgb = csfsurf(1, j)
jc = pcbl(iy,ipcgb)
ic = pcbl(ix,ipcgb)
lo_no(jc,ic) = lo_no(jc,ic) + 1
ENDDO
ind = 1
DO i = nxl, nxr
DO j = nys, nyn
start_index(j,i) = ind
end_index(j,i) = start_index(j,i) + lo_no(j,i) - 1
ind = ind+lo_no(j,i)
ENDDO
ENDDO
ELSE
start_index = 1
end_index = -1
ENDIF
IF ( ncsfl_tot > 0 ) THEN
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_write, global_start,&
global_end )
CALL wrd_mpi_io( 'ncsfl_global_start', global_start )
CALL wrd_mpi_io( 'ncsfl_global_end', global_end )
IF ( data_to_write ) THEN
IF ( ALLOCATED( csf ) ) THEN
CALL wrd_mpi_io_surface( 'csf', csf )
ELSE
ALLOCATE( tmp(ndcsf,0) )
CALL wrd_mpi_io_surface( 'csf', tmp )
DEALLOCATE( tmp )
ENDIF
IF ( ALLOCATED( csfsurf ) ) THEN
ALLOCATE( tmp(SIZE(csfsurf,1),SIZE(csfsurf,2)) )
tmp(:,:) = csfsurf(:,:)
CALL wrd_mpi_io_surface( 'csfsurf', tmp )
DEALLOCATE( tmp )
ELSE
ALLOCATE( tmp(idcsf,ncsfl) )
CALL wrd_mpi_io_surface( 'csfsurf', tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
ENDIF
ENDIF
IF ( nmrtbl > 0 ) THEN
lo_no = 0
DO j = 1, nmrtbl
jc = mrtbl(iy,j)
ic = mrtbl(ix,j)
lo_no(jc,ic) = lo_no(jc,ic) + 1
ENDDO
ind = 1
DO i = nxl, nxr
DO j = nys, nyn
start_index(j,i) = ind
end_index(j,i) = start_index(j,i) + lo_no(j,i) - 1
ind = ind+lo_no(j,i)
ENDDO
ENDDO
ELSE
start_index = 1
end_index = 0
ENDIF
IF ( nmrtbl_tot > 0 ) THEN
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_write, global_start, &
global_end )
CALL wrd_mpi_io( 'nmrtbl_global_start', global_start )
CALL wrd_mpi_io( 'nmrtbl_global_end', global_end )
IF ( data_to_write ) THEN
CALL wrd_mpi_io_surface( 'mrtsky', mrtsky )
CALL wrd_mpi_io_surface( 'mrtskyt', mrtskyt )
ALLOCATE( tmp(SIZE(mrtdsit,2),SIZE(mrtdsit,1)) )
tmp = TRANSPOSE( mrtdsit )
CALL wrd_mpi_io_surface( 'mrtdsit', tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
IF ( nmrtf > 0 ) THEN
lo_no = 0
DO j = 1, nmrtf
isurf = mrtfsurf(1,j)
jc = surfl(iy,isurf)
ic = surfl(ix,isurf)
lo_no(jc,ic) = lo_no(jc,ic) + 1
ENDDO
ind = 1
DO i = nxl, nxr
DO j = nys, nyn
start_index(j,i) = ind
end_index(j,i) = start_index(j,i) + lo_no(j,i) - 1
ind = ind+lo_no(j,i)
ENDDO
ENDDO
ELSE
start_index = 1
end_index = 0
ENDIF
IF ( nmrtf_tot > 0 ) THEN
CALL rd_mpi_io_surface_filetypes( start_index, end_index, data_to_write, global_start, &
global_end)
CALL wrd_mpi_io( 'nmrtf_global_start', global_start )
CALL wrd_mpi_io( 'nmrtf_global_end', global_end )
IF ( data_to_write ) THEN
CALL wrd_mpi_io_surface ( 'mrtf', mrtf )
CALL wrd_mpi_io_surface ( 'mrtft', mrtft )
ALLOCATE( tmp(SIZE(mrtfsurf,1),SIZE(mrtfsurf,2)) )
tmp = mrtfsurf
CALL wrd_mpi_io_surface( 'mrtfsurf', tmp )
DEALLOCATE( tmp )
ENDIF
ENDIF
CALL rd_mpi_io_close
!
!-- Reset switch to its original value to be used for other than SVF I/O.
include_total_domain_boundaries = save_include_total_domain_boundaries
CALL location_message( 'writing sky view factors in MPI-IO format', 'finished' )
ENDIF
END SUBROUTINE radiation_write_svf
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Block of auxiliary subroutines for RTM:
!> 1. quicksort and corresponding comparison
!> 2. merge_and_grow_csf for implementation of "dynamical growing" array for csf
!--------------------------------------------------------------------------------------------------!
!-- quicksort.f -*-f90-*-
!-- Author: t-nissie, adaptation J.Resler
!-- License: GPLv3
!-- Gist: https://gist.github.com/t-nissie/479f0f16966925fa29ea
!--------------------------------------------------------------------------------------------------!
RECURSIVE SUBROUTINE quicksort_itarget( itarget, vffrac, ztransp, first, last )
IMPLICIT NONE
INTEGER(iwp) :: i, j !<
INTEGER(iwp) :: x, t !<
INTEGER(iwp), INTENT(IN) :: first, last !<
INTEGER(iwp), DIMENSION(:), INTENT(INOUT) :: itarget !<
REAL(wp) :: tr !<
REAL(wp), DIMENSION(:), INTENT(INOUT) :: vffrac, ztransp !<
IF ( first >= last ) RETURN
x = itarget(( first + last ) / 2)
i = first
j = last
DO
DO WHILE ( itarget(i) < x )
i = i+1
ENDDO
DO WHILE ( x < itarget(j) )
j = j-1
ENDDO
IF ( i >= j ) EXIT
t = itarget(i); itarget(i) = itarget(j); itarget(j) = t
tr = vffrac(i); vffrac(i) = vffrac(j); vffrac(j) = tr
tr = ztransp(i); ztransp(i) = ztransp(j); ztransp(j) = tr
i = i+1
j = j-1
ENDDO
IF ( first < i-1 ) CALL quicksort_itarget( itarget, vffrac, ztransp, first, i - 1 )
IF ( j+1 < last ) CALL quicksort_itarget( itarget, vffrac, ztransp, j + 1, last )
END SUBROUTINE quicksort_itarget
PURE FUNCTION svf_lt( svf1, svf2 ) result( res )
TYPE(t_svf), INTENT(in) :: svf1,svf2 !<
LOGICAL :: res !<
IF ( svf1%isurflt < svf2%isurflt .OR. &
(svf1%isurflt == svf2%isurflt .AND. svf1%isurfs < svf2%isurfs) ) THEN
res = .TRUE.
ELSE
res = .FALSE.
ENDIF
END FUNCTION svf_lt
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> @Todo: Missing subroutine description!
!--------------------------------------------------------------------------------------------------!
!-- quicksort.f -*-f90-*-
!-- Author: t-nissie, adaptation J.Resler
!-- License: GPLv3
!-- Gist: https://gist.github.com/t-nissie/479f0f16966925fa29ea
!--------------------------------------------------------------------------------------------------!
RECURSIVE SUBROUTINE quicksort_svf( svfl, first, last )
IMPLICIT NONE
INTEGER(iwp) :: i, j !<
INTEGER(iwp), INTENT(IN) :: first, last !<
TYPE(t_svf) :: x, t !<
TYPE(t_svf), DIMENSION(:), INTENT(INOUT) :: svfl !<
IF ( first >= last ) RETURN
x = svfl(( first + last ) / 2)
i = first
j = last
DO
DO WHILE ( svf_lt(svfl(i),x) )
i = i+1
ENDDO
DO WHILE ( svf_lt(x,svfl(j)) )
j=j-1
ENDDO
IF ( i >= j ) EXIT
t = svfl(i); svfl(i) = svfl(j); svfl(j) = t
i= i+1
j= j-1
ENDDO
IF ( first < i-1 ) CALL quicksort_svf( svfl, first, i - 1 )
IF ( j+1 < last ) CALL quicksort_svf( svfl, j + 1, last )
END SUBROUTINE quicksort_svf
PURE FUNCTION csf_lt( csf1, csf2 ) result( res )
LOGICAL :: res !<
TYPE(t_csf), INTENT(in) :: csf1,csf2 !<
IF ( csf1%ip < csf2%ip .OR. &
( csf1%ip == csf2%ip .AND. csf1%itx < csf2%itx ) .OR. &
( csf1%ip == csf2%ip .AND. csf1%itx == csf2%itx .AND. csf1%ity < csf2%ity ) .OR. &
( csf1%ip == csf2%ip .AND. csf1%itx == csf2%itx .AND. csf1%ity == csf2%ity .AND. &
csf1%itz < csf2%itz ) .OR. &
( csf1%ip == csf2%ip .AND. csf1%itx == csf2%itx .AND. csf1%ity == csf2%ity .AND. &
csf1%itz == csf2%itz .AND. csf1%isurfs < csf2%isurfs ) ) THEN
res = .TRUE.
ELSE
res = .FALSE.
ENDIF
END FUNCTION csf_lt
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> @Todo: Missing subroutine description!
!--------------------------------------------------------------------------------------------------!
!-- quicksort.f -*-f90-*-
!-- Author: t-nissie, adaptation J.Resler
!-- License: GPLv3
!-- Gist: https://gist.github.com/t-nissie/479f0f16966925fa29ea
!--------------------------------------------------------------------------------------------------!
RECURSIVE SUBROUTINE quicksort_csf(csfl, first, last)
IMPLICIT NONE
INTEGER(iwp) :: i, j !<
INTEGER(iwp), INTENT(IN) :: first, last !<
TYPE(t_csf) :: x, t !<
TYPE(t_csf), DIMENSION(:), INTENT(INOUT) :: csfl !<
IF ( first >= last ) RETURN
x = csfl(( first + last ) / 2)
i = first
j = last
DO
DO WHILE ( csf_lt(csfl(i),x) )
i = i+1
ENDDO
DO WHILE ( csf_lt(x,csfl(j)) )
j = j-1
ENDDO
IF ( i >= j ) EXIT
t = csfl(i); csfl(i) = csfl(j); csfl(j) = t
i = i+1
j = j-1
ENDDO
IF ( first < i-1 ) CALL quicksort_csf( csfl, first, i-1 )
IF ( j+1 < last ) CALL quicksort_csf( csfl, j+1, last )
END SUBROUTINE quicksort_csf
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Grows the CSF array in RTM exponentially when it is full. During that, the ray canopy sink
!> factors with common source face and target plant canopy grid cell are merged together so that the
!> size doesn't grow out of control.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE merge_and_grow_csf( newsize )
INTEGER(iwp) :: iread, iwrite !<
INTEGER(iwp), INTENT(IN) :: newsize !< new array size after grow, must be >= ncsfl
!< or -1 to shrink to minimum
TYPE(t_csf), DIMENSION(:), POINTER :: acsfnew !<
IF ( newsize == -1 ) THEN
!
!-- Merge in-place
acsfnew => acsf
ELSE
!
!-- Allocate new array
IF ( mcsf == 0 ) THEN
ALLOCATE( acsf1(newsize) )
acsfnew => acsf1
ELSE
ALLOCATE( acsf2(newsize) )
acsfnew => acsf2
ENDIF
ENDIF
IF ( ncsfl >= 1 ) THEN
!
!-- Sort csf in place (quicksort)
CALL quicksort_csf( acsf, 1, ncsfl )
!
!-- While moving to a new array, aggregate canopy sink factor records with identical box & source
acsfnew(1) = acsf(1)
iwrite = 1
DO iread = 2, ncsfl
!
!-- Here acsf(kcsf) already has values from acsf(icsf)
IF ( acsfnew(iwrite)%itx == acsf(iread)%itx &
.AND. acsfnew(iwrite)%ity == acsf(iread)%ity &
.AND. acsfnew(iwrite)%itz == acsf(iread)%itz &
.AND. acsfnew(iwrite)%isurfs == acsf(iread)%isurfs ) THEN
acsfnew(iwrite)%rcvf = acsfnew(iwrite)%rcvf + acsf(iread)%rcvf
!
!-- Advance reading index, keep writing index
ELSE
!
!-- Not identical, just advance and copy
iwrite = iwrite + 1
acsfnew(iwrite) = acsf(iread)
ENDIF
ENDDO
ncsfl = iwrite
ENDIF
IF ( newsize == -1 ) THEN
!
!-- Allocate new array and copy shrinked data
IF ( mcsf == 0 ) THEN
ALLOCATE( acsf1(ncsfl) )
acsf1(1:ncsfl) = acsf2(1:ncsfl)
ELSE
ALLOCATE( acsf2(ncsfl) )
acsf2(1:ncsfl) = acsf1(1:ncsfl)
ENDIF
ENDIF
!
!-- Deallocate old array
IF ( mcsf == 0 ) THEN
mcsf = 1
acsf => acsf1
DEALLOCATE( acsf2 )
ELSE
mcsf = 0
acsf => acsf2
DEALLOCATE( acsf1 )
ENDIF
ncsfla = newsize
IF ( debug_output ) THEN
WRITE( debug_string, '(A,2I12)' ) 'Grow acsf2:', ncsfl, ncsfla
CALL debug_message( debug_string, 'info' )
ENDIF
END SUBROUTINE merge_and_grow_csf
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> @Todo: Missing subroutine description!
!--------------------------------------------------------------------------------------------------!
!-- quicksort.f -*-f90-*-
!-- Author: t-nissie, adaptation J.Resler
!-- License: GPLv3
!-- Gist: https://gist.github.com/t-nissie/479f0f16966925fa29ea
!--------------------------------------------------------------------------------------------------!
RECURSIVE SUBROUTINE quicksort_csf2( kpcsflt, pcsflt, first, last )
IMPLICIT NONE
INTEGER(iwp) :: i, j !<
INTEGER(iwp), INTENT(IN) :: first, last !<
INTEGER(iwp), DIMENSION(kdcsf) :: x, t1 !<
INTEGER(iwp), DIMENSION(:,:), INTENT(INOUT) :: kpcsflt !<
REAL(wp), DIMENSION(ndcsf) :: t2 !<
REAL(wp), DIMENSION(:,:), INTENT(INOUT) :: pcsflt !<
IF ( first >= last ) RETURN
x = kpcsflt(:, ( first + last ) / 2 )
i = first
j = last
DO
DO WHILE ( csf_lt2(kpcsflt(:,i),x) )
i = i+1
ENDDO
DO WHILE ( csf_lt2(x,kpcsflt(:,j)) )
j = j-1
ENDDO
IF ( i >= j ) EXIT
t1 = kpcsflt(:,i); kpcsflt(:,i) = kpcsflt(:,j); kpcsflt(:,j) = t1
t2 = pcsflt(:,i); pcsflt(:,i) = pcsflt(:,j); pcsflt(:,j) = t2
i=i+1
j=j-1
ENDDO
IF ( first < i-1 ) CALL quicksort_csf2( kpcsflt, pcsflt, first, i-1 )
IF ( j+1 < last ) CALL quicksort_csf2( kpcsflt, pcsflt, j+1, last )
END SUBROUTINE quicksort_csf2
PURE FUNCTION csf_lt2( item1, item2 ) result( res )
INTEGER(iwp), DIMENSION(kdcsf), INTENT(IN) :: item1, item2 !<
LOGICAL :: res !<
res = ( ( item1(3) < item2(3) ) .OR. ( item1(3) == item2(3) .AND. item1(2) < item2(2) ) &
.OR. ( item1(3) == item2(3) .AND. item1(2) == item2(2) .AND. item1(1) < item2(1) )&
.OR. ( item1(3) == item2(3) .AND. item1(2) == item2(2) .AND. item1(1) == item2(1) &
.AND. item1(4) < item2(4) ) )
END FUNCTION csf_lt2
PURE FUNCTION searchsorted( athresh, val ) result( ind )
INTEGER(iwp) :: i !<
INTEGER(iwp) :: ind !<
REAL(wp), INTENT(IN) :: val !<
REAL(wp), DIMENSION(:), INTENT(IN) :: athresh !<
DO i = LBOUND( athresh, 1 ), UBOUND( athresh, 1 )
IF ( val < athresh(i) ) THEN
ind = i - 1
RETURN
ENDIF
ENDDO
ind = UBOUND( athresh, 1 )
END FUNCTION searchsorted
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> For given coordinates, calculates indices within a global 3D (or 2D if nlayers=1) field, e.g. an
!> MPI one-sided window or an array which has been created using e.g. MPI_AllGather.
!--------------------------------------------------------------------------------------------------!
PURE SUBROUTINE radiation_calc_global_offset( i, j, k, nlayers, iproc, offs_proc, offs_glob )
IMPLICIT NONE
INTEGER(iwp), INTENT(IN) :: i !< x-coordinate
INTEGER(iwp), INTENT(IN) :: j !< y-coordinate
INTEGER(iwp), INTENT(IN) :: k !< z-coordinate
INTEGER(iwp), INTENT(IN) :: nlayers !< number of z-layers
INTEGER(iwp), INTENT(OUT), OPTIONAL :: iproc !< MPI process rank
#if defined( __parallel )
INTEGER(kind=MPI_ADDRESS_KIND), INTENT(OUT), OPTIONAL :: offs_proc !< offset within MPI proc
#else
INTEGER(iwp), INTENT(OUT), OPTIONAL :: offs_proc !(actually unused without __parallel)
#endif
INTEGER(iwp), INTENT(OUT), OPTIONAL :: offs_glob !< global offset
INTEGER(iwp) :: iproc_l !< local variable for iproc
INTEGER(iwp) :: oproc_l !< local variable for offs_proc
iproc_l = ipx(i) * npey + ipy(j)
IF ( PRESENT( iproc ) ) iproc = iproc_l
IF ( PRESENT( offs_proc ) .OR. PRESENT( offs_glob ) ) THEN
oproc_l = (i - nxl_pe(ipx(i))) * (nyn_pe(ipy(j)) - nys_pe(ipy(j)) + 1) * nlayers + & ! columns before
(j - nys_pe(ipy(j))) * nlayers + & ! rows in column
k
IF ( PRESENT( offs_proc ) ) offs_proc = oproc_l
IF ( PRESENT( offs_glob ) ) THEN
IF ( iproc_l == 0 ) THEN
offs_glob = oproc_l
ELSE
offs_glob = nnxyd(iproc_l) * nlayers + oproc_l
ENDIF
ENDIF
ENDIF
END SUBROUTINE radiation_calc_global_offset
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Performs MPI alltoall exchange for integer and floating-point data, optionally splitting the
!> exchange to multiple iterations with maximum number of items per iteration.
!--------------------------------------------------------------------------------------------------!
#if defined( __parallel )
SUBROUTINE radiation_exchange_alltoall( ntosend, npint, npfloat, isendbuf, fsendbuf, nrecv, &
irecvbuf, frecvbuf )
IMPLICIT NONE
INTEGER(iwp) :: i, j !< iterators
INTEGER(iwp) :: iproc !< process iterator
INTEGER(iwp) :: iter !< current iteration
INTEGER(iwp) :: niters !< local number of iterations needed
INTEGER(iwp) :: nitersg !< global no. of iterations needed
INTEGER(iwp) :: nmaxsend !< max no. of records sent to each process in each iteration
INTEGER(iwp), INTENT(IN) :: npint !< no. of integers in a record
INTEGER(iwp), INTENT(IN) :: npfloat !< no. of floats in a record
INTEGER(iwp), INTENT(OUT) :: nrecv !< total no. of records received
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: drecv !< received data displacements per proc
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: drecvnow !< current receive displacements
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: dsend !< sent data displacements per process
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: dsendnow !< current send displacements
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nrecvnow !< no. of items to receive in current iteration
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nsendnow !< no. of items to send in current iteration
INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: ntorecv !< no. of records to receive from each process
INTEGER(iwp), DIMENSION(0:), INTENT(IN) :: isendbuf !< send buffer with integers
INTEGER(iwp), DIMENSION(0:), INTENT(IN) :: ntosend !< number of records to send to each process
INTEGER(iwp), DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: irecvbuf !< int receive buffer (will be allocated to proper size)
REAL(wp), DIMENSION(0:), INTENT(IN) :: fsendbuf !< send buffer with floats
REAL(wp), DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: frecvbuf !< float receive buffer
ALLOCATE( ntorecv(0:numprocs-1) )
ALLOCATE( dsend(0:numprocs) )
ALLOCATE( drecv(0:numprocs) )
ALLOCATE( dsendnow(0:numprocs-1) )
ALLOCATE( drecvnow(0:numprocs-1) )
ALLOCATE( nsendnow(0:numprocs-1) )
ALLOCATE( nrecvnow(0:numprocs-1) )
!
!-- Exchange send and receive sizes
CALL MPI_ALLTOALL( ntosend, 1, MPI_INTEGER, ntorecv, 1, MPI_INTEGER, comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error at MPI_ALLTOALL1:', ierr, ntosend, ntorecv
FLUSH( 9 )
ENDIF
!
!-- Calculate initial displacements
i = 0
j = 0
DO iproc = 0, numprocs-1
dsend(iproc) = i
dsendnow(iproc) = i
drecv(iproc) = j
drecvnow(iproc) = j
i = i + ntosend(iproc)
j = j + ntorecv(iproc)
ENDDO
dsend(numprocs) = i ! Behind last pos = sum of all to send
drecv(numprocs) = j ! Behind last pos = sum of all to receive
nrecv = j
!
!-- Allocate receive buffers
ALLOCATE( irecvbuf(0:nrecv*npint-1) )
ALLOCATE( frecvbuf(0:nrecv*npfloat-1) )
!
!-- Determine number of iterations among all processes
!-- (e.g. this process may have nothing to send and receive, yet some other still might)
IF ( bufsize_alltoall <= 0 ) THEN
nitersg = 1
nmaxsend = HUGE( nitersg )
ELSE
nmaxsend = bufsize_alltoall
niters = ( MAXVAL( ntosend(:) ) + nmaxsend - 1 ) / nmaxsend
CALL MPI_ALLREDUCE( niters, nitersg, 1, MPI_INTEGER, MPI_MAX, comm2d, ierr )
IF ( nitersg > 1 ) THEN
WRITE( debug_string, '("The MPI_ALLTOALL call has been split to ",I8," iterations ' // &
'of max. ",I12," records each.")' ) nitersg, bufsize_alltoall
CALL debug_message( debug_string, 'info' )
ENDIF
ENDIF
!
!-- Iterate alltoall using max-sized buffers
DO iter = 1, nitersg
nsendnow(:) = MIN( dsend(1:) - dsendnow(:), nmaxsend )
nrecvnow(:) = MIN( drecv(1:) - drecvnow(:), nmaxsend )
!
!-- Send integer data
CALL MPI_ALLTOALLV( isendbuf, nsendnow(:) * npint, dsendnow(:) * npint, MPI_INTEGER, &
irecvbuf, nrecvnow(:) * npint, drecvnow(:) * npint, MPI_INTEGER, &
comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error at MPI_ALLTOALLV 1:', ierr, iter, nmaxsend, dsend, dsendnow, &
nsendnow, drecv, drecvnow, nrecvnow
FLUSH( 9 )
ENDIF
!
!-- Send floating point data
CALL MPI_ALLTOALLV( fsendbuf, nsendnow(:) * npfloat, dsendnow(:) * npfloat, MPI_REAL, &
frecvbuf, nrecvnow(:) * npfloat, drecvnow(:) * npfloat, MPI_REAL, &
comm2d, ierr )
IF ( ierr /= 0 ) THEN
WRITE( 9, * ) 'Error at MPI_ALLTOALLV 2:', ierr, iter, nmaxsend, dsend, dsendnow, &
nsendnow, drecv, drecvnow, nrecvnow
FLUSH( 9 )
ENDIF
!
!-- Shift displacements for next iteration
dsendnow(:) = dsendnow(:) + nsendnow(:)
drecvnow(:) = drecvnow(:) + nrecvnow(:)
ENDDO
DEALLOCATE( ntorecv, dsend, drecv, dsendnow, drecvnow, nsendnow, nrecvnow )
END SUBROUTINE radiation_exchange_alltoall
#endif
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Subroutine for averaging 3D data
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_3d_data_averaging( mode, variable )
USE control_parameters
USE indices
USE kinds
IMPLICIT NONE
CHARACTER(LEN=*) :: variable !<
CHARACTER(LEN=*) :: mode !<
CHARACTER(LEN=varnamelength) :: var !<
INTEGER(iwp) :: i !<
INTEGER(iwp) :: imrt !< index of MRT
INTEGER(iwp) :: j !<
INTEGER(iwp) :: k !<
INTEGER(iwp) :: l, m !< index of current surface element
INTEGER(iwp) :: ids, idsint, isurf !<
LOGICAL :: match_lsm !< flag indicating natural-type surface
LOGICAL :: match_usm !< flag indicating urban-type surface
!
!-- Find the real name of the variable
ids = -1
l = -1
var = TRIM( variable )
DO i = 0, nd-1
k = LEN( TRIM( var ) )
j = LEN( TRIM( dirname(i) ) )
IF ( k - j + 1 >= 1_iwp ) THEN
IF ( TRIM( var(k-j+1:k) ) == TRIM( dirname(i) ) ) THEN
ids = i
idsint = dirint(ids)
var = var(:k-j)
EXIT
ENDIF
ENDIF
ENDDO
IF ( ids == -1 ) THEN
var = TRIM( variable )
ENDIF
IF ( mode == 'allocate' ) THEN
SELECT CASE ( TRIM( var ) )
!
!-- Block of large scale (e.g. RRTMG) radiation output variables
CASE ( 'rad_net*' )
IF ( .NOT. ALLOCATED( rad_net_av ) ) THEN
ALLOCATE( rad_net_av(nysg:nyng,nxlg:nxrg) )
ENDIF
rad_net_av = 0.0_wp
CASE ( 'rad_lw_in*' )
IF ( .NOT. ALLOCATED( rad_lw_in_xy_av ) ) THEN
ALLOCATE( rad_lw_in_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
rad_lw_in_xy_av = 0.0_wp
CASE ( 'rad_lw_out*' )
IF ( .NOT. ALLOCATED( rad_lw_out_xy_av ) ) THEN
ALLOCATE( rad_lw_out_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
rad_lw_out_xy_av = 0.0_wp
CASE ( 'rad_sw_in*' )
IF ( .NOT. ALLOCATED( rad_sw_in_xy_av ) ) THEN
ALLOCATE( rad_sw_in_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
rad_sw_in_xy_av = 0.0_wp
CASE ( 'rad_sw_out*' )
IF ( .NOT. ALLOCATED( rad_sw_out_xy_av ) ) THEN
ALLOCATE( rad_sw_out_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
rad_sw_out_xy_av = 0.0_wp
CASE ( 'rad_lw_in' )
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) THEN
ALLOCATE( rad_lw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_lw_in_av = 0.0_wp
CASE ( 'rad_lw_out' )
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) THEN
ALLOCATE( rad_lw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_lw_out_av = 0.0_wp
CASE ( 'rad_lw_cs_hr' )
IF ( .NOT. ALLOCATED( rad_lw_cs_hr_av ) ) THEN
ALLOCATE( rad_lw_cs_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_lw_cs_hr_av = 0.0_wp
CASE ( 'rad_lw_hr' )
IF ( .NOT. ALLOCATED( rad_lw_hr_av ) ) THEN
ALLOCATE( rad_lw_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_lw_hr_av = 0.0_wp
CASE ( 'rad_sw_in' )
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) THEN
ALLOCATE( rad_sw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_sw_in_av = 0.0_wp
CASE ( 'rad_sw_out' )
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) THEN
ALLOCATE( rad_sw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_sw_out_av = 0.0_wp
CASE ( 'rad_sw_cs_hr' )
IF ( .NOT. ALLOCATED( rad_sw_cs_hr_av ) ) THEN
ALLOCATE( rad_sw_cs_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_sw_cs_hr_av = 0.0_wp
CASE ( 'rad_sw_hr' )
IF ( .NOT. ALLOCATED( rad_sw_hr_av ) ) THEN
ALLOCATE( rad_sw_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
rad_sw_hr_av = 0.0_wp
!
!-- Block of RTM output variables
CASE ( 'rtm_rad_net' )
!
!-- Array of complete radiation balance
IF ( .NOT. ALLOCATED( surfradnet_av ) ) THEN
ALLOCATE( surfradnet_av(nsurfl) )
ENDIF
surfradnet_av = 0.0_wp
CASE ( 'rtm_rad_insw' )
!
!-- Array of sw radiation falling to surface after i-th reflection
IF ( .NOT. ALLOCATED( surfinsw_av ) ) THEN
ALLOCATE( surfinsw_av(nsurfl) )
ENDIF
surfinsw_av = 0.0_wp
CASE ( 'rtm_rad_inlw' )
!
!-- Array of lw radiation falling to surface after i-th reflection
IF ( .NOT. ALLOCATED( surfinlw_av ) ) THEN
ALLOCATE( surfinlw_av(nsurfl) )
ENDIF
surfinlw_av = 0.0_wp
CASE ( 'rtm_rad_inswdir' )
!
!-- Array of direct sw radiation falling to surface from sun
IF ( .NOT. ALLOCATED( surfinswdir_av ) ) THEN
ALLOCATE( surfinswdir_av(nsurfl) )
ENDIF
surfinswdir_av = 0.0_wp
CASE ( 'rtm_rad_inswdif' )
!
!-- Array of difusion sw radiation falling to surface from sky and borders of the domain
IF ( .NOT. ALLOCATED( surfinswdif_av ) ) THEN
ALLOCATE( surfinswdif_av(nsurfl) )
ENDIF
surfinswdif_av = 0.0_wp
CASE ( 'rtm_rad_inswref' )
!
!-- Array of sw radiation falling to surface from reflections
IF ( .NOT. ALLOCATED( surfinswref_av ) ) THEN
ALLOCATE( surfinswref_av(nsurfl) )
ENDIF
surfinswref_av = 0.0_wp
CASE ( 'rtm_rad_inlwdif' )
!
!-- Array of sw radiation falling to surface after i-th reflection
IF ( .NOT. ALLOCATED( surfinlwdif_av ) ) THEN
ALLOCATE( surfinlwdif_av(nsurfl) )
ENDIF
surfinlwdif_av = 0.0_wp
CASE ( 'rtm_rad_inlwref' )
!
!-- Array of lw radiation falling to surface from reflections
IF ( .NOT. ALLOCATED( surfinlwref_av ) ) THEN
ALLOCATE( surfinlwref_av(nsurfl) )
ENDIF
surfinlwref_av = 0.0_wp
CASE ( 'rtm_rad_outsw' )
!
!-- Array of sw radiation emitted from surface after i-th reflection
IF ( .NOT. ALLOCATED( surfoutsw_av ) ) THEN
ALLOCATE( surfoutsw_av(nsurfl) )
ENDIF
surfoutsw_av = 0.0_wp
CASE ( 'rtm_rad_outlw' )
!
!-- Array of lw radiation emitted from surface after i-th reflection
IF ( .NOT. ALLOCATED( surfoutlw_av ) ) THEN
ALLOCATE( surfoutlw_av(nsurfl) )
surfoutlw_av = 0.0_wp
ENDIF
CASE ( 'rtm_rad_ressw' )
!
!-- Array of residua of sw radiation absorbed in surface after last reflection
IF ( .NOT. ALLOCATED( surfins_av ) ) THEN
ALLOCATE( surfins_av(nsurfl) )
ENDIF
surfins_av = 0.0_wp
CASE ( 'rtm_rad_reslw' )
!
!-- Array of residua of lw radiation absorbed in surface after last reflection
IF ( .NOT. ALLOCATED( surfinl_av ) ) THEN
ALLOCATE( surfinl_av(nsurfl) )
ENDIF
surfinl_av = 0.0_wp
CASE ( 'rtm_rad_pc_inlw' )
!
!-- Array of of lw radiation absorbed in plant canopy
IF ( .NOT. ALLOCATED( pcbinlw_av ) ) THEN
ALLOCATE( pcbinlw_av(1:npcbl) )
pcbinlw_av = 0.0_wp
ENDIF
CASE ( 'rtm_rad_pc_insw' )
!
!-- Array of of sw radiation absorbed in plant canopy
IF ( .NOT. ALLOCATED( pcbinsw_av ) ) THEN
ALLOCATE( pcbinsw_av(1:npcbl) )
ENDIF
pcbinsw_av = 0.0_wp
CASE ( 'rtm_rad_pc_inswdir' )
!
!-- Array of of direct sw radiation absorbed in plant canopy
IF ( .NOT. ALLOCATED( pcbinswdir_av ) ) THEN
ALLOCATE( pcbinswdir_av(1:npcbl) )
ENDIF
pcbinswdir_av = 0.0_wp
CASE ( 'rtm_rad_pc_inswdif' )
!
!-- Array of of diffuse sw radiation absorbed in plant canopy
IF ( .NOT. ALLOCATED( pcbinswdif_av ) ) THEN
ALLOCATE( pcbinswdif_av(1:npcbl) )
ENDIF
pcbinswdif_av = 0.0_wp
CASE ( 'rtm_rad_pc_inswref' )
!
!-- Array of of reflected sw radiation absorbed in plant canopy
IF ( .NOT. ALLOCATED( pcbinswref_av ) ) THEN
ALLOCATE( pcbinswref_av(1:npcbl) )
ENDIF
pcbinswref_av = 0.0_wp
CASE ( 'rtm_mrt_sw' )
IF ( .NOT. ALLOCATED( mrtinsw_av ) ) THEN
ALLOCATE( mrtinsw_av(nmrtbl) )
ENDIF
mrtinsw_av = 0.0_wp
CASE ( 'rtm_mrt_lw' )
IF ( .NOT. ALLOCATED( mrtinlw_av ) ) THEN
ALLOCATE( mrtinlw_av(nmrtbl) )
ENDIF
mrtinlw_av = 0.0_wp
CASE ( 'rtm_mrt' )
IF ( .NOT. ALLOCATED( mrt_av ) ) THEN
ALLOCATE( mrt_av(nmrtbl) )
ENDIF
mrt_av = 0.0_wp
CASE DEFAULT
CONTINUE
END SELECT
ELSEIF ( mode == 'sum' ) THEN
SELECT CASE ( TRIM( var ) )
!
!-- Block of large scale (e.g. RRTMG) radiation output variables only upward faced horizontal
!-- surfaces are considered here
CASE ( 'rad_net*' )
IF ( ALLOCATED( rad_net_av ) ) THEN
DO i = nxl, nxr
DO j = nys, nyn
match_lsm = surf_lsm_h(0)%start_index(j,i) <= surf_lsm_h(0)%end_index(j,i)
match_usm = surf_usm_h(0)%start_index(j,i) <= surf_usm_h(0)%end_index(j,i)
IF ( match_lsm .AND. .NOT. match_usm ) THEN
m = surf_lsm_h(0)%end_index(j,i)
rad_net_av(j,i) = rad_net_av(j,i) + surf_lsm_h(0)%rad_net(m)
ELSEIF ( match_usm ) THEN
m = surf_usm_h(0)%end_index(j,i)
rad_net_av(j,i) = rad_net_av(j,i) + &
surf_usm_h(0)%rad_net(m)
ENDIF
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_in*' )
IF ( ALLOCATED( rad_lw_in_xy_av ) ) THEN
DO i = nxl, nxr
DO j = nys, nyn
match_lsm = surf_lsm_h(0)%start_index(j,i) <= surf_lsm_h(0)%end_index(j,i)
match_usm = surf_usm_h(0)%start_index(j,i) <= surf_usm_h(0)%end_index(j,i)
IF ( match_lsm .AND. .NOT. match_usm ) THEN
m = surf_lsm_h(0)%end_index(j,i)
rad_lw_in_xy_av(j,i) = rad_lw_in_xy_av(j,i) + surf_lsm_h(0)%rad_lw_in(m)
ELSEIF ( match_usm ) THEN
m = surf_usm_h(0)%end_index(j,i)
rad_lw_in_xy_av(j,i) = rad_lw_in_xy_av(j,i) + surf_usm_h(0)%rad_lw_in(m)
ENDIF
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_out*' )
IF ( ALLOCATED( rad_lw_out_xy_av ) ) THEN
DO i = nxl, nxr
DO j = nys, nyn
match_lsm = surf_lsm_h(0)%start_index(j,i) <= surf_lsm_h(0)%end_index(j,i)
match_usm = surf_usm_h(0)%start_index(j,i) <= surf_usm_h(0)%end_index(j,i)
IF ( match_lsm .AND. .NOT. match_usm ) THEN
m = surf_lsm_h(0)%end_index(j,i)
rad_lw_out_xy_av(j,i) = rad_lw_out_xy_av(j,i) + surf_lsm_h(0)%rad_lw_out(m)
ELSEIF ( match_usm ) THEN
m = surf_usm_h(0)%end_index(j,i)
rad_lw_out_xy_av(j,i) = rad_lw_out_xy_av(j,i) + surf_usm_h(0)%rad_lw_out(m)
ENDIF
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_in*' )
IF ( ALLOCATED( rad_sw_in_xy_av ) ) THEN
DO i = nxl, nxr
DO j = nys, nyn
match_lsm = surf_lsm_h(0)%start_index(j,i) <= surf_lsm_h(0)%end_index(j,i)
match_usm = surf_usm_h(0)%start_index(j,i) <= surf_usm_h(0)%end_index(j,i)
IF ( match_lsm .AND. .NOT. match_usm ) THEN
m = surf_lsm_h(0)%end_index(j,i)
rad_sw_in_xy_av(j,i) = rad_sw_in_xy_av(j,i) + surf_lsm_h(0)%rad_sw_in(m)
ELSEIF ( match_usm ) THEN
m = surf_usm_h(0)%end_index(j,i)
rad_sw_in_xy_av(j,i) = rad_sw_in_xy_av(j,i) + surf_usm_h(0)%rad_sw_in(m)
ENDIF
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_out*' )
IF ( ALLOCATED( rad_sw_out_xy_av ) ) THEN
DO i = nxl, nxr
DO j = nys, nyn
match_lsm = surf_lsm_h(0)%start_index(j,i) <= surf_lsm_h(0)%end_index(j,i)
match_usm = surf_usm_h(0)%start_index(j,i) <= surf_usm_h(0)%end_index(j,i)
IF ( match_lsm .AND. .NOT. match_usm ) THEN
m = surf_lsm_h(0)%end_index(j,i)
rad_sw_out_xy_av(j,i) = rad_sw_out_xy_av(j,i) + surf_lsm_h(0)%rad_sw_out(m)
ELSEIF ( match_usm ) THEN
m = surf_usm_h(0)%end_index(j,i)
rad_sw_out_xy_av(j,i) = rad_sw_out_xy_av(j,i) + surf_usm_h(0)%rad_sw_out(m)
ENDIF
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_in' )
IF ( ALLOCATED( rad_lw_in_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_in_av(k,j,i) = rad_lw_in_av(k,j,i) + rad_lw_in(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_out' )
IF ( ALLOCATED( rad_lw_out_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_out_av(k,j,i) = rad_lw_out_av(k,j,i) + rad_lw_out(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_cs_hr' )
IF ( ALLOCATED( rad_lw_cs_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_cs_hr_av(k,j,i) = rad_lw_cs_hr_av(k,j,i) + rad_lw_cs_hr(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_hr' )
IF ( ALLOCATED( rad_lw_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_hr_av(k,j,i) = rad_lw_hr_av(k,j,i) + rad_lw_hr(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_in' )
IF ( ALLOCATED( rad_sw_in_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_in_av(k,j,i) = rad_sw_in_av(k,j,i) + rad_sw_in(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_out' )
IF ( ALLOCATED( rad_sw_out_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_out_av(k,j,i) = rad_sw_out_av(k,j,i) + rad_sw_out(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_cs_hr' )
IF ( ALLOCATED( rad_sw_cs_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_cs_hr_av(k,j,i) = rad_sw_cs_hr_av(k,j,i) + rad_sw_cs_hr(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_hr' )
IF ( ALLOCATED( rad_sw_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_hr_av(k,j,i) = rad_sw_hr_av(k,j,i) + rad_sw_hr(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
!
!-- Block of RTM output variables
CASE ( 'rtm_rad_net' )
!
!-- Array of complete radiation balance
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfradnet_av(isurf) = surfradnet_av(isurf) + surfinsw(isurf) - &
surfoutsw(isurf) + surfinlw(isurf) - surfoutlw(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_insw' )
!
!-- Array of sw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinsw_av(isurf) = surfinsw_av(isurf) + surfinsw(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_inlw' )
!
!-- Array of lw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinlw_av(isurf) = surfinlw_av(isurf) + surfinlw(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_inswdir' )
!
!-- Array of direct sw radiation falling to surface from sun
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinswdir_av(isurf) = surfinswdir_av(isurf) + surfinswdir(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_inswdif' )
!
!-- Array of diffusion sw radiation falling to surface from sky and borders of the domain
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinswdif_av(isurf) = surfinswdif_av(isurf) + surfinswdif(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_inswref' )
!
!-- Array of sw radiation falling to surface from reflections
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinswref_av(isurf) = surfinswref_av(isurf) + surfinsw(isurf) - &
surfinswdir(isurf) - surfinswdif(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_inlwdif' )
!
!-- Array of sw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinlwdif_av(isurf) = surfinlwdif_av(isurf) + surfinlwdif(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_inlwref' )
!
!-- Array of lw radiation falling to surface from reflections
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinlwref_av(isurf) = surfinlwref_av(isurf) + &
surfinlw(isurf) - surfinlwdif(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_outsw' )
!
!-- Array of sw radiation emitted from surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfoutsw_av(isurf) = surfoutsw_av(isurf) + surfoutsw(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_outlw' )
!
!-- Array of lw radiation emitted from surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfoutlw_av(isurf) = surfoutlw_av(isurf) + surfoutlw(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_ressw' )
!
!-- Array of residua of sw radiation absorbed in surface after last reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfins_av(isurf) = surfins_av(isurf) + surfins(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_reslw' )
!
!-- Array of residua of lw radiation absorbed in surface after last reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinl_av(isurf) = surfinl_av(isurf) + surfinl(isurf)
ENDIF
ENDDO
CASE ( 'rtm_rad_pc_inlw' )
DO l = 1, npcbl
pcbinlw_av(l) = pcbinlw_av(l) + pcbinlw(l)
ENDDO
CASE ( 'rtm_rad_pc_insw' )
DO l = 1, npcbl
pcbinsw_av(l) = pcbinsw_av(l) + pcbinsw(l)
ENDDO
CASE ( 'rtm_rad_pc_inswdir' )
DO l = 1, npcbl
pcbinswdir_av(l) = pcbinswdir_av(l) + pcbinswdir(l)
ENDDO
CASE ( 'rtm_rad_pc_inswdif' )
DO l = 1, npcbl
pcbinswdif_av(l) = pcbinswdif_av(l) + pcbinswdif(l)
ENDDO
CASE ( 'rtm_rad_pc_inswref' )
DO l = 1, npcbl
pcbinswref_av(l) = pcbinswref_av(l) + pcbinsw(l) - pcbinswdir(l) - pcbinswdif(l)
ENDDO
CASE ( 'rtm_mrt_sw' )
IF ( ALLOCATED( mrtinsw_av ) ) THEN
mrtinsw_av(:) = mrtinsw_av(:) + mrtinsw(:)
ENDIF
CASE ( 'rtm_mrt_lw' )
IF ( ALLOCATED( mrtinlw_av ) ) THEN
mrtinlw_av(:) = mrtinlw_av(:) + mrtinlw(:)
ENDIF
CASE ( 'rtm_mrt' )
IF ( ALLOCATED( mrt_av ) ) THEN
mrt_av(:) = mrt_av(:) + mrt(:)
ENDIF
CASE DEFAULT
CONTINUE
END SELECT
ELSEIF ( mode == 'average' ) THEN
SELECT CASE ( TRIM( var ) )
!
!-- Block of large scale (e.g. RRTMG) radiation output variables
CASE ( 'rad_net*' )
IF ( ALLOCATED( rad_net_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
rad_net_av(j,i) = rad_net_av(j,i) / REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_in*' )
IF ( ALLOCATED( rad_lw_in_xy_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
rad_lw_in_xy_av(j,i) = rad_lw_in_xy_av(j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_out*' )
IF ( ALLOCATED( rad_lw_out_xy_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
rad_lw_out_xy_av(j,i) = rad_lw_out_xy_av(j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_in*' )
IF ( ALLOCATED( rad_sw_in_xy_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
rad_sw_in_xy_av(j,i) = rad_sw_in_xy_av(j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_out*' )
IF ( ALLOCATED( rad_sw_out_xy_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
rad_sw_out_xy_av(j,i) = rad_sw_out_xy_av(j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_in' )
IF ( ALLOCATED( rad_lw_in_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_in_av(k,j,i) = rad_lw_in_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_out' )
IF ( ALLOCATED( rad_lw_out_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_out_av(k,j,i) = rad_lw_out_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_cs_hr' )
IF ( ALLOCATED( rad_lw_cs_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_cs_hr_av(k,j,i) = rad_lw_cs_hr_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_hr' )
IF ( ALLOCATED( rad_lw_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_lw_hr_av(k,j,i) = rad_lw_hr_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_in' )
IF ( ALLOCATED( rad_sw_in_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_in_av(k,j,i) = rad_sw_in_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_out' )
IF ( ALLOCATED( rad_sw_out_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_out_av(k,j,i) = rad_sw_out_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_cs_hr' )
IF ( ALLOCATED( rad_sw_cs_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_cs_hr_av(k,j,i) = rad_sw_cs_hr_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_hr' )
IF ( ALLOCATED( rad_sw_hr_av ) ) THEN
DO i = nxlg, nxrg
DO j = nysg, nyng
DO k = nzb, nzt+1
rad_sw_hr_av(k,j,i) = rad_sw_hr_av(k,j,i) / &
REAL( average_count_3d, KIND = wp )
ENDDO
ENDDO
ENDDO
ENDIF
!
!-- Block of RTM output variables
CASE ( 'rtm_rad_net' )
!
!-- Array of complete radiation balance
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfradnet_av(isurf) = surfradnet_av(isurf) / &
REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_insw' )
!
!-- Array of sw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinsw_av(isurf) = surfinsw_av(isurf) / REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_inlw' )
!
!-- Array of lw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinlw_av(isurf) = surfinlw_av(isurf) / REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_inswdir' )
!
!-- Array of direct sw radiation falling to surface from sun
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinswdir_av(isurf) = surfinswdir_av(isurf) / &
REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_inswdif' )
!
!-- Array of diffusion sw radiation falling to surface from sky and borders of the domain
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinswdif_av(isurf) = surfinswdif_av(isurf) / &
REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_inswref' )
!
!-- Array of sw radiation falling to surface from reflections
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinswref_av(isurf) = surfinswref_av(isurf) / &
REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_inlwdif' )
!
!-- Array of sw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinlwdif_av(isurf) = surfinlwdif_av(isurf) / &
REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_inlwref' )
!
!-- Array of lw radiation falling to surface from reflections
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinlwref_av(isurf) = surfinlwref_av(isurf) / &
REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_outsw' )
!
!-- Array of sw radiation emitted from surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfoutsw_av(isurf) = surfoutsw_av(isurf) / REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_outlw' )
!
!-- Array of lw radiation emitted from surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfoutlw_av(isurf) = surfoutlw_av(isurf) / REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_ressw' )
!
!-- Array of residua of sw radiation absorbed in surface after last reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfins_av(isurf) = surfins_av(isurf) / REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_reslw' )
!
!-- Array of residua of lw radiation absorbed in surface after last reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
surfinl_av(isurf) = surfinl_av(isurf) / REAL( average_count_3d, KIND = wp )
ENDIF
ENDDO
CASE ( 'rtm_rad_pc_inlw' )
DO l = 1, npcbl
pcbinlw_av(l) = pcbinlw_av(l) / REAL( average_count_3d, KIND = wp )
ENDDO
CASE ( 'rtm_rad_pc_insw' )
DO l = 1, npcbl
pcbinsw_av(l) = pcbinsw_av(l) / REAL( average_count_3d, KIND = wp )
ENDDO
CASE ( 'rtm_rad_pc_inswdir' )
DO l = 1, npcbl
pcbinswdir_av(l) = pcbinswdir_av(l) / REAL( average_count_3d, KIND = wp )
ENDDO
CASE ( 'rtm_rad_pc_inswdif' )
DO l = 1, npcbl
pcbinswdif_av(l) = pcbinswdif_av(l) / REAL( average_count_3d, KIND = wp )
ENDDO
CASE ( 'rtm_rad_pc_inswref' )
DO l = 1, npcbl
pcbinswref_av(l) = pcbinswref_av(l) / REAL( average_count_3d, KIND = wp )
ENDDO
CASE ( 'rtm_mrt_sw' )
IF ( ALLOCATED( mrtinsw_av ) ) THEN
DO imrt = 1, nmrtbl
mrtinsw_av(imrt) = mrtinsw_av(imrt) / REAL( average_count_3d, KIND = wp )
ENDDO
ENDIF
CASE ( 'rtm_mrt_lw' )
IF ( ALLOCATED( mrtinlw_av ) ) THEN
DO imrt = 1, nmrtbl
mrtinlw_av(imrt) = mrtinlw_av(imrt) / REAL( average_count_3d, KIND = wp )
ENDDO
ENDIF
CASE ( 'rtm_mrt' )
IF ( ALLOCATED( mrt_av ) ) THEN
DO imrt = 1, nmrtbl
mrt_av(imrt) = mrt_av(imrt) / REAL( average_count_3d, KIND = wp )
ENDDO
ENDIF
END SELECT
ENDIF
END SUBROUTINE radiation_3d_data_averaging
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Subroutine defining appropriate grid for netcdf variables.
!> It is called out from subroutine netcdf.
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_define_netcdf_grid( variable, found, grid_x, grid_y, grid_z )
IMPLICIT NONE
CHARACTER(LEN=*), INTENT(IN) :: variable !<
CHARACTER(LEN=*), INTENT(OUT) :: grid_x !<
CHARACTER(LEN=*), INTENT(OUT) :: grid_y !<
CHARACTER(LEN=*), INTENT(OUT) :: grid_z !<
CHARACTER(LEN=varnamelength) :: var !<
LOGICAL, INTENT(OUT) :: found !<
found = .TRUE.
!
!-- Check for the grid
var = TRIM( variable )
!
!-- RTM directional variables
IF ( var(1:12) == 'rtm_rad_net_' .OR. var(1:13) == 'rtm_rad_insw_' .OR. &
var(1:13) == 'rtm_rad_inlw_' .OR. var(1:16) == 'rtm_rad_inswdir_' .OR. &
var(1:16) == 'rtm_rad_inswdif_' .OR. var(1:16) == 'rtm_rad_inswref_' .OR. &
var(1:16) == 'rtm_rad_inlwdif_' .OR. var(1:16) == 'rtm_rad_inlwref_' .OR. &
var(1:14) == 'rtm_rad_outsw_' .OR. var(1:14) == 'rtm_rad_outlw_' .OR. &
var(1:14) == 'rtm_rad_ressw_' .OR. var(1:14) == 'rtm_rad_reslw_' .OR. &
var == 'rtm_rad_pc_inlw' .OR. var == 'rtm_rad_pc_insw' .OR. &
var == 'rtm_rad_pc_inswdir' .OR. var == 'rtm_rad_pc_inswdif' .OR. &
var == 'rtm_rad_pc_inswref' .OR. var(1:7) == 'rtm_svf' .OR. &
var(1:7) == 'rtm_dif' .OR. var(1:9) == 'rtm_skyvf' .OR. &
var(1:10) == 'rtm_skyvft' .OR. var(1:12) == 'rtm_surfalb_' .OR. &
var(1:13) == 'rtm_surfemis_' .OR. var == 'rtm_mrt' .OR. &
var == 'rtm_mrt_sw' .OR. var == 'rtm_mrt_lw' ) THEN
found = .TRUE.
grid_x = 'x'
grid_y = 'y'
grid_z = 'zu'
ELSE
SELECT CASE ( TRIM( var ) )
CASE ( 'rad_lw_cs_hr', 'rad_lw_hr', 'rad_sw_cs_hr', 'rad_sw_hr', 'rad_lw_cs_hr_xy', &
'rad_lw_hr_xy', 'rad_sw_cs_hr_xy', 'rad_sw_hr_xy', 'rad_lw_cs_hr_xz', &
'rad_lw_hr_xz', 'rad_sw_cs_hr_xz', 'rad_sw_hr_xz', 'rad_lw_cs_hr_yz', &
'rad_lw_hr_yz', 'rad_sw_cs_hr_yz', 'rad_sw_hr_yz' )
grid_x = 'x'
grid_y = 'y'
grid_z = 'zu'
CASE ( 'rad_lw_in', 'rad_lw_out', 'rad_sw_in', 'rad_sw_out', 'rad_lw_in_xy', &
'rad_lw_out_xy', 'rad_sw_in_xy','rad_sw_out_xy','rad_lw_in_xz','rad_lw_out_xz', &
'rad_sw_in_xz','rad_sw_out_xz', 'rad_lw_in_yz', 'rad_lw_out_yz', 'rad_sw_in_yz', &
'rad_sw_out_yz' )
grid_x = 'x'
grid_y = 'y'
grid_z = 'zw'
CASE DEFAULT
found = .FALSE.
grid_x = 'none'
grid_y = 'none'
grid_z = 'none'
END SELECT
ENDIF
END SUBROUTINE radiation_define_netcdf_grid
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Subroutine defining 2D output variables
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_data_output_2d( av, variable, found, grid, mode, local_pf, two_d, nzb_do, &
nzt_do, fill_value )
USE indices
USE kinds
IMPLICIT NONE
CHARACTER(LEN=*) :: grid !<
CHARACTER(LEN=*) :: mode !<
CHARACTER(LEN=*) :: variable !<
INTEGER(iwp) :: av !<
INTEGER(iwp) :: i !<
INTEGER(iwp) :: j !<
INTEGER(iwp) :: k !<
INTEGER(iwp) :: m !< index of surface element at grid point (j,i)
INTEGER(iwp) :: nzb_do !<
INTEGER(iwp) :: nzt_do !<
LOGICAL :: found !<
LOGICAL :: two_d !< flag parameter that indicates 2D variables (horizontal cross sections)
REAL(wp) :: fill_value !< value for the _FillValue attribute
REAL(wp), DIMENSION(nxl:nxr,nys:nyn,nzb_do:nzt_do) :: local_pf !<
found = .TRUE.
SELECT CASE ( TRIM( variable ) )
CASE ( 'rad_net*_xy' ) ! 2d-array
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Obtain rad_net from its respective surface type
!-- Only upward faced horizontal outputs are considered here
!-- Natural-type surfaces
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_lsm_h(0)%rad_net(m)
ENDDO
!
!-- Urban-type surfaces
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_usm_h(0)%rad_net(m)
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_net_av ) ) THEN
ALLOCATE( rad_net_av(nysg:nyng,nxlg:nxrg) )
rad_net_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
local_pf(i,j,nzb+1) = rad_net_av(j,i)
ENDDO
ENDDO
ENDIF
two_d = .TRUE.
grid = 'zu1'
CASE ( 'rad_lw_in*_xy' ) ! 2d-array
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Obtain rad_net from its respective surface type
!-- Natural-type surfaces
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_lsm_h(0)%rad_lw_in(m)
ENDDO
!
!-- Urban-type surfaces
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_usm_h(0)%rad_lw_in(m)
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_in_xy_av ) ) THEN
ALLOCATE( rad_lw_in_xy_av(nysg:nyng,nxlg:nxrg) )
rad_lw_in_xy_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
local_pf(i,j,nzb+1) = rad_lw_in_xy_av(j,i)
ENDDO
ENDDO
ENDIF
two_d = .TRUE.
grid = 'zu1'
CASE ( 'rad_lw_out*_xy' ) ! 2d-array
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Obtain rad_net from its respective surface type
!-- Natural-type surfaces
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_lsm_h(0)%rad_lw_out(m)
ENDDO
!
!-- Urban-type surfaces
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_usm_h(0)%rad_lw_out(m)
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_out_xy_av ) ) THEN
ALLOCATE( rad_lw_out_xy_av(nysg:nyng,nxlg:nxrg) )
rad_lw_out_xy_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
local_pf(i,j,nzb+1) = rad_lw_out_xy_av(j,i)
ENDDO
ENDDO
ENDIF
two_d = .TRUE.
grid = 'zu1'
CASE ( 'rad_sw_in*_xy' ) ! 2d-array
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Obtain rad_net from its respective surface type
!-- Natural-type surfaces
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_lsm_h(0)%rad_sw_in(m)
ENDDO
!
!-- Urban-type surfaces
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_usm_h(0)%rad_sw_in(m)
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_in_xy_av ) ) THEN
ALLOCATE( rad_sw_in_xy_av(nysg:nyng,nxlg:nxrg) )
rad_sw_in_xy_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
local_pf(i,j,nzb+1) = rad_sw_in_xy_av(j,i)
ENDDO
ENDDO
ENDIF
two_d = .TRUE.
grid = 'zu1'
CASE ( 'rad_sw_out*_xy' ) ! 2d-array
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
!
!-- Obtain rad_net from its respective surface type
!-- Natural-type surfaces
DO m = surf_lsm_h(0)%start_index(j,i), surf_lsm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_lsm_h(0)%rad_sw_out(m)
ENDDO
!
!-- Urban-type surfaces
DO m = surf_usm_h(0)%start_index(j,i), surf_usm_h(0)%end_index(j,i)
local_pf(i,j,nzb+1) = surf_usm_h(0)%rad_sw_out(m)
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_out_xy_av ) ) THEN
ALLOCATE( rad_sw_out_xy_av(nysg:nyng,nxlg:nxrg) )
rad_sw_out_xy_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
local_pf(i,j,nzb+1) = rad_sw_out_xy_av(j,i)
ENDDO
ENDDO
ENDIF
two_d = .TRUE.
grid = 'zu1'
CASE ( 'rad_lw_in_xy', 'rad_lw_in_xz', 'rad_lw_in_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_in(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) THEN
ALLOCATE( rad_lw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_in_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_in_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zu'
CASE ( 'rad_lw_out_xy', 'rad_lw_out_xz', 'rad_lw_out_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_out(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) THEN
ALLOCATE( rad_lw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_out_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_out_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zu'
CASE ( 'rad_lw_cs_hr_xy', 'rad_lw_cs_hr_xz', 'rad_lw_cs_hr_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_cs_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_cs_hr_av ) ) THEN
ALLOCATE( rad_lw_cs_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_cs_hr_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_cs_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zw'
CASE ( 'rad_lw_hr_xy', 'rad_lw_hr_xz', 'rad_lw_hr_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_hr_av ) ) THEN
ALLOCATE( rad_lw_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_hr_av= REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zw'
CASE ( 'rad_sw_in_xy', 'rad_sw_in_xz', 'rad_sw_in_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_in(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) THEN
ALLOCATE( rad_sw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_in_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_sw_in_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zu'
CASE ( 'rad_sw_out_xy', 'rad_sw_out_xz', 'rad_sw_out_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_out(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) THEN
ALLOCATE( rad_sw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_out_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb, nzt+1
local_pf(i,j,k) = rad_sw_out_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zu'
CASE ( 'rad_sw_cs_hr_xy', 'rad_sw_cs_hr_xz', 'rad_sw_cs_hr_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_cs_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_cs_hr_av ) ) THEN
ALLOCATE( rad_sw_cs_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_cs_hr_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_sw_cs_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zw'
CASE ( 'rad_sw_hr_xy', 'rad_sw_hr_xz', 'rad_sw_hr_yz' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_hr_av ) ) THEN
ALLOCATE( rad_sw_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_hr_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_sw_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
IF ( mode == 'xy' ) grid = 'zw'
CASE DEFAULT
found = .FALSE.
grid = 'none'
END SELECT
END SUBROUTINE radiation_data_output_2d
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Subroutine defining 3D output variables
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_data_output_3d( av, variable, found, local_pf, fill_value, nzb_do, nzt_do )
USE indices
USE kinds
IMPLICIT NONE
CHARACTER(LEN=*) :: variable !<
CHARACTER(LEN=varnamelength) :: var, surfid !<
INTEGER(iwp) :: av !<
INTEGER(iwp) :: i, j, k, l !<
INTEGER(iwp) :: nzb_do !<
INTEGER(iwp) :: nzt_do !<
INTEGER(iwp) :: ids,idsint,isurf,isvf,isurfs,isurflt,ipcgb !<
INTEGER(iwp) :: is, js, ks, istat !<
LOGICAL :: found !<
REAL(wp) :: fill_value !< value for the _FillValue attribute
REAL(wp), DIMENSION(nxl:nxr,nys:nyn,nzb_do:nzt_do) :: local_pf !<
found = .TRUE.
var = TRIM( variable )
!
!-- Check if variable belongs to radiation related variables (starts with rad or rtm)
IF ( LEN( var ) < 3_iwp ) THEN
found = .FALSE.
RETURN
ENDIF
IF ( var(1:3) /= 'rad' .AND. var(1:3) /= 'rtm' ) THEN
found = .FALSE.
RETURN
ENDIF
ids = -1
DO i = 0, nd-1
k = LEN( TRIM( var ) )
j = LEN( TRIM( dirname(i) ) )
IF ( k - j + 1 >= 1_iwp ) THEN
IF ( TRIM( var(k-j+1:k) ) == TRIM( dirname(i) ) ) THEN
ids = i
idsint = dirint(ids)
var = var(:k-j)
EXIT
ENDIF
ENDIF
ENDDO
IF ( ids == -1 ) THEN
var = TRIM( variable )
ENDIF
IF ( (var(1:8) == 'rtm_svf_' .OR. var(1:8) == 'rtm_dif_') .AND. LEN( TRIM( var ) ) >= 13 ) &
THEN
!
!-- svf values to particular surface
surfid = var(9:)
i = INDEX( surfid, '_' )
j = INDEX( surfid(i+1:), '_' )
READ( surfid(1:i-1), *, IOSTAT = istat ) is
IF ( istat == 0 ) THEN
READ( surfid(i+1:i+j-1), *, IOSTAT = istat ) js
ENDIF
IF ( istat == 0 ) THEN
READ( surfid(i+j+1:), *, IOSTAT = istat ) ks
ENDIF
IF ( istat == 0 ) THEN
var = var(1:7)
ENDIF
ENDIF
local_pf = fill_value
SELECT CASE ( TRIM( var ) )
!
!-- Block of large scale radiation model (e.g. RRTMG) output variables
CASE ( 'rad_sw_in' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_in(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) THEN
ALLOCATE( rad_sw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_in_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_sw_in_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_out' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_out(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) THEN
ALLOCATE( rad_sw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_out_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_sw_out_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_cs_hr' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_cs_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_cs_hr_av ) ) THEN
ALLOCATE( rad_sw_cs_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_cs_hr_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_sw_cs_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_sw_hr' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_sw_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_sw_hr_av ) ) THEN
ALLOCATE( rad_sw_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_sw_hr_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_sw_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_in' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_in(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) THEN
ALLOCATE( rad_lw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_in_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_in_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_out' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_out(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) THEN
ALLOCATE( rad_lw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_out_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_out_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_cs_hr' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_cs_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_cs_hr_av ) ) THEN
ALLOCATE( rad_lw_cs_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_cs_hr_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_cs_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rad_lw_hr' )
IF ( av == 0 ) THEN
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = MERGE( rad_lw_hr(k,j,i), fill_value, &
BTEST( topo_flags(k,j,i), 0 ) )
ENDDO
ENDDO
ENDDO
ELSE
IF ( .NOT. ALLOCATED( rad_lw_hr_av ) ) THEN
ALLOCATE( rad_lw_hr_av(nzb+1:nzt+1,nysg:nyng,nxlg:nxrg) )
rad_lw_hr_av = REAL( fill_value, KIND = wp )
ENDIF
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_do, nzt_do
local_pf(i,j,k) = rad_lw_hr_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
CASE ( 'rtm_rad_net' )
!
!-- Array of complete radiation balance
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = &
surfinsw(isurf) - surfoutsw(isurf) + surfinlw(isurf) - surfoutlw(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfradnet_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_insw' )
!
!-- Array of sw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinsw(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinsw_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_inlw' )
!
!-- Array of lw radiation falling to surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinlw(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinlw_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_inswdir' )
!
!-- Array of direct sw radiation falling to surface from sun
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinswdir(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinswdir_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_inswdif' )
!
!-- Array of difusion sw radiation falling to surface from sky and borders of the domain
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinswdif(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinswdif_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_inswref' )
!
!-- Array of sw radiation falling to surface from reflections
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = &
surfinsw(isurf) - surfinswdir(isurf) - surfinswdif(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinswref_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_inlwdif' )
!
!-- Array of difusion lw radiation falling to surface from sky and borders of the domain
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinlwdif(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinlwdif_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_inlwref' )
!
!-- Array of lw radiation falling to surface from reflections
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinlw(isurf) - &
surfinlwdif(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinlwref_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_outsw' )
!
!-- Array of sw radiation emitted from surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfoutsw(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfoutsw_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_outlw' )
!
!-- Array of lw radiation emitted from surface after i-th reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfoutlw(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfoutlw_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_ressw' )
!
!-- Average of array of residua of sw radiation absorbed in surface after last reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfins(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfins_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_reslw' )
!
!-- Average of array of residua of lw radiation absorbed in surface after last reflection
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
IF ( av == 0 ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinl(isurf)
ELSE
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = surfinl_av(isurf)
ENDIF
ENDIF
ENDDO
CASE ( 'rtm_rad_pc_inlw' )
!
!-- Array of lw radiation absorbed by plant canopy
DO ipcgb = 1, npcbl
IF ( av == 0 ) THEN
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinlw(ipcgb)
ELSE
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinlw_av(ipcgb)
ENDIF
ENDDO
CASE ( 'rtm_rad_pc_insw' )
!
!-- Array of sw radiation absorbed by plant canopy
DO ipcgb = 1, npcbl
IF ( av == 0 ) THEN
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinsw(ipcgb)
ELSE
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinsw_av(ipcgb)
ENDIF
ENDDO
CASE ( 'rtm_rad_pc_inswdir' )
!
!-- Array of direct sw radiation absorbed by plant canopy
DO ipcgb = 1, npcbl
IF ( av == 0 ) THEN
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinswdir(ipcgb)
ELSE
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinswdir_av(ipcgb)
ENDIF
ENDDO
CASE ( 'rtm_rad_pc_inswdif' )
!
!-- Array of diffuse sw radiation absorbed by plant canopy
DO ipcgb = 1, npcbl
IF ( av == 0 ) THEN
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinswdif(ipcgb)
ELSE
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinswdif_av(ipcgb)
ENDIF
ENDDO
CASE ( 'rtm_rad_pc_inswref' )
!
!-- Array of reflected sw radiation absorbed by plant canopy
DO ipcgb = 1, npcbl
IF ( av == 0 ) THEN
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = &
pcbinsw(ipcgb) - pcbinswdir(ipcgb) - pcbinswdif(ipcgb)
ELSE
local_pf(pcbl(ix,ipcgb),pcbl(iy,ipcgb),pcbl(iz,ipcgb)) = pcbinswref_av(ipcgb)
ENDIF
ENDDO
CASE ( 'rtm_mrt_sw' )
local_pf = REAL( fill_value, KIND = wp )
IF ( av == 0 ) THEN
DO l = 1, nmrtbl
local_pf(mrtbl(ix,l),mrtbl(iy,l),mrtbl(iz,l)) = mrtinsw(l)
ENDDO
ELSE
IF ( ALLOCATED( mrtinsw_av ) ) THEN
DO l = 1, nmrtbl
local_pf(mrtbl(ix,l),mrtbl(iy,l),mrtbl(iz,l)) = mrtinsw_av(l)
ENDDO
ENDIF
ENDIF
CASE ( 'rtm_mrt_lw' )
local_pf = REAL( fill_value, KIND = wp )
IF ( av == 0 ) THEN
DO l = 1, nmrtbl
local_pf(mrtbl(ix,l),mrtbl(iy,l),mrtbl(iz,l)) = mrtinlw(l)
ENDDO
ELSE
IF ( ALLOCATED( mrtinlw_av ) ) THEN
DO l = 1, nmrtbl
local_pf(mrtbl(ix,l),mrtbl(iy,l),mrtbl(iz,l)) = mrtinlw_av(l)
ENDDO
ENDIF
ENDIF
CASE ( 'rtm_mrt' )
local_pf = REAL( fill_value, KIND = wp )
IF ( av == 0 ) THEN
DO l = 1, nmrtbl
local_pf(mrtbl(ix,l),mrtbl(iy,l),mrtbl(iz,l)) = mrt(l)
ENDDO
ELSE
IF ( ALLOCATED( mrt_av ) ) THEN
DO l = 1, nmrtbl
local_pf(mrtbl(ix,l),mrtbl(iy,l),mrtbl(iz,l)) = mrt_av(l)
ENDDO
ENDIF
ENDIF
!
!-- Block of RTM output variables
!-- Variables are intended mainly for debugging and detailed analysis purposes
CASE ( 'rtm_skyvf' )
!
!-- Sky view factor
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = skyvf(isurf)
ENDIF
ENDDO
CASE ( 'rtm_skyvft' )
!
!-- Sky view factor
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = skyvft(isurf)
ENDIF
ENDDO
CASE ( 'rtm_svf', 'rtm_dif' )
!
!-- Shape view factors or iradiance factors to selected surface
IF ( TRIM( var ) == 'rtm_svf' ) THEN
k = 1
ELSE
k = 2
ENDIF
DO isvf = 1, nsvfl
isurflt = svfsurf(1, isvf)
isurfs = svfsurf(2, isvf)
IF ( surf(ix,isurfs) == is .AND. surf(iy,isurfs) == js .AND. surf(iz,isurfs) == ks &
.AND. surfl(id,isurflt) == idsint ) THEN
!
!-- Correct source surface
local_pf(surfl(ix,isurflt),surfl(iy,isurflt),surfl(iz,isurflt)) = svf(k,isvf)
ENDIF
ENDDO
CASE ( 'rtm_surfalb' )
!
!-- Surface albedo
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = albedo_surf(isurf)
ENDIF
ENDDO
CASE ( 'rtm_surfemis' )
!
!-- Surface emissivity, weighted average
DO isurf = 1, nsurfl
IF ( surfl(id,isurf) == idsint ) THEN
local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = emiss_surf(isurf)
ENDIF
ENDDO
CASE DEFAULT
found = .FALSE.
END SELECT
END SUBROUTINE radiation_data_output_3d
!--------------------------------------------------------------------------------------------------!
!
! Description:
! ------------
!> Subroutine defining masked data output
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_data_output_mask( av, variable, found, local_pf, mid )
USE control_parameters
USE indices
USE kinds
IMPLICIT NONE
CHARACTER (LEN=*) :: variable !<
CHARACTER(LEN=5) :: grid !< flag to distinquish between staggered grids
INTEGER(iwp) :: av !<
INTEGER(iwp) :: i !<
INTEGER(iwp) :: j !<
INTEGER(iwp) :: k !<
INTEGER(iwp) :: mid !< masked output running index
INTEGER(iwp) :: topo_top_index !< k index of highest horizontal surface
LOGICAL :: found !< true if output array was found
LOGICAL :: resorted !< true if array is resorted
REAL(wp), DIMENSION(mask_size_l(mid,1),mask_size_l(mid,2),mask_size_l(mid,3)) :: local_pf !<
REAL(wp), DIMENSION(:,:,:), POINTER :: to_be_resorted !< points to array which needs to be resorted for output
found = .TRUE.
grid = 's'
resorted = .FALSE.
SELECT CASE ( TRIM( variable ) )
CASE ( 'rad_lw_in' )
IF ( av == 0 ) THEN
to_be_resorted => rad_lw_in
ELSE
to_be_resorted => rad_lw_in_av
ENDIF
CASE ( 'rad_lw_out' )
IF ( av == 0 ) THEN
to_be_resorted => rad_lw_out
ELSE
to_be_resorted => rad_lw_out_av
ENDIF
CASE ( 'rad_lw_cs_hr' )
IF ( av == 0 ) THEN
to_be_resorted => rad_lw_cs_hr
ELSE
to_be_resorted => rad_lw_cs_hr_av
ENDIF
CASE ( 'rad_lw_hr' )
IF ( av == 0 ) THEN
to_be_resorted => rad_lw_hr
ELSE
to_be_resorted => rad_lw_hr_av
ENDIF
CASE ( 'rad_sw_in' )
IF ( av == 0 ) THEN
to_be_resorted => rad_sw_in
ELSE
to_be_resorted => rad_sw_in_av
ENDIF
CASE ( 'rad_sw_out' )
IF ( av == 0 ) THEN
to_be_resorted => rad_sw_out
ELSE
to_be_resorted => rad_sw_out_av
ENDIF
CASE ( 'rad_sw_cs_hr' )
IF ( av == 0 ) THEN
to_be_resorted => rad_sw_cs_hr
ELSE
to_be_resorted => rad_sw_cs_hr_av
ENDIF
CASE ( 'rad_sw_hr' )
IF ( av == 0 ) THEN
to_be_resorted => rad_sw_hr
ELSE
to_be_resorted => rad_sw_hr_av
ENDIF
CASE DEFAULT
found = .FALSE.
END SELECT
!
!-- Resort the array to be output, if not done above
IF ( found .AND. .NOT. resorted ) THEN
IF ( .NOT. mask_surface(mid) ) THEN
!
!-- Default masked output
DO i = 1, mask_size_l(mid,1)
DO j = 1, mask_size_l(mid,2)
DO k = 1, mask_size_l(mid,3)
local_pf(i,j,k) = to_be_resorted(mask_k(mid,k), mask_j(mid,j), mask_i(mid,i))
ENDDO
ENDDO
ENDDO
ELSE
!
!-- Terrain-following masked output
DO i = 1, mask_size_l(mid,1)
DO j = 1, mask_size_l(mid,2)
!
!-- Get k index of highest horizontal surface
topo_top_index = topo_top_ind(mask_j(mid,j), mask_i(mid,i), 0 )
!
!-- Save output array
DO k = 1, mask_size_l(mid,3)
local_pf(i,j,k) = to_be_resorted( MIN( topo_top_index+mask_k(mid,k), nzt+1 ), &
mask_j(mid,j), mask_i(mid,i) )
ENDDO
ENDDO
ENDDO
ENDIF
ENDIF
END SUBROUTINE radiation_data_output_mask
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Subroutine writes local (subdomain) restart data
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_wrd_local
IMPLICIT NONE
REAL(wp), DIMENSION(nysg:nyng,nxlg:nxrg) :: tmp !< temporary array for reading from file
IF ( TRIM( restart_data_format_output ) == 'fortran_binary' ) THEN
IF ( ALLOCATED( rad_net_av ) ) THEN
CALL wrd_write_string( 'rad_net_av' )
WRITE( 14 ) rad_net_av
ENDIF
IF ( ALLOCATED( rad_lw_in_xy_av ) ) THEN
CALL wrd_write_string( 'rad_lw_in_xy_av' )
WRITE( 14 ) rad_lw_in_xy_av
ENDIF
IF ( ALLOCATED( rad_lw_out_xy_av ) ) THEN
CALL wrd_write_string( 'rad_lw_out_xy_av' )
WRITE( 14 ) rad_lw_out_xy_av
ENDIF
IF ( ALLOCATED( rad_sw_in_xy_av ) ) THEN
CALL wrd_write_string( 'rad_sw_in_xy_av' )
WRITE( 14 ) rad_sw_in_xy_av
ENDIF
IF ( ALLOCATED( rad_sw_out_xy_av ) ) THEN
CALL wrd_write_string( 'rad_sw_out_xy_av' )
WRITE( 14 ) rad_sw_out_xy_av
ENDIF
IF ( ALLOCATED( rad_lw_in ) ) THEN
CALL wrd_write_string( 'rad_lw_in' )
WRITE( 14 ) rad_lw_in
ENDIF
IF ( ALLOCATED( rad_lw_in_av ) ) THEN
CALL wrd_write_string( 'rad_lw_in_av' )
WRITE( 14 ) rad_lw_in_av
ENDIF
IF ( ALLOCATED( rad_lw_out ) ) THEN
CALL wrd_write_string( 'rad_lw_out' )
WRITE( 14 ) rad_lw_out
ENDIF
IF ( ALLOCATED( rad_lw_out_av) ) THEN
CALL wrd_write_string( 'rad_lw_out_av' )
WRITE( 14 ) rad_lw_out_av
ENDIF
IF ( ALLOCATED( rad_lw_cs_hr) ) THEN
CALL wrd_write_string( 'rad_lw_cs_hr' )
WRITE( 14 ) rad_lw_cs_hr
ENDIF
IF ( ALLOCATED( rad_lw_cs_hr_av) ) THEN
CALL wrd_write_string( 'rad_lw_cs_hr_av' )
WRITE( 14 ) rad_lw_cs_hr_av
ENDIF
IF ( ALLOCATED( rad_lw_hr) ) THEN
CALL wrd_write_string( 'rad_lw_hr' )
WRITE( 14 ) rad_lw_hr
ENDIF
IF ( ALLOCATED( rad_lw_hr_av) ) THEN
CALL wrd_write_string( 'rad_lw_hr_av' )
WRITE( 14 ) rad_lw_hr_av
ENDIF
IF ( ALLOCATED( rad_sw_in) ) THEN
CALL wrd_write_string( 'rad_sw_in' )
WRITE( 14 ) rad_sw_in
ENDIF
IF ( ALLOCATED( rad_sw_in_av) ) THEN
CALL wrd_write_string( 'rad_sw_in_av' )
WRITE( 14 ) rad_sw_in_av
ENDIF
IF ( ALLOCATED( rad_sw_out) ) THEN
CALL wrd_write_string( 'rad_sw_out' )
WRITE( 14 ) rad_sw_out
ENDIF
IF ( ALLOCATED( rad_sw_out_av) ) THEN
CALL wrd_write_string( 'rad_sw_out_av' )
WRITE( 14 ) rad_sw_out_av
ENDIF
IF ( ALLOCATED( rad_sw_cs_hr) ) THEN
CALL wrd_write_string( 'rad_sw_cs_hr' )
WRITE( 14 ) rad_sw_cs_hr
ENDIF
IF ( ALLOCATED( rad_sw_cs_hr_av) ) THEN
CALL wrd_write_string( 'rad_sw_cs_hr_av' )
WRITE( 14 ) rad_sw_cs_hr_av
ENDIF
IF ( ALLOCATED( rad_sw_hr) ) THEN
CALL wrd_write_string( 'rad_sw_hr' )
WRITE( 14 ) rad_sw_hr
ENDIF
IF ( ALLOCATED( rad_sw_hr_av) ) THEN
CALL wrd_write_string( 'rad_sw_hr_av' )
WRITE( 14 ) rad_sw_hr_av
ENDIF
ELSEIF ( restart_data_format_output(1:3) == 'mpi' ) THEN
IF ( ALLOCATED( rad_net_av ) ) CALL wrd_mpi_io( 'rad_net_av', rad_net_av )
IF ( ALLOCATED( rad_lw_in_xy_av ) ) CALL wrd_mpi_io( 'rad_lw_in_xy_av', rad_lw_in_xy_av )
IF ( ALLOCATED( rad_lw_out_xy_av ) ) CALL wrd_mpi_io( 'rad_lw_out_xy_av', rad_lw_out_xy_av )
IF ( ALLOCATED( rad_sw_in_xy_av ) ) CALL wrd_mpi_io( 'rad_sw_in_xy_av', rad_sw_in_xy_av )
IF ( ALLOCATED( rad_sw_out_xy_av ) ) CALL wrd_mpi_io( 'rad_sw_out_xy_av', rad_sw_out_xy_av )
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) &
THEN
IF ( ALLOCATED( rad_lw_in ) ) THEN
tmp = rad_lw_in(0,:,:)
CALL wrd_mpi_io( 'rad_lw_in', tmp )
ENDIF
IF ( ALLOCATED( rad_lw_in_av ) ) THEN
tmp = rad_lw_in_av(0,:,:)
CALL wrd_mpi_io( 'rad_lw_in_av', tmp )
ENDIF
IF ( ALLOCATED( rad_lw_out ) ) THEN
tmp = rad_lw_out(0,:,:)
CALL wrd_mpi_io( 'rad_lw_out', tmp )
ENDIF
IF ( ALLOCATED( rad_lw_out_av ) ) THEN
tmp = rad_lw_out_av(0,:,:)
CALL wrd_mpi_io( 'rad_lw_out_av', tmp )
ENDIF
ELSE
IF ( ALLOCATED( rad_lw_in ) ) CALL wrd_mpi_io( 'rad_lw_in', rad_lw_in )
IF ( ALLOCATED( rad_lw_in_av ) ) CALL wrd_mpi_io( 'rad_lw_in_av', rad_lw_in_av )
IF ( ALLOCATED( rad_lw_out ) ) CALL wrd_mpi_io( 'rad_lw_out', rad_lw_out )
IF ( ALLOCATED( rad_lw_out_av) ) CALL wrd_mpi_io( 'rad_lw_out_av', rad_lw_out_av )
ENDIF
IF ( ALLOCATED( rad_lw_cs_hr) ) CALL wrd_mpi_io( 'rad_lw_cs_hr', rad_lw_cs_hr )
IF ( ALLOCATED( rad_lw_cs_hr_av) ) CALL wrd_mpi_io( 'rad_lw_cs_hr_av', rad_lw_cs_hr_av )
IF ( ALLOCATED( rad_lw_hr) ) CALL wrd_mpi_io( 'rad_lw_hr', rad_lw_hr )
IF ( ALLOCATED( rad_lw_hr_av) ) CALL wrd_mpi_io( 'rad_lw_hr_av', rad_lw_hr_av )
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) &
THEN
IF ( ALLOCATED( rad_sw_in ) ) THEN
tmp = rad_sw_in(0,:,:)
CALL wrd_mpi_io( 'rad_sw_in', tmp )
ENDIF
IF ( ALLOCATED( rad_sw_in_av ) ) THEN
tmp = rad_sw_in_av(0,:,:)
CALL wrd_mpi_io( 'rad_sw_in_av', tmp )
ENDIF
IF ( ALLOCATED( rad_sw_out ) ) THEN
tmp = rad_sw_out(0,:,:)
CALL wrd_mpi_io( 'rad_sw_out', tmp )
ENDIF
IF ( ALLOCATED( rad_sw_out_av ) ) THEN
tmp = rad_sw_out_av(0,:,:)
CALL wrd_mpi_io( 'rad_sw_out_av', tmp )
ENDIF
ELSE
IF ( ALLOCATED( rad_sw_in) ) CALL wrd_mpi_io( 'rad_sw_in', rad_sw_in )
IF ( ALLOCATED( rad_sw_in_av) ) CALL wrd_mpi_io( 'rad_sw_in_av', rad_sw_in_av )
IF ( ALLOCATED( rad_sw_out) ) CALL wrd_mpi_io( 'rad_sw_out', rad_sw_out )
IF ( ALLOCATED( rad_sw_out_av) ) CALL wrd_mpi_io( 'rad_sw_out_av', rad_sw_out_av )
ENDIF
IF ( ALLOCATED( rad_sw_cs_hr) ) CALL wrd_mpi_io( 'rad_sw_cs_hr', rad_sw_cs_hr )
IF ( ALLOCATED( rad_sw_cs_hr_av) ) CALL wrd_mpi_io( 'rad_sw_cs_hr_av', rad_sw_cs_hr_av )
IF ( ALLOCATED( rad_sw_hr) ) CALL wrd_mpi_io( 'rad_sw_hr', rad_sw_hr )
IF ( ALLOCATED( rad_sw_hr_av) ) CALL wrd_mpi_io( 'rad_sw_hr_av', rad_sw_hr_av )
ENDIF
END SUBROUTINE radiation_wrd_local
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Read module-specific local restart data arrays (Fortran binary format).
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_rrd_local_ftn( k, nxlf, nxlc, nxl_on_file, nxrf, nxrc, nxr_on_file, nynf, &
nync, nyn_on_file, nysf, nysc, nys_on_file, tmp_2d, tmp_3d, &
found )
USE control_parameters
USE indices
USE kinds
USE pegrid
IMPLICIT NONE
INTEGER(iwp) :: k !<
INTEGER(iwp) :: nxlc !<
INTEGER(iwp) :: nxlf !<
INTEGER(iwp) :: nxl_on_file !<
INTEGER(iwp) :: nxrc !<
INTEGER(iwp) :: nxrf !<
INTEGER(iwp) :: nxr_on_file !<
INTEGER(iwp) :: nync !<
INTEGER(iwp) :: nynf !<
INTEGER(iwp) :: nyn_on_file !<
INTEGER(iwp) :: nysc !<
INTEGER(iwp) :: nysf !<
INTEGER(iwp) :: nys_on_file !<
LOGICAL, INTENT(OUT) :: found !<
REAL(wp), DIMENSION(nys_on_file-nbgp:nyn_on_file+nbgp,nxl_on_file-nbgp:nxr_on_file+nbgp) :: tmp_2d !<
REAL(wp), DIMENSION(nzb:nzt+1,nys_on_file-nbgp:nyn_on_file+nbgp,nxl_on_file-nbgp:nxr_on_file+nbgp) :: tmp_3d !<
REAL(wp), DIMENSION(0:0,nys_on_file-nbgp:nyn_on_file+nbgp,nxl_on_file-nbgp:nxr_on_file+nbgp) :: tmp_3d2 !<
found = .TRUE.
SELECT CASE ( restart_string(1:length) )
CASE ( 'rad_net_av' )
IF ( .NOT. ALLOCATED( rad_net_av ) ) THEN
ALLOCATE( rad_net_av(nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_2d
rad_net_av(nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_2d(nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_lw_in_xy_av' )
IF ( .NOT. ALLOCATED( rad_lw_in_xy_av ) ) THEN
ALLOCATE( rad_lw_in_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_2d
rad_lw_in_xy_av(nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_2d(nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_lw_out_xy_av' )
IF ( .NOT. ALLOCATED( rad_lw_out_xy_av ) ) THEN
ALLOCATE( rad_lw_out_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_2d
rad_lw_out_xy_av(nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_2d(nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_sw_in_xy_av' )
IF ( .NOT. ALLOCATED( rad_sw_in_xy_av ) ) THEN
ALLOCATE( rad_sw_in_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_2d
rad_sw_in_xy_av(nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_2d(nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_sw_out_xy_av' )
IF ( .NOT. ALLOCATED( rad_sw_out_xy_av ) ) THEN
ALLOCATE( rad_sw_out_xy_av(nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_2d
rad_sw_out_xy_av(nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_2d(nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_lw_in' )
IF ( .NOT. ALLOCATED( rad_lw_in ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_lw_in(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_lw_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_lw_in(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_lw_in(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_lw_in_av' )
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_lw_in_av(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_lw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_lw_in_av(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_lw_in_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_lw_out' )
IF ( .NOT. ALLOCATED( rad_lw_out ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_lw_out(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_lw_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_lw_out(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_lw_out(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_lw_out_av' )
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_lw_out_av(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_lw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_lw_out_av(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_lw_out_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_lw_cs_hr' )
IF ( .NOT. ALLOCATED( rad_lw_cs_hr ) ) THEN
ALLOCATE( rad_lw_cs_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_lw_cs_hr(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_lw_cs_hr_av' )
IF ( .NOT. ALLOCATED( rad_lw_cs_hr_av ) ) THEN
ALLOCATE( rad_lw_cs_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_lw_cs_hr_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_lw_hr' )
IF ( .NOT. ALLOCATED( rad_lw_hr ) ) THEN
ALLOCATE( rad_lw_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_lw_hr(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_lw_hr_av' )
IF ( .NOT. ALLOCATED( rad_lw_hr_av ) ) THEN
ALLOCATE( rad_lw_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_lw_hr_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_sw_in' )
IF ( .NOT. ALLOCATED( rad_sw_in ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_sw_in(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_sw_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_sw_in(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_sw_in(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_sw_in_av' )
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_sw_in_av(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_sw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_sw_in_av(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_sw_in_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_sw_out' )
IF ( .NOT. ALLOCATED( rad_sw_out ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_sw_out(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_sw_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_sw_out(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_sw_out(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_sw_out_av' )
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
ALLOCATE( rad_sw_out_av(0:0,nysg:nyng,nxlg:nxrg) )
ELSE
ALLOCATE( rad_sw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
ENDIF
IF ( k == 1 ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
READ( 13 ) tmp_3d2
rad_sw_out_av(0:0,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d2(0:0,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ELSE
READ( 13 ) tmp_3d
rad_sw_out_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
ENDIF
ENDIF
CASE ( 'rad_sw_cs_hr' )
IF ( .NOT. ALLOCATED( rad_sw_cs_hr ) ) THEN
ALLOCATE( rad_sw_cs_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_sw_cs_hr(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_sw_cs_hr_av' )
IF ( .NOT. ALLOCATED( rad_sw_cs_hr_av ) ) THEN
ALLOCATE( rad_sw_cs_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_sw_cs_hr_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_sw_hr' )
IF ( .NOT. ALLOCATED( rad_sw_hr ) ) THEN
ALLOCATE( rad_sw_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_sw_hr(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE ( 'rad_sw_hr_av' )
IF ( .NOT. ALLOCATED( rad_sw_hr_av ) ) THEN
ALLOCATE( rad_sw_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
ENDIF
IF ( k == 1 ) READ( 13 ) tmp_3d
rad_lw_hr_av(:,nysc-nbgp:nync+nbgp,nxlc-nbgp:nxrc+nbgp) = &
tmp_3d(:,nysf-nbgp:nynf+nbgp,nxlf-nbgp:nxrf+nbgp)
CASE DEFAULT
found = .FALSE.
END SELECT
END SUBROUTINE radiation_rrd_local_ftn
!--------------------------------------------------------------------------------------------------!
! Description:
! ------------
!> Read module-specific local restart data arrays (MPI-IO).
!--------------------------------------------------------------------------------------------------!
SUBROUTINE radiation_rrd_local_mpi
USE control_parameters
USE indices
USE kinds
IMPLICIT NONE
LOGICAL :: array_found !<
REAL(wp), DIMENSION(nysg:nyng,nxlg:nxrg) :: tmp !< temporary array for reading from file
CALL rd_mpi_io_check_array( 'rad_net_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_net_av ) ) ALLOCATE( rad_net_av(nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_net_av', rad_net_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_in_xy_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_lw_in_xy_av ) ) ALLOCATE( rad_lw_in_xy_av(nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_in_xy_av', rad_lw_in_xy_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_out_xy_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_lw_out_xy_av ) ) ALLOCATE( rad_lw_out_xy_av(nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_out_xy_av', rad_lw_out_xy_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_in_xy_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_sw_in_xy_av ) ) ALLOCATE( rad_sw_in_xy_av(nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_in_xy_av', rad_sw_in_xy_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_out_xy_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_sw_out_xy_av ) ) ALLOCATE( rad_sw_out_xy_av(nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_out_xy_av', rad_sw_out_xy_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_in' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_lw_in ) ) ALLOCATE( rad_lw_in(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_in', tmp )
rad_lw_in(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_lw_in ) ) ALLOCATE( rad_lw_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_in', rad_lw_in )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_in_av' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) ALLOCATE( rad_lw_in_av(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_in_av', tmp )
rad_lw_in_av(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_lw_in_av ) ) &
ALLOCATE( rad_lw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_in_av', rad_lw_in_av )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_out' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_lw_out ) ) ALLOCATE( rad_lw_out(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_out', tmp )
rad_lw_out(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_lw_out ) ) ALLOCATE( rad_lw_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_out', rad_lw_out )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_out_av' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) ALLOCATE( rad_lw_out_av(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_out_av', tmp )
rad_lw_out_av(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_lw_out_av ) ) &
ALLOCATE( rad_lw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_out_av', rad_lw_out_av )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_cs_hr' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_lw_cs_hr ) ) &
ALLOCATE( rad_lw_cs_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_cs_hr', rad_lw_cs_hr )
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_cs_hr_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_lw_cs_hr_av ) ) &
ALLOCATE( rad_lw_cs_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_cs_hr_av', rad_lw_cs_hr_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_hr' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_lw_hr ) ) ALLOCATE( rad_lw_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_hr', rad_lw_hr )
ENDIF
CALL rd_mpi_io_check_array( 'rad_lw_hr_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_lw_hr_av ) ) &
ALLOCATE( rad_lw_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_lw_hr_av', rad_lw_hr_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_in' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_sw_in ) ) ALLOCATE( rad_sw_in(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_in', tmp )
rad_sw_in(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_sw_in ) ) ALLOCATE( rad_sw_in(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_in', rad_sw_in )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_in_av' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) ALLOCATE( rad_sw_in_av(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_in_av', tmp )
rad_sw_in_av(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_sw_in_av ) ) &
ALLOCATE( rad_sw_in_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_in_av', rad_sw_in_av )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_out' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_sw_out ) ) ALLOCATE( rad_sw_out(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_out', tmp)
rad_sw_out(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_sw_out ) ) &
ALLOCATE( rad_sw_out(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_out', rad_sw_out )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_out_av' , found = array_found )
IF ( array_found ) THEN
IF ( radiation_scheme == 'clear-sky' .OR. radiation_scheme == 'constant' .OR. &
radiation_scheme == 'external' ) THEN
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) &
ALLOCATE( rad_sw_out_av(0:0,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_out_av', tmp )
rad_sw_out_av(0,:,:) = tmp
ELSE
IF ( .NOT. ALLOCATED( rad_sw_out_av ) ) &
ALLOCATE( rad_sw_out_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_out_av', rad_sw_out_av )
ENDIF
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_cs_hr' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_sw_cs_hr ) ) &
ALLOCATE( rad_sw_cs_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_cs_hr', rad_sw_cs_hr )
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_cs_hr_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_sw_cs_hr_av ) ) &
ALLOCATE( rad_sw_cs_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_cs_hr_av', rad_sw_cs_hr_av )
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_hr' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_sw_hr ) ) ALLOCATE( rad_sw_hr(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_hr', rad_sw_hr )
ENDIF
CALL rd_mpi_io_check_array( 'rad_sw_hr_av' , found = array_found )
IF ( array_found ) THEN
IF ( .NOT. ALLOCATED( rad_sw_hr_av ) ) &
ALLOCATE( rad_sw_hr_av(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
CALL rrd_mpi_io( 'rad_sw_hr_av', rad_sw_hr_av )
ENDIF
END SUBROUTINE radiation_rrd_local_mpi
END MODULE radiation_model_mod