!> @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-2020 Institute of Computer Science of the ! Czech Academy of Sciences, Prague ! Copyright 2015-2019 Czech Technical University in Prague ! Copyright 1997-2020 Leibniz Universitaet Hannover !------------------------------------------------------------------------------! ! ! Current revisions: ! ------------------ ! ! ! Former revisions: ! ----------------- ! $Id: radiation_model_mod.f90 4392 2020-01-31 16:14:57Z pavelkrc $ ! - Add debug tracing of large radiative fluxes (option trace_fluxes_above) ! - Print exact counts of SVF and CSF if debut_output is enabled ! - Update descriptions of RTM 3.0 and related comments ! ! 4360 2020-01-07 11:25:50Z suehring ! Renamed pc_heating_rate, pc_transpiration_rate, pc_transpiration_rate to ! pcm_heating_rate, pcm_latent_rate, pcm_transpiration_rate ! ! 4340 2019-12-16 08:17:03Z Giersch ! Albedo indices for building_surface_pars are now declared as parameters to ! prevent an error if the gfortran compiler with -Werror=unused-value is used ! ! 4291 2019-11-11 12:36:54Z moh.hefny ! Enabled RTM in case of biometeorology even if there is no vertical ! surfaces or 3D vegetation in the domain ! ! 4286 2019-10-30 16:01:14Z resler ! - Fix wrong treating of time_rad during interpolation in radiation_model_mod ! - Fix wrong checks of time_rad from dynamic driver in radiation_model_mod ! - Add new directional model of human body for MRT: ellipsoid ! ! 4271 2019-10-23 10:46:41Z maronga ! Bugfix: missing parentheses in calculation of snow albedo ! ! 4245 2019-09-30 08:40:37Z pavelkrc ! Initialize explicit per-surface albedos from building_surface_pars ! ! 4238 2019-09-25 16:06:01Z suehring ! Modify check in order to avoid equality comparisons of floating points ! ! 4227 2019-09-10 18:04:34Z gronemeier ! implement new palm_date_time_mod ! ! 4226 2019-09-10 17:03:24Z suehring ! - Netcdf input routine for dimension length renamed ! - Define time variable for external radiation input relative to time_utc_init ! ! 4210 2019-09-02 13:07:09Z suehring ! - Revise steering of splitting diffuse and direct radiation ! - Bugfixes in checks ! - Optimize mapping of radiation components onto 2D arrays, avoid unnecessary ! operations ! ! 4208 2019-09-02 09:01:07Z suehring ! Bugfix in accessing albedo_pars in the clear-sky branch ! (merge from branch resler) ! ! 4198 2019-08-29 15:17:48Z gronemeier ! Prohibit execution of radiation model if rotation_angle is not zero ! ! 4197 2019-08-29 14:33:32Z suehring ! Revise steering of surface albedo initialization when albedo_pars is provided ! ! 4190 2019-08-27 15:42:37Z suehring ! Implement external radiation forcing also for level-of-detail = 2 ! (horizontally 2D radiation) ! ! 4188 2019-08-26 14:15:47Z suehring ! Minor adjustment in error message ! ! 4187 2019-08-26 12:43:15Z suehring ! - Take external radiation from root domain dynamic input if not provided for ! each nested domain ! - Combine MPI_ALLREDUCE calls to reduce mpi overhead ! ! 4182 2019-08-22 15:20:23Z scharf ! Corrected "Former revisions" section ! ! 4179 2019-08-21 11:16:12Z suehring ! Remove debug prints ! ! 4178 2019-08-21 11:13:06Z suehring ! External radiation forcing implemented. ! ! 4168 2019-08-16 13:50:17Z suehring ! Replace function get_topography_top_index by topo_top_ind ! ! 4157 2019-08-14 09:19:12Z suehring ! Give informative message on raytracing distance only by core zero ! ! 4148 2019-08-08 11:26:00Z suehring ! Comments added ! ! 4134 2019-08-02 18:39:57Z suehring ! Bugfix in formatted write statement ! ! 4127 2019-07-30 14:47:10Z suehring ! Remove unused pch_index (merge from branch resler) ! ! 4089 2019-07-11 14:30:27Z suehring ! - Correct level 2 initialization of spectral albedos in rrtmg branch, long- and ! shortwave albedos were mixed-up. ! - Change order of albedo_pars so that it is now consistent with the defined ! order of albedo_pars in PIDS ! ! 4069 2019-07-01 14:05:51Z Giersch ! Masked output running index mid has been introduced as a local variable to ! avoid runtime error (Loop variable has been modified) in time_integration ! ! 4067 2019-07-01 13:29:25Z suehring ! Bugfix, pass dummy string to MPI_INFO_SET (J. Resler) ! ! 4039 2019-06-18 10:32:41Z suehring ! Bugfix for masked data output ! ! 4008 2019-05-30 09:50:11Z moh.hefny ! Bugfix in check variable when a variable's string is less than 3 ! characters is processed. All variables now are checked if they ! belong to radiation ! ! 3992 2019-05-22 16:49:38Z suehring ! Bugfix in rrtmg radiation branch in a nested run when the lowest prognistic ! grid points in a child domain are all inside topography ! ! 3987 2019-05-22 09:52:13Z kanani ! Introduce alternative switch for debug output during timestepping ! ! 3943 2019-05-02 09:50:41Z maronga ! Missing blank characteer added. ! ! 3900 2019-04-16 15:17:43Z suehring ! Fixed initialization problem ! ! 3885 2019-04-11 11:29:34Z kanani ! Changes related to global restructuring of location messages and introduction ! of additional debug messages ! ! 3881 2019-04-10 09:31:22Z suehring ! Output of albedo and emissivity moved from USM, bugfixes in initialization ! of albedo ! ! 3861 2019-04-04 06:27:41Z maronga ! Bugfix: factor of 4.0 required instead of 3.0 in calculation of rad_lw_out_change_0 ! ! 3859 2019-04-03 20:30:31Z maronga ! Added some descriptions ! ! 3847 2019-04-01 14:51:44Z suehring ! Implement check for dt_radiation (must be > 0) ! ! 3846 2019-04-01 13:55:30Z suehring ! unused variable removed ! ! 3814 2019-03-26 08:40:31Z pavelkrc ! Change zenith(0:0) and others to scalar. ! Code review. ! Rename exported nzu, nzp and related variables due to name conflict ! ! 3771 2019-02-28 12:19:33Z raasch ! rrtmg preprocessor for directives moved/added, save attribute added to temporary ! pointers to avoid compiler warnings about outlived pointer targets, ! statement added to avoid compiler warning about unused variable ! ! 3769 2019-02-28 10:16:49Z moh.hefny ! removed unused variables and subroutine radiation_radflux_gridbox ! ! 3767 2019-02-27 08:18:02Z raasch ! unused variable for file index removed from rrd-subroutines parameter list ! ! 3760 2019-02-21 18:47:35Z moh.hefny ! Bugfix: initialized simulated_time before calculating solar position ! to enable restart option with reading in SVF from file(s). ! ! 3754 2019-02-19 17:02:26Z kanani ! (resler, pavelkrc) ! Bugfixes: add further required MRT factors to read/write_svf, ! fix for aggregating view factors to eliminate local noise in reflected ! irradiance at mutually close surfaces (corners, presence of trees) in the ! angular discretization scheme. ! ! 3752 2019-02-19 09:37:22Z resler ! added read/write number of MRT factors to the respective routines ! ! 3705 2019-01-29 19:56:39Z suehring ! Make variables that are sampled in virtual measurement module public ! ! 3704 2019-01-29 19:51:41Z suehring ! Some interface calls moved to module_interface + cleanup ! ! 3667 2019-01-10 14:26:24Z schwenkel ! Modified check for rrtmg input files ! ! 3655 2019-01-07 16:51:22Z knoop ! nopointer option removed ! ! 1496 2014-12-02 17:25:50Z maronga ! Initial revision ! ! ! 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 USE arrays_3d, & ONLY: dzw, hyp, nc, pt, p, q, ql, u, v, w, zu, zw, exner, d_exner USE basic_constants_and_equations_mod, & ONLY: c_p, g, lv_d_cp, l_v, pi, r_d, rho_l, solar_constant, sigma_sb, & barometric_formula 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, & initializing_actions, io_blocks, io_group, & land_surface, large_scale_forcing, & latitude, longitude, lsf_surf, & message_string, plant_canopy, pt_surface, & rho_surface, simulated_time, spinup_time, surface_pressure, & read_svf, write_svf, & time_since_reference_point, urban_surface, varnamelength 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, nxlg, nxr, nxrg, ny, nyn, nyng, nys, nysg, & nzb, nzt, topo_top_ind 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, & pavement_type_f, & vegetation_type_f, & water_type_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, & pids_id, & open_read_file, & real_1d_3d, & vars_pids 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 statistics, & ONLY: hom USE surface_mod, & ONLY: ind_pav_green, ind_veg_wall, ind_wat_win, & 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:33), 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 /) ! !-- 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 LOGICAL :: unscheduled_radiation_calls = .TRUE., & !< 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 interaction between surfaces. !< When it switched off, only the effect of buildings and trees shadow !< will be considered. However fewer SVFs are expected. radiation_interactions_on = .TRUE. !< namelist flag to force RTM activiation regardless to vertical urban/land surface and trees REAL(wp) :: albedo = 9999999.9_wp, & !< NAMELIST alpha albedo_lw_dif = 9999999.9_wp, & !< NAMELIST aldif albedo_lw_dir = 9999999.9_wp, & !< NAMELIST aldir albedo_sw_dif = 9999999.9_wp, & !< NAMELIST asdif albedo_sw_dir = 9999999.9_wp, & !< NAMELIST asdir decl_1, & !< declination coef. 1 decl_2, & !< declination coef. 2 decl_3, & !< declination coef. 3 dt_radiation = 0.0_wp, & !< radiation model timestep emissivity = 9999999.9_wp, & !< NAMELIST surface emissivity lon = 0.0_wp, & !< longitude in radians lat = 0.0_wp, & !< latitude in radians net_radiation = 0.0_wp, & !< net radiation at surface skip_time_do_radiation = 0.0_wp, & !< Radiation model is not called before this time sky_trans, & !< sky transmissivity time_radiation = 0.0_wp, & !< time since last call of radiation code trace_fluxes_above = -1.0_wp !< NAMELIST option for debug tracing of large radiative fluxes (W/m2;W/m3) INTEGER(iwp) :: day_of_year !< day of the current year REAL(wp) :: cos_zenith !< cosine of solar zenith angle, also z-coordinate of solar unit vector REAL(wp) :: d_hours_day !< 1 / hours-per-day REAL(wp) :: d_seconds_hour !< 1 / seconds-per-hour REAL(wp) :: second_of_day !< second of the current day REAL(wp) :: sun_dir_lat !< y-coordinate of solar unit vector REAL(wp) :: sun_dir_lon !< x-coordinate of solar unit vector REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_net_av !< average of net radiation (rad_net) at surface REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_lw_in_xy_av !< average of incoming longwave radiation at surface REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_lw_out_xy_av !< average of outgoing longwave radiation at surface REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_sw_in_xy_av !< average of incoming shortwave radiation at surface REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_sw_out_xy_av !< average of outgoing shortwave radiation at surface REAL(wp), PARAMETER :: emissivity_atm_clsky = 0.8_wp !< emissivity of the clear-sky atmosphere ! !-- Land surface albedos for solar zenith angle of 60degree after Briegleb (1992) !-- (broadband, longwave, shortwave ): bb, lw, sw, REAL(wp), DIMENSION(0:2,1:33), PARAMETER :: albedo_pars = RESHAPE( (/& 0.06_wp, 0.06_wp, 0.06_wp, & ! 1 0.19_wp, 0.28_wp, 0.09_wp, & ! 2 0.23_wp, 0.33_wp, 0.11_wp, & ! 3 0.23_wp, 0.33_wp, 0.11_wp, & ! 4 0.25_wp, 0.34_wp, 0.14_wp, & ! 5 0.14_wp, 0.22_wp, 0.06_wp, & ! 6 0.17_wp, 0.27_wp, 0.06_wp, & ! 7 0.19_wp, 0.31_wp, 0.06_wp, & ! 8 0.14_wp, 0.22_wp, 0.06_wp, & ! 9 0.18_wp, 0.28_wp, 0.06_wp, & ! 10 0.43_wp, 0.51_wp, 0.35_wp, & ! 11 0.32_wp, 0.40_wp, 0.24_wp, & ! 12 0.19_wp, 0.27_wp, 0.10_wp, & ! 13 0.77_wp, 0.65_wp, 0.90_wp, & ! 14 0.77_wp, 0.65_wp, 0.90_wp, & ! 15 0.82_wp, 0.70_wp, 0.95_wp, & ! 16 0.08_wp, 0.08_wp, 0.08_wp, & ! 17 0.17_wp, 0.17_wp, 0.17_wp, & ! 18 0.17_wp, 0.17_wp, 0.17_wp, & ! 19 0.30_wp, 0.30_wp, 0.30_wp, & ! 20 0.17_wp, 0.17_wp, 0.17_wp, & ! 21 0.17_wp, 0.17_wp, 0.17_wp, & ! 22 0.17_wp, 0.17_wp, 0.17_wp, & ! 23 0.17_wp, 0.17_wp, 0.17_wp, & ! 24 0.17_wp, 0.17_wp, 0.17_wp, & ! 25 0.17_wp, 0.17_wp, 0.17_wp, & ! 26 0.17_wp, 0.17_wp, 0.17_wp, & ! 27 0.17_wp, 0.17_wp, 0.17_wp, & ! 28 0.17_wp, 0.17_wp, 0.17_wp, & ! 29 0.17_wp, 0.17_wp, 0.17_wp, & ! 30 0.17_wp, 0.17_wp, 0.17_wp, & ! 31 0.17_wp, 0.17_wp, 0.17_wp, & ! 32 0.17_wp, 0.17_wp, 0.17_wp & ! 33 /), (/ 3, 33 /) ) REAL(wp), DIMENSION(:,:,:), ALLOCATABLE, TARGET :: & rad_lw_cs_hr, & !< longwave clear sky radiation heating rate (K/s) rad_lw_cs_hr_av, & !< average of rad_lw_cs_hr rad_lw_hr, & !< longwave radiation heating rate (K/s) rad_lw_hr_av, & !< average of rad_sw_hr rad_lw_in, & !< incoming longwave radiation (W/m2) rad_lw_in_av, & !< average of rad_lw_in rad_lw_out, & !< outgoing longwave radiation (W/m2) rad_lw_out_av, & !< average of rad_lw_out rad_sw_cs_hr, & !< shortwave clear sky radiation heating rate (K/s) rad_sw_cs_hr_av, & !< average of rad_sw_cs_hr rad_sw_hr, & !< shortwave radiation heating rate (K/s) rad_sw_hr_av, & !< average of rad_sw_hr rad_sw_in, & !< incoming shortwave radiation (W/m2) rad_sw_in_av, & !< average of rad_sw_in rad_sw_out, & !< outgoing shortwave radiation (W/m2) rad_sw_out_av !< average of rad_sw_out ! !-- Variables and parameters used in RRTMG only #if defined ( __rrtmg ) CHARACTER(LEN=12) :: rrtm_input_file = "RAD_SND_DATA" !< name of the NetCDF input file (sounding data) ! !-- Flag parameters to be passed to RRTMG (should not be changed until ice phase in clouds is allowed) INTEGER(iwp), PARAMETER :: rrtm_idrv = 1, & !< flag for longwave upward flux calculation option (0,1) rrtm_inflglw = 2, & !< flag for lw cloud optical properties (0,1,2) rrtm_iceflglw = 0, & !< flag for lw ice particle specifications (0,1,2,3) rrtm_liqflglw = 1, & !< flag for lw liquid droplet specifications rrtm_inflgsw = 2, & !< flag for sw cloud optical properties (0,1,2) rrtm_iceflgsw = 0, & !< flag for sw ice particle specifications (0,1,2,3) rrtm_liqflgsw = 1 !< flag for sw liquid droplet specifications ! !-- The following variables should be only changed with care, as this will !-- require further setting of some variables, which is currently not !-- implemented (aerosols, ice phase). INTEGER(iwp) :: nzt_rad, & !< upper vertical limit for radiation calculations rrtm_icld = 0, & !< cloud flag (0: clear sky column, 1: cloudy column) rrtm_iaer = 0 !< aerosol option flag (0: no aerosol layers, for lw only: 6 (requires setting of rrtm_sw_ecaer), 10: one or more aerosol layers (not implemented) INTEGER(iwp) :: nc_stat !< local variable for storin the result of netCDF calls for error message handling LOGICAL :: snd_exists = .FALSE. !< flag parameter to check whether a user-defined input files exists LOGICAL :: sw_exists = .FALSE. !< flag parameter to check whether that required rrtmg sw file exists LOGICAL :: lw_exists = .FALSE. !< flag parameter to check whether that required rrtmg lw file exists REAL(wp), PARAMETER :: mol_mass_air_d_wv = 1.607793_wp !< molecular weight dry air / water vapor REAL(wp), DIMENSION(:), ALLOCATABLE :: hyp_snd, & !< hypostatic pressure from sounding data (hPa) rrtm_tsfc, & !< dummy array for storing surface temperature t_snd !< actual temperature from sounding data (hPa) REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rrtm_ccl4vmr, & !< CCL4 volume mixing ratio (g/mol) rrtm_cfc11vmr, & !< CFC11 volume mixing ratio (g/mol) rrtm_cfc12vmr, & !< CFC12 volume mixing ratio (g/mol) rrtm_cfc22vmr, & !< CFC22 volume mixing ratio (g/mol) rrtm_ch4vmr, & !< CH4 volume mixing ratio rrtm_cicewp, & !< in-cloud ice water path (g/m2) rrtm_cldfr, & !< cloud fraction (0,1) rrtm_cliqwp, & !< in-cloud liquid water path (g/m2) rrtm_co2vmr, & !< CO2 volume mixing ratio (g/mol) rrtm_emis, & !< surface emissivity (0-1) rrtm_h2ovmr, & !< H2O volume mixing ratio rrtm_n2ovmr, & !< N2O volume mixing ratio rrtm_o2vmr, & !< O2 volume mixing ratio rrtm_o3vmr, & !< O3 volume mixing ratio rrtm_play, & !< pressure layers (hPa, zu-grid) rrtm_plev, & !< pressure layers (hPa, zw-grid) rrtm_reice, & !< cloud ice effective radius (microns) rrtm_reliq, & !< cloud water drop effective radius (microns) rrtm_tlay, & !< actual temperature (K, zu-grid) rrtm_tlev, & !< actual temperature (K, zw-grid) rrtm_lwdflx, & !< RRTM output of incoming longwave radiation flux (W/m2) rrtm_lwdflxc, & !< RRTM output of outgoing clear sky longwave radiation flux (W/m2) rrtm_lwuflx, & !< RRTM output of outgoing longwave radiation flux (W/m2) rrtm_lwuflxc, & !< RRTM output of incoming clear sky longwave radiation flux (W/m2) rrtm_lwuflx_dt, & !< RRTM output of incoming clear sky longwave radiation flux (W/m2) rrtm_lwuflxc_dt,& !< RRTM output of outgoing clear sky longwave radiation flux (W/m2) rrtm_lwhr, & !< RRTM output of longwave radiation heating rate (K/d) rrtm_lwhrc, & !< RRTM output of incoming longwave clear sky radiation heating rate (K/d) rrtm_swdflx, & !< RRTM output of incoming shortwave radiation flux (W/m2) rrtm_swdflxc, & !< RRTM output of outgoing clear sky shortwave radiation flux (W/m2) rrtm_swuflx, & !< RRTM output of outgoing shortwave radiation flux (W/m2) rrtm_swuflxc, & !< RRTM output of incoming clear sky shortwave radiation flux (W/m2) rrtm_swhr, & !< RRTM output of shortwave radiation heating rate (K/d) rrtm_swhrc, & !< RRTM output of incoming shortwave clear sky radiation heating rate (K/d) rrtm_dirdflux, & !< RRTM output of incoming direct shortwave (W/m2) rrtm_difdflux !< RRTM output of incoming diffuse shortwave (W/m2) REAL(wp), DIMENSION(1) :: rrtm_aldif, & !< surface albedo for longwave diffuse radiation rrtm_aldir, & !< surface albedo for longwave direct radiation rrtm_asdif, & !< surface albedo for shortwave diffuse radiation rrtm_asdir !< surface albedo for shortwave direct radiation ! !-- Definition of arrays that are currently not used for calling RRTMG (due to setting of flag parameters) REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: rad_lw_cs_in, & !< incoming clear sky longwave radiation (W/m2) (not used) rad_lw_cs_out, & !< outgoing clear sky longwave radiation (W/m2) (not used) rad_sw_cs_in, & !< incoming clear sky shortwave radiation (W/m2) (not used) rad_sw_cs_out, & !< outgoing clear sky shortwave radiation (W/m2) (not used) rrtm_lw_tauaer, & !< lw aerosol optical depth rrtm_lw_taucld, & !< lw in-cloud optical depth rrtm_sw_taucld, & !< sw in-cloud optical depth rrtm_sw_ssacld, & !< sw in-cloud single scattering albedo rrtm_sw_asmcld, & !< sw in-cloud asymmetry parameter rrtm_sw_fsfcld, & !< sw in-cloud forward scattering fraction rrtm_sw_tauaer, & !< sw aerosol optical depth rrtm_sw_ssaaer, & !< sw aerosol single scattering albedo rrtm_sw_asmaer, & !< sw aerosol asymmetry parameter rrtm_sw_ecaer !< sw aerosol optical detph at 0.55 microns (rrtm_iaer = 6 only) #endif ! !-- Parameters of urban and land surface models INTEGER(iwp) :: nz_urban !< number of layers of urban surface (will be calculated) INTEGER(iwp) :: nz_plant !< number of layers of plant canopy (will be calculated) INTEGER(iwp) :: nz_urban_b !< bottom layer of urban surface (will be calculated) INTEGER(iwp) :: nz_urban_t !< top layer of urban surface (will be calculated) INTEGER(iwp) :: nz_plant_t !< top layer of plant canopy (will be calculated) !-- parameters of urban and land surface models INTEGER(iwp), PARAMETER :: nzut_free = 3 !< number of free layers above top of of topography INTEGER(iwp), PARAMETER :: ndsvf = 2 !< number of dimensions of real values in SVF INTEGER(iwp), PARAMETER :: idsvf = 2 !< number of dimensions of integer values in SVF INTEGER(iwp), PARAMETER :: ndcsf = 1 !< number of dimensions of real values in CSF INTEGER(iwp), PARAMETER :: idcsf = 2 !< number of dimensions of integer values in CSF INTEGER(iwp), PARAMETER :: kdcsf = 4 !< number of dimensions of integer values in CSF calculation array INTEGER(iwp), PARAMETER :: id = 1 !< position of d-index in surfl and surf INTEGER(iwp), PARAMETER :: iz = 2 !< position of k-index in surfl and surf INTEGER(iwp), PARAMETER :: iy = 3 !< position of j-index in surfl and surf INTEGER(iwp), PARAMETER :: ix = 4 !< position of i-index in surfl and surf INTEGER(iwp), PARAMETER :: im = 5 !< position of surface m-index in surfl and surf INTEGER(iwp), PARAMETER :: nidx_surf = 5 !< number of indices in surfl and surf INTEGER(iwp), PARAMETER :: nsurf_type = 10 !< number of surf types incl. phys.(land+urban) & (atm.,sky,boundary) surfaces - 1 INTEGER(iwp), PARAMETER :: iup_u = 0 !< 0 - index of urban upward surface (ground or roof) INTEGER(iwp), PARAMETER :: idown_u = 1 !< 1 - index of urban downward surface (overhanging) INTEGER(iwp), PARAMETER :: inorth_u = 2 !< 2 - index of urban northward facing wall INTEGER(iwp), PARAMETER :: isouth_u = 3 !< 3 - index of urban southward facing wall INTEGER(iwp), PARAMETER :: ieast_u = 4 !< 4 - index of urban eastward facing wall INTEGER(iwp), PARAMETER :: iwest_u = 5 !< 5 - index of urban westward facing wall INTEGER(iwp), PARAMETER :: iup_l = 6 !< 6 - index of land upward surface (ground or roof) INTEGER(iwp), PARAMETER :: inorth_l = 7 !< 7 - index of land northward facing wall INTEGER(iwp), PARAMETER :: isouth_l = 8 !< 8 - index of land southward facing wall INTEGER(iwp), PARAMETER :: ieast_l = 9 !< 9 - index of land eastward facing wall INTEGER(iwp), PARAMETER :: iwest_l = 10 !< 10- index of land westward facing wall INTEGER(iwp), DIMENSION(0:nsurf_type), PARAMETER :: idir = (/0, 0,0, 0,1,-1,0,0, 0,1,-1/) !< surface normal direction x indices INTEGER(iwp), DIMENSION(0:nsurf_type), PARAMETER :: jdir = (/0, 0,1,-1,0, 0,0,1,-1,0, 0/) !< surface normal direction y indices INTEGER(iwp), DIMENSION(0:nsurf_type), PARAMETER :: kdir = (/1,-1,0, 0,0, 0,1,0, 0,0, 0/) !< surface normal direction z indices REAL(wp), DIMENSION(0:nsurf_type) :: facearea !< area of single face in respective !< direction (will be calc'd) !-- indices and sizes of urban and land surface models INTEGER(iwp) :: startland !< start index of block of land and roof surfaces INTEGER(iwp) :: endland !< end index of block of land and roof surfaces INTEGER(iwp) :: nlands !< number of land and roof surfaces in local processor INTEGER(iwp) :: startwall !< start index of block of wall surfaces INTEGER(iwp) :: endwall !< end index of block of wall surfaces INTEGER(iwp) :: nwalls !< number of wall surfaces in local processor !-- indices needed for RTM netcdf output subroutines INTEGER(iwp), PARAMETER :: nd = 5 CHARACTER(LEN=6), DIMENSION(0:nd-1), PARAMETER :: dirname = (/ '_roof ', '_south', '_north', '_west ', '_east ' /) INTEGER(iwp), DIMENSION(0:nd-1), PARAMETER :: dirint_u = (/ iup_u, isouth_u, inorth_u, iwest_u, ieast_u /) INTEGER(iwp), DIMENSION(0:nd-1), PARAMETER :: dirint_l = (/ iup_l, isouth_l, inorth_l, iwest_l, ieast_l /) INTEGER(iwp), DIMENSION(0:nd-1) :: dirstart INTEGER(iwp), DIMENSION(0:nd-1) :: dirend !-- indices and sizes of urban and land surface models INTEGER(iwp), DIMENSION(:,:), POINTER :: surfl !< coordinates of i-th local surface in local grid - surfl[:,k] = [d, z, y, x, m] INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET :: surfl_linear !< dtto (linearly allocated array) INTEGER(iwp), DIMENSION(:,:), POINTER :: surf !< coordinates of i-th surface in grid - surf[:,k] = [d, z, y, x, m] INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET :: surf_linear !< dtto (linearly allocated array) INTEGER(iwp) :: nsurfl !< number of all surfaces in local processor INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET :: nsurfs !< array of number of all surfaces in individual processors INTEGER(iwp) :: nsurf !< global number of surfaces in index array of surfaces (nsurf = proc nsurfs) INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET :: surfstart !< starts of blocks of surfaces for individual processors in array surf (indexed from 1) !< respective block for particular processor is surfstart[iproc+1]+1 : surfstart[iproc+1]+nsurfs[iproc+1] !-- block variables needed for calculation of the plant canopy model inside the urban surface model INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: pct !< top layer of the plant canopy INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: pch !< heights of the plant canopy INTEGER(iwp) :: npcbl = 0 !< number of the plant canopy gridboxes in local processor INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: pcbl !< k,j,i coordinates of l-th local plant canopy box pcbl[:,l] = [k, j, i] REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinsw !< array of absorbed sw radiation for local plant canopy box REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinswdir !< array of absorbed direct sw radiation for local plant canopy box REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinswdif !< array of absorbed diffusion sw radiation for local plant canopy box REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinlw !< array of absorbed lw radiation for local plant canopy box !-- configuration parameters (they can be setup in PALM config) LOGICAL :: raytrace_mpi_rma = .TRUE. !< use MPI RMA to access LAD and gridsurf from remote processes during raytracing LOGICAL :: rad_angular_discretization = .TRUE.!< whether to use fixed resolution discretization of view factors for !< reflected radiation (as opposed to all mutually visible pairs) LOGICAL :: plant_lw_interact = .TRUE. !< whether plant canopy interacts with LW radiation (in addition to SW) INTEGER(iwp) :: mrt_nlevels = 0 !< number of vertical boxes above surface for which to calculate MRT LOGICAL :: mrt_skip_roof = .TRUE. !< do not calculate MRT above roof surfaces LOGICAL :: mrt_include_sw = .TRUE. !< should MRT calculation include SW radiation as well? INTEGER(wp) :: mrt_geom = 1 !< method for MRT direction weights simulating a sphere or a human body REAL(wp), DIMENSION(2) :: mrt_geom_params = (/ .12_wp, .88_wp /) !< parameters for the selected method INTEGER(iwp) :: nrefsteps = 3 !< number of reflection steps to perform REAL(wp), PARAMETER :: ext_coef = 0.6_wp !< extinction coefficient (a.k.a. alpha) INTEGER(iwp), PARAMETER :: rad_version_len = 10 !< length of identification string of rad version CHARACTER(rad_version_len), PARAMETER :: rad_version = 'RAD v. 3.0' !< identification of version of binary svf and restart files INTEGER(iwp) :: raytrace_discrete_elevs = 40 !< number of discretization steps for elevation (nadir to zenith) INTEGER(iwp) :: raytrace_discrete_azims = 80 !< number of discretization steps for azimuth (out of 360 degrees) REAL(wp) :: max_raytracing_dist = -999.0_wp !< maximum distance for raytracing (in metres) REAL(wp) :: min_irrf_value = 1e-6_wp !< minimum potential irradiance factor value for raytracing REAL(wp), DIMENSION(1:30) :: svfnorm_report_thresh = 1e21_wp !< thresholds of SVF normalization values to report INTEGER(iwp) :: svfnorm_report_num !< number of SVF normalization thresholds to report !-- radiation related arrays to be used in radiation_interaction routine REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_sw_in_dir !< direct sw radiation REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_sw_in_diff !< diffusion sw radiation REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rad_lw_in_diff !< diffusion lw radiation !-- parameters required for RRTMG lower boundary condition REAL(wp) :: albedo_urb !< albedo value retuned to RRTMG boundary cond. REAL(wp) :: emissivity_urb !< emissivity value retuned to RRTMG boundary cond. REAL(wp) :: t_rad_urb !< temperature value retuned to RRTMG boundary cond. !-- type for calculation of svf TYPE t_svf INTEGER(iwp) :: isurflt !< INTEGER(iwp) :: isurfs !< REAL(wp) :: rsvf !< REAL(wp) :: rtransp !< END TYPE !-- type for calculation of csf TYPE t_csf INTEGER(iwp) :: ip !< INTEGER(iwp) :: itx !< INTEGER(iwp) :: ity !< INTEGER(iwp) :: itz !< INTEGER(iwp) :: isurfs !< Idx of source face / -1 for sky REAL(wp) :: rcvf !< Canopy view factor for faces / !< canopy sink factor for sky (-1) END TYPE !-- arrays storing the values of USM INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: svfsurf !< svfsurf[:,isvf] = index of target and source surface for svf[isvf] REAL(wp), DIMENSION(:,:), ALLOCATABLE :: svf !< array of shape view factors+direct irradiation factors for local surfaces REAL(wp), DIMENSION(:), ALLOCATABLE :: surfins !< array of sw radiation falling to local surface after i-th reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinl !< array of lw radiation for local surface after i-th reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: skyvf !< array of sky view factor for each local surface REAL(wp), DIMENSION(:), ALLOCATABLE :: skyvft !< array of sky view factor including transparency for each local surface REAL(wp), DIMENSION(:,:), ALLOCATABLE :: dsitrans !< dsidir[isvfl,i] = path transmittance of i-th !< direction of direct solar irradiance per target surface REAL(wp), DIMENSION(:,:), ALLOCATABLE :: dsitransc !< dtto per plant canopy box REAL(wp), DIMENSION(:,:), ALLOCATABLE :: dsidir !< dsidir[:,i] = unit vector of i-th !< direction of direct solar irradiance INTEGER(iwp) :: ndsidir !< number of apparent solar directions used INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: dsidir_rev !< dsidir_rev[ielev,iazim] = i for dsidir or -1 if not present INTEGER(iwp) :: nmrtbl !< No. of local grid boxes for which MRT is calculated INTEGER(iwp) :: nmrtf !< number of MRT factors for local processor INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: mrtbl !< coordinates of i-th local MRT box - surfl[:,i] = [z, y, x] INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: mrtfsurf !< mrtfsurf[:,imrtf] = index of target MRT box and source surface for mrtf[imrtf] REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtf !< array of MRT factors for each local MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtft !< array of MRT factors including transparency for each local MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtsky !< array of sky view factor for each local MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtskyt !< array of sky view factor including transparency for each local MRT box REAL(wp), DIMENSION(:,:), ALLOCATABLE :: mrtdsit !< array of direct solar transparencies for each local MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtinsw !< mean SW radiant flux for each MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtinlw !< mean LW radiant flux for each MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrt !< mean radiant temperature for each MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtinsw_av !< time average mean SW radiant flux for each MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrtinlw_av !< time average mean LW radiant flux for each MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: mrt_av !< time average mean radiant temperature for each MRT box REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinsw !< array of sw radiation falling to local surface including radiation from reflections REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinlw !< array of lw radiation falling to local surface including radiation from reflections REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinswdir !< array of direct sw radiation falling to local surface REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinswdif !< array of diffuse sw radiation from sky and model boundary falling to local surface REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinlwdif !< array of diffuse lw radiation from sky and model boundary falling to local surface !< Outward radiation is only valid for nonvirtual surfaces REAL(wp), DIMENSION(:), ALLOCATABLE :: surfoutsl !< array of reflected sw radiation for local surface in i-th reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfoutll !< array of reflected + emitted lw radiation for local surface in i-th reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfouts !< array of reflected sw radiation for all surfaces in i-th reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfoutl !< array of reflected + emitted lw radiation for all surfaces in i-th reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinlg !< global array of incoming lw radiation from plant canopy REAL(wp), DIMENSION(:), ALLOCATABLE :: surfoutsw !< array of total sw radiation outgoing from nonvirtual surfaces surfaces after all reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfoutlw !< array of total lw radiation outgoing from nonvirtual surfaces surfaces after all reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfemitlwl !< array of emitted lw radiation for local surface used to calculate effective surface temperature for radiation model !-- block variables needed for calculation of the plant canopy model inside the urban surface model INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: csfsurf !< csfsurf[:,icsf] = index of target surface and csf grid index for csf[icsf] REAL(wp), DIMENSION(:,:), ALLOCATABLE :: csf !< array of plant canopy sink fators + direct irradiation factors (transparency) REAL(wp), DIMENSION(:,:,:), POINTER :: sub_lad !< subset of lad_s within urban surface, transformed to plain Z coordinate REAL(wp), DIMENSION(:), POINTER :: sub_lad_g !< sub_lad globalized (used to avoid MPI RMA calls in raytracing) REAL(wp) :: prototype_lad !< prototype leaf area density for computing effective optical depth INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nzterr, plantt !< temporary global arrays for raytracing INTEGER(iwp) :: plantt_max !-- arrays and variables for calculation of svf and csf TYPE(t_svf), DIMENSION(:), POINTER :: asvf !< pointer to growing svc array TYPE(t_csf), DIMENSION(:), POINTER :: acsf !< pointer to growing csf array TYPE(t_svf), DIMENSION(:), POINTER :: amrtf !< pointer to growing mrtf array TYPE(t_svf), DIMENSION(:), ALLOCATABLE, TARGET :: asvf1, asvf2 !< realizations of svf array TYPE(t_csf), DIMENSION(:), ALLOCATABLE, TARGET :: acsf1, acsf2 !< realizations of csf array TYPE(t_svf), DIMENSION(:), ALLOCATABLE, TARGET :: amrtf1, amrtf2 !< realizations of mftf array INTEGER(iwp) :: nsvfla !< dimmension of array allocated for storage of svf in local processor INTEGER(iwp) :: ncsfla !< dimmension of array allocated for storage of csf in local processor INTEGER(iwp) :: nmrtfa !< dimmension of array allocated for storage of mrt INTEGER(iwp) :: msvf, mcsf, mmrtf!< mod for swapping the growing array INTEGER(iwp), PARAMETER :: gasize = 100000_iwp !< initial size of growing arrays REAL(wp), PARAMETER :: grow_factor = 1.4_wp !< growth factor of growing arrays INTEGER(iwp) :: nsvfl !< number of svf for local processor INTEGER(iwp) :: ncsfl !< no. of csf in local processor !< needed only during calc_svf but must be here because it is !< shared between subroutines calc_svf and raytrace INTEGER(iwp), DIMENSION(:,:,:,:), POINTER :: gridsurf !< reverse index of local surfl[d,k,j,i] (for case rad_angular_discretization) INTEGER(iwp), DIMENSION(:,:,:), ALLOCATABLE :: gridpcbl !< reverse index of local pcbl[k,j,i] INTEGER(iwp), PARAMETER :: nsurf_type_u = 6 !< number of urban surf types (used in gridsurf) !-- temporary arrays for calculation of csf in raytracing INTEGER(iwp) :: maxboxesg !< max number of boxes ray can cross in the domain INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: boxes !< coordinates of gridboxes being crossed by ray REAL(wp), DIMENSION(:), ALLOCATABLE :: crlens !< array of crossing lengths of ray for particular grid boxes INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: lad_ip !< array of numbers of process where lad is stored #if defined( __parallel ) INTEGER(kind=MPI_ADDRESS_KIND), & DIMENSION(:), ALLOCATABLE :: lad_disp !< array of displaycements of lad in local array of proc lad_ip INTEGER(iwp) :: win_lad !< MPI RMA window for leaf area density INTEGER(iwp) :: win_gridsurf !< MPI RMA window for reverse grid surface index #endif REAL(wp), DIMENSION(:), ALLOCATABLE :: lad_s_ray !< array of received lad_s for appropriate gridboxes crossed by ray INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: target_surfl INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE :: rt2_track REAL(wp), DIMENSION(:,:), ALLOCATABLE :: rt2_track_lad REAL(wp), DIMENSION(:), ALLOCATABLE :: rt2_track_dist REAL(wp), DIMENSION(:), ALLOCATABLE :: rt2_dist !-- arrays for time averages REAL(wp), DIMENSION(:), ALLOCATABLE :: surfradnet_av !< average of net radiation to local surface including radiation from reflections REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinsw_av !< average of sw radiation falling to local surface including radiation from reflections REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinlw_av !< average of lw radiation falling to local surface including radiation from reflections REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinswdir_av !< average of direct sw radiation falling to local surface REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinswdif_av !< average of diffuse sw radiation from sky and model boundary falling to local surface REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinlwdif_av !< average of diffuse lw radiation from sky and model boundary falling to local surface REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinswref_av !< average of sw radiation falling to surface from reflections REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinlwref_av !< average of lw radiation falling to surface from reflections REAL(wp), DIMENSION(:), ALLOCATABLE :: surfoutsw_av !< average of total sw radiation outgoing from nonvirtual surfaces surfaces after all reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfoutlw_av !< average of total lw radiation outgoing from nonvirtual surfaces surfaces after all reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfins_av !< average of array of residua of sw radiation absorbed in surface after last reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: surfinl_av !< average of array of residua of lw radiation absorbed in surface after last reflection REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinlw_av !< Average of pcbinlw REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinsw_av !< Average of pcbinsw REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinswdir_av !< Average of pcbinswdir REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinswdif_av !< Average of pcbinswdif REAL(wp), DIMENSION(:), ALLOCATABLE :: pcbinswref_av !< Average of pcbinswref !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !-- Energy balance variables !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !-- parameters of the land, roof and wall surfaces REAL(wp), DIMENSION(:), ALLOCATABLE :: albedo_surf !< albedo of the surface REAL(wp), DIMENSION(:), ALLOCATABLE :: emiss_surf !< emissivity of the wall surface ! !-- External radiation. Depending on the given level of detail either a 1D or !-- a 3D array will be allocated. TYPE( real_1d_3d ) :: rad_lw_in_f !< external incoming longwave radiation, from observation or model TYPE( real_1d_3d ) :: rad_sw_in_f !< external incoming shortwave radiation, from observation or model TYPE( real_1d_3d ) :: rad_sw_in_dif_f !< external incoming shortwave radiation, diffuse part, from observation or model TYPE( real_1d_3d ) :: time_rad_f !< time dimension for external radiation, from observation or model INTERFACE radiation_check_data_output MODULE PROCEDURE radiation_check_data_output END INTERFACE radiation_check_data_output INTERFACE radiation_check_data_output_ts MODULE PROCEDURE radiation_check_data_output_ts END INTERFACE radiation_check_data_output_ts INTERFACE radiation_check_data_output_pr MODULE PROCEDURE radiation_check_data_output_pr END INTERFACE radiation_check_data_output_pr INTERFACE radiation_check_parameters MODULE PROCEDURE radiation_check_parameters END INTERFACE radiation_check_parameters INTERFACE radiation_clearsky MODULE PROCEDURE radiation_clearsky END INTERFACE radiation_clearsky INTERFACE radiation_constant MODULE PROCEDURE radiation_constant END INTERFACE radiation_constant INTERFACE radiation_control MODULE PROCEDURE radiation_control END INTERFACE radiation_control INTERFACE radiation_3d_data_averaging MODULE PROCEDURE radiation_3d_data_averaging END INTERFACE radiation_3d_data_averaging INTERFACE radiation_data_output_2d MODULE PROCEDURE radiation_data_output_2d END INTERFACE radiation_data_output_2d INTERFACE radiation_data_output_3d MODULE PROCEDURE radiation_data_output_3d END INTERFACE radiation_data_output_3d INTERFACE radiation_data_output_mask MODULE PROCEDURE radiation_data_output_mask END INTERFACE radiation_data_output_mask INTERFACE radiation_define_netcdf_grid MODULE PROCEDURE radiation_define_netcdf_grid END INTERFACE radiation_define_netcdf_grid INTERFACE radiation_header MODULE PROCEDURE radiation_header END INTERFACE radiation_header INTERFACE radiation_init MODULE PROCEDURE radiation_init END INTERFACE radiation_init INTERFACE radiation_parin MODULE PROCEDURE radiation_parin END INTERFACE radiation_parin INTERFACE radiation_rrtmg MODULE PROCEDURE radiation_rrtmg END INTERFACE radiation_rrtmg #if defined( __rrtmg ) INTERFACE radiation_tendency MODULE PROCEDURE radiation_tendency MODULE PROCEDURE radiation_tendency_ij END INTERFACE radiation_tendency #endif INTERFACE radiation_rrd_local MODULE PROCEDURE radiation_rrd_local END INTERFACE radiation_rrd_local INTERFACE radiation_wrd_local MODULE PROCEDURE radiation_wrd_local END INTERFACE radiation_wrd_local INTERFACE radiation_interaction MODULE PROCEDURE radiation_interaction END INTERFACE radiation_interaction INTERFACE radiation_interaction_init MODULE PROCEDURE radiation_interaction_init END INTERFACE radiation_interaction_init INTERFACE radiation_presimulate_solar_pos MODULE PROCEDURE radiation_presimulate_solar_pos END INTERFACE radiation_presimulate_solar_pos INTERFACE radiation_calc_svf MODULE PROCEDURE radiation_calc_svf END INTERFACE radiation_calc_svf INTERFACE radiation_write_svf MODULE PROCEDURE radiation_write_svf END INTERFACE radiation_write_svf INTERFACE radiation_read_svf MODULE PROCEDURE radiation_read_svf END INTERFACE radiation_read_svf SAVE PRIVATE ! !-- Public functions / NEEDS SORTING PUBLIC radiation_check_data_output, radiation_check_data_output_pr, & radiation_check_data_output_ts, & radiation_check_parameters, radiation_control, & radiation_header, radiation_init, radiation_parin, & radiation_3d_data_averaging, & radiation_data_output_2d, radiation_data_output_3d, & radiation_define_netcdf_grid, radiation_wrd_local, & radiation_rrd_local, radiation_data_output_mask, & radiation_calc_svf, radiation_write_svf, & radiation_interaction, radiation_interaction_init, & radiation_read_svf, radiation_presimulate_solar_pos ! !-- Public variables and constants / NEEDS SORTING PUBLIC albedo, albedo_type, decl_1, decl_2, decl_3, dots_rad, dt_radiation,& emissivity, force_radiation_call, lat, lon, mrt_geom, & mrt_geom_params, & mrt_include_sw, mrt_nlevels, mrtbl, mrtinsw, mrtinlw, nmrtbl, & rad_net_av, radiation, radiation_scheme, rad_lw_in, & rad_lw_in_av, rad_lw_out, rad_lw_out_av, & rad_lw_cs_hr, rad_lw_cs_hr_av, rad_lw_hr, rad_lw_hr_av, rad_sw_in, & rad_sw_in_av, rad_sw_out, rad_sw_out_av, rad_sw_cs_hr, & rad_sw_cs_hr_av, rad_sw_hr, rad_sw_hr_av, solar_constant, & skip_time_do_radiation, time_radiation, unscheduled_radiation_calls,& cos_zenith, calc_zenith, sun_direction, sun_dir_lat, sun_dir_lon, & idir, jdir, kdir, id, iz, iy, ix, & iup_u, inorth_u, isouth_u, ieast_u, iwest_u, & iup_l, inorth_l, isouth_l, ieast_l, iwest_l, & nsurf_type, nz_urban_b, nz_urban_t, nz_urban, pch, nsurf, & idsvf, ndsvf, idcsf, ndcsf, kdcsf, pct, & radiation_interactions, startwall, startland, endland, endwall, & skyvf, skyvft, radiation_interactions_on, average_radiation, & rad_sw_in_diff, rad_sw_in_dir #if defined ( __rrtmg ) PUBLIC radiation_tendency, rrtm_aldif, rrtm_aldir, rrtm_asdif, rrtm_asdir #endif CONTAINS !------------------------------------------------------------------------------! ! Description: ! ------------ !> 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 !< INTEGER(iwp) :: i, k INTEGER(iwp) :: ilen CHARACTER(LEN=varnamelength) :: var !< TRIM(variable) var = TRIM(variable) IF ( len(var) < 3_iwp ) THEN unit = 'illegal' RETURN ENDIF IF ( var(1:3) /= 'rad' .AND. var(1:3) /= 'rtm' ) THEN unit = 'illegal' RETURN ENDIF !-- first process diractional 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_' ) THEN IF ( .NOT. radiation ) THEN message_string = 'output of "' // TRIM( var ) // '" require'& // 's radiation = .TRUE.' CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 ) ENDIF unit = 'W/m2' ELSE IF ( var(1:7) == 'rtm_svf' .OR. var(1:7) == 'rtm_dif' .OR. & var(1:9) == 'rtm_skyvf' .OR. var(1:9) == 'rtm_skyvft' .OR. & var(1:12) == 'rtm_surfalb_' .OR. var(1:13) == 'rtm_surfemis_' ) THEN IF ( .NOT. radiation ) THEN message_string = 'output of "' // TRIM( var ) // '" require'& // 's radiation = .TRUE.' CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 ) ENDIF unit = '1' ELSE !-- non-directional variables SELECT CASE ( TRIM( var ) ) CASE ( 'rad_lw_cs_hr', 'rad_lw_hr', 'rad_lw_in', 'rad_lw_out', & 'rad_sw_cs_hr', 'rad_sw_hr', 'rad_sw_in', 'rad_sw_out' ) IF ( .NOT. radiation .OR. radiation_scheme /= 'rrtmg' ) THEN message_string = '"output of "' // TRIM( var ) // '" requi' // & 'res radiation = .TRUE. and ' // & 'radiation_scheme = "rrtmg"' CALL message( 'check_parameters', 'PA0406', 1, 2, 0, 6, 0 ) ENDIF unit = 'K/h' CASE ( 'rad_net*', 'rrtm_aldif*', 'rrtm_aldir*', 'rrtm_asdif*', & 'rrtm_asdir*', 'rad_lw_in*', 'rad_lw_out*', 'rad_sw_in*', & 'rad_sw_out*') IF ( i == 0 .AND. ilen == 0 .AND. k == 0) THEN ! Workaround for masked output (calls with i=ilen=k=0) unit = 'illegal' RETURN ENDIF IF ( k == 0 .OR. data_output(i)(ilen-2:ilen) /= '_xy' ) THEN message_string = 'illegal value for data_output: "' // & TRIM( 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 IF ( TRIM( var ) == 'rrtm_aldif*' .OR. & TRIM( var ) == 'rrtm_aldir*' .OR. & TRIM( var ) == 'rrtm_asdif*' .OR. & TRIM( var ) == 'rrtm_asdir*' ) & THEN message_string = 'output of "' // TRIM( var ) // '" require'& // 's radiation = .TRUE. and radiation_sch'& // 'eme = "rrtmg"' CALL message( 'check_parameters', 'PA0409', 1, 2, 0, 6, 0 ) ENDIF ENDIF IF ( TRIM( var ) == 'rad_net*' ) unit = 'W/m2' IF ( TRIM( var ) == 'rad_lw_in*' ) unit = 'W/m2' IF ( TRIM( var ) == 'rad_lw_out*' ) unit = 'W/m2' IF ( TRIM( var ) == 'rad_sw_in*' ) unit = 'W/m2' IF ( TRIM( var ) == 'rad_sw_out*' ) unit = 'W/m2' IF ( TRIM( var ) == 'rad_sw_in' ) unit = 'W/m2' IF ( TRIM( var ) == 'rrtm_aldif*' ) unit = '' IF ( TRIM( var ) == 'rrtm_aldir*' ) unit = '' IF ( TRIM( var ) == 'rrtm_asdif*' ) unit = '' IF ( TRIM( var ) == 'rrtm_asdir*' ) 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 "' // TRIM( var ) // '" require'& // 's 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 ( i == 0 .AND. ilen == 0 .AND. k == 0) THEN ! Workaround for masked output (calls with i=ilen=k=0) unit = 'illegal' RETURN ENDIF IF ( .NOT. radiation ) THEN message_string = 'output of "' // TRIM( var ) // '" require'& // 's radiation = .TRUE.' CALL message( 'check_parameters', 'PA0509', 1, 2, 0, 6, 0 ) ENDIF IF ( mrt_nlevels == 0 ) THEN message_string = 'output of "' // TRIM( var ) // '" require'& // 's mrt_nlevels > 0' CALL message( 'check_parameters', 'PA0510', 1, 2, 0, 6, 0 ) ENDIF IF ( TRIM( var ) == 'rtm_mrt_sw' .AND. .NOT. mrt_include_sw ) THEN message_string = 'output of "' // TRIM( var ) // '" require'& // 's rtm_mrt_sw = .TRUE.' CALL message( 'check_parameters', 'PA0511', 1, 2, 0, 6, 0 ) ENDIF IF ( TRIM( var ) == 'rtm_mrt' ) THEN unit = 'K' ELSE unit = 'W m-2' ENDIF CASE DEFAULT unit = 'illegal' END SELECT ENDIF 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=*) :: unit !< CHARACTER (LEN=*) :: variable !< CHARACTER (LEN=*) :: dopr_unit !< local value of dopr_unit 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, rotation_angle, 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 make 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( '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( '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( '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( '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( '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( 'check_parameters', 'PA0411', 1, 2, 0, 6, 0 ) ENDIF ENDIF ! !-- Parallel rad_angular_discretization without raytrace_mpi_rma is not implemented #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( 'check_parameters', 'PA0486', 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( 'check_parameters', 'PA0560', 1, 2, 0, 6, 0 ) ENDIF ! !-- Incialize 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( 'check_parameters', 'PA0591', 1, 2, 0, 6, 0 ) ENDIF ! !-- Check rotation angle !> @todo Remove this limitation IF ( rotation_angle /= 0.0 ) THEN message_string = 'rotation of the model domain is not considered in the radiation ' // & 'model.&Using rotation_angle /= 0.0 is not allowed in combination ' // & 'with the radiation model at the moment!' CALL message( 'check_parameters', 'PA0675', 1, 2, 0, 6, 0 ) ENDIF END SUBROUTINE radiation_check_parameters !------------------------------------------------------------------------------! ! Description: ! ------------ !> Initialization of the radiation model and Radiative Transfer Model !------------------------------------------------------------------------------! SUBROUTINE radiation_init 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( 'init_3d_model', 'PA0348', 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 IF ( .NOT. ALLOCATED ( surf_lsm_h%rad_net ) .AND. & surf_lsm_h%ns > 0 ) THEN ALLOCATE( surf_lsm_h%rad_net(1:surf_lsm_h%ns) ) surf_lsm_h%rad_net = 0.0_wp ENDIF IF ( .NOT. ALLOCATED ( surf_usm_h%rad_net ) .AND. & surf_usm_h%ns > 0 ) THEN ALLOCATE( surf_usm_h%rad_net(1:surf_usm_h%ns) ) surf_usm_h%rad_net = 0.0_wp ENDIF 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 IF ( .NOT. ALLOCATED ( surf_lsm_h%rad_lw_out_change_0 ) .AND. & surf_lsm_h%ns > 0 ) THEN ALLOCATE( surf_lsm_h%rad_lw_out_change_0(1:surf_lsm_h%ns) ) surf_lsm_h%rad_lw_out_change_0 = 0.0_wp ENDIF IF ( .NOT. ALLOCATED ( surf_usm_h%rad_lw_out_change_0 ) .AND. & surf_usm_h%ns > 0 ) THEN ALLOCATE( surf_usm_h%rad_lw_out_change_0(1:surf_usm_h%ns) ) surf_usm_h%rad_lw_out_change_0 = 0.0_wp ENDIF 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 IF ( .NOT. ALLOCATED ( surf_lsm_h%rad_sw_in ) .AND. & surf_lsm_h%ns > 0 ) THEN ALLOCATE( surf_lsm_h%rad_sw_in(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_sw_out(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_sw_dir(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_sw_dif(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_sw_ref(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_sw_res(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_lw_in(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_lw_out(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_lw_dif(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_lw_ref(1:surf_lsm_h%ns) ) ALLOCATE( surf_lsm_h%rad_lw_res(1:surf_lsm_h%ns) ) surf_lsm_h%rad_sw_in = 0.0_wp surf_lsm_h%rad_sw_out = 0.0_wp surf_lsm_h%rad_sw_dir = 0.0_wp surf_lsm_h%rad_sw_dif = 0.0_wp surf_lsm_h%rad_sw_ref = 0.0_wp surf_lsm_h%rad_sw_res = 0.0_wp surf_lsm_h%rad_lw_in = 0.0_wp surf_lsm_h%rad_lw_out = 0.0_wp surf_lsm_h%rad_lw_dif = 0.0_wp surf_lsm_h%rad_lw_ref = 0.0_wp surf_lsm_h%rad_lw_res = 0.0_wp ENDIF IF ( .NOT. ALLOCATED ( surf_usm_h%rad_sw_in ) .AND. & surf_usm_h%ns > 0 ) THEN ALLOCATE( surf_usm_h%rad_sw_in(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_sw_out(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_sw_dir(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_sw_dif(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_sw_ref(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_sw_res(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_lw_in(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_lw_out(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_lw_dif(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_lw_ref(1:surf_usm_h%ns) ) ALLOCATE( surf_usm_h%rad_lw_res(1:surf_usm_h%ns) ) surf_usm_h%rad_sw_in = 0.0_wp surf_usm_h%rad_sw_out = 0.0_wp surf_usm_h%rad_sw_dir = 0.0_wp surf_usm_h%rad_sw_dif = 0.0_wp surf_usm_h%rad_sw_ref = 0.0_wp surf_usm_h%rad_sw_res = 0.0_wp surf_usm_h%rad_lw_in = 0.0_wp surf_usm_h%rad_lw_out = 0.0_wp surf_usm_h%rad_lw_dif = 0.0_wp surf_usm_h%rad_lw_ref = 0.0_wp surf_usm_h%rad_lw_res = 0.0_wp ENDIF 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 IF ( ALLOCATED( surf_lsm_h%rad_net ) ) & surf_lsm_h%rad_net = net_radiation IF ( ALLOCATED( surf_usm_h%rad_net ) ) & surf_usm_h%rad_net = net_radiation ! !-- 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) ) ENDIF IF ( .NOT. ALLOCATED ( rad_sw_out ) ) THEN ALLOCATE ( rad_sw_out(0:0,nysg:nyng,nxlg:nxrg) ) ENDIF IF ( .NOT. ALLOCATED ( rad_lw_in ) ) THEN ALLOCATE ( rad_lw_in(0:0,nysg:nyng,nxlg:nxrg) ) ENDIF IF ( .NOT. ALLOCATED ( rad_lw_out ) ) THEN ALLOCATE ( rad_lw_out(0:0,nysg:nyng,nxlg:nxrg) ) 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. IF ( .NOT. ALLOCATED(surf_lsm_h%albedo) ) THEN ALLOCATE( surf_lsm_h%albedo(0:2,1:surf_lsm_h%ns) ) surf_lsm_h%albedo = albedo ENDIF IF ( .NOT. ALLOCATED(surf_usm_h%albedo) ) THEN ALLOCATE( surf_usm_h%albedo(0:2,1:surf_usm_h%ns) ) surf_usm_h%albedo = albedo ENDIF DO l = 0, 3 IF ( .NOT. ALLOCATED( surf_lsm_v(l)%albedo ) ) THEN ALLOCATE( surf_lsm_v(l)%albedo(0:2,1:surf_lsm_v(l)%ns) ) surf_lsm_v(l)%albedo = albedo ENDIF IF ( .NOT. ALLOCATED( surf_usm_v(l)%albedo ) ) THEN ALLOCATE( surf_usm_v(l)%albedo(0:2,1:surf_usm_v(l)%ns) ) 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 m = 1, surf_lsm_h%ns IF ( surf_lsm_h%albedo_type(ind_veg_wall,m) /= 0 ) & surf_lsm_h%albedo(ind_veg_wall,m) = & albedo_pars(0,surf_lsm_h%albedo_type(ind_veg_wall,m)) IF ( surf_lsm_h%albedo_type(ind_pav_green,m) /= 0 ) & surf_lsm_h%albedo(ind_pav_green,m) = & albedo_pars(0,surf_lsm_h%albedo_type(ind_pav_green,m)) IF ( surf_lsm_h%albedo_type(ind_wat_win,m) /= 0 ) & surf_lsm_h%albedo(ind_wat_win,m) = & albedo_pars(0,surf_lsm_h%albedo_type(ind_wat_win,m)) ENDDO DO m = 1, surf_usm_h%ns IF ( surf_usm_h%albedo_type(ind_veg_wall,m) /= 0 ) & surf_usm_h%albedo(ind_veg_wall,m) = & albedo_pars(0,surf_usm_h%albedo_type(ind_veg_wall,m)) IF ( surf_usm_h%albedo_type(ind_pav_green,m) /= 0 ) & surf_usm_h%albedo(ind_pav_green,m) = & albedo_pars(0,surf_usm_h%albedo_type(ind_pav_green,m)) IF ( surf_usm_h%albedo_type(ind_wat_win,m) /= 0 ) & surf_usm_h%albedo(ind_wat_win,m) = & albedo_pars(0,surf_usm_h%albedo_type(ind_wat_win,m)) ENDDO DO l = 0, 3 DO m = 1, surf_lsm_v(l)%ns IF ( surf_lsm_v(l)%albedo_type(ind_veg_wall,m) /= 0 ) & surf_lsm_v(l)%albedo(ind_veg_wall,m) = & albedo_pars(0,surf_lsm_v(l)%albedo_type(ind_veg_wall,m)) IF ( surf_lsm_v(l)%albedo_type(ind_pav_green,m) /= 0 ) & surf_lsm_v(l)%albedo(ind_pav_green,m) = & albedo_pars(0,surf_lsm_v(l)%albedo_type(ind_pav_green,m)) IF ( surf_lsm_v(l)%albedo_type(ind_wat_win,m) /= 0 ) & surf_lsm_v(l)%albedo(ind_wat_win,m) = & albedo_pars(0,surf_lsm_v(l)%albedo_type(ind_wat_win,m)) ENDDO DO m = 1, surf_usm_v(l)%ns IF ( surf_usm_v(l)%albedo_type(ind_veg_wall,m) /= 0 ) & surf_usm_v(l)%albedo(ind_veg_wall,m) = & albedo_pars(0,surf_usm_v(l)%albedo_type(ind_veg_wall,m)) IF ( surf_usm_v(l)%albedo_type(ind_pav_green,m) /= 0 ) & surf_usm_v(l)%albedo(ind_pav_green,m) = & albedo_pars(0,surf_usm_v(l)%albedo_type(ind_pav_green,m)) IF ( surf_usm_v(l)%albedo_type(ind_wat_win,m) /= 0 ) & surf_usm_v(l)%albedo(ind_wat_win,m) = & albedo_pars(0,surf_usm_v(l)%albedo_type(ind_wat_win,m)) ENDDO ENDDO ! !-- Level 3 initialization at grid points where albedo type is zero. !-- 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 m = 1, surf_lsm_h%ns i = surf_lsm_h%i(m) j = surf_lsm_h%j(m) IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) THEN surf_lsm_h%albedo(ind_veg_wall,m) = albedo_pars_f%pars_xy(0,j,i) surf_lsm_h%albedo(ind_pav_green,m) = albedo_pars_f%pars_xy(0,j,i) surf_lsm_h%albedo(ind_wat_win,m) = albedo_pars_f%pars_xy(0,j,i) ENDIF ENDDO DO m = 1, surf_usm_h%ns i = surf_usm_h%i(m) j = surf_usm_h%j(m) IF ( albedo_pars_f%pars_xy(0,j,i) /= albedo_pars_f%fill ) THEN surf_usm_h%albedo(ind_veg_wall,m) = albedo_pars_f%pars_xy(0,j,i) surf_usm_h%albedo(ind_pav_green,m) = albedo_pars_f%pars_xy(0,j,i) surf_usm_h%albedo(ind_wat_win,m) = albedo_pars_f%pars_xy(0,j,i) ENDIF 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(ind_veg_wall,m) = albedo_pars_f%pars_xy(0,j,i) surf_lsm_v(l)%albedo(ind_pav_green,m) = albedo_pars_f%pars_xy(0,j,i) surf_lsm_v(l)%albedo(ind_wat_win,m) = 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(ind_veg_wall,m) = albedo_pars_f%pars_xy(0,j,i) surf_usm_v(l)%albedo(ind_pav_green,m) = albedo_pars_f%pars_xy(0,j,i) surf_usm_v(l)%albedo(ind_wat_win,m) = 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 a albedo_type !-- to zero in order to take effect. IF ( building_surface_pars_f%from_file ) THEN DO m = 1, surf_usm_h%ns i = surf_usm_h%i(m) j = surf_usm_h%j(m) k = surf_usm_h%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%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%albedo(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_b_wall,is) surf_usm_h%albedo_type(ind_veg_wall,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_b_win,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%albedo(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_b_win,is) surf_usm_h%albedo_type(ind_wat_win,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_b_green,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%albedo(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_b_green,is) surf_usm_h%albedo_type(ind_pav_green,m) = 0 ENDIF EXIT ! surface was found and processed ENDIF 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(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_b_wall,is) surf_usm_v(l)%albedo_type(ind_veg_wall,m) = 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(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_b_win,is) surf_usm_v(l)%albedo_type(ind_wat_win,m) = 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(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_b_green,is) surf_usm_v(l)%albedo_type(ind_pav_green,m) = 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). ALLOCATE ( surf_lsm_h%aldif(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_lsm_h%aldir(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_lsm_h%asdif(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_lsm_h%asdir(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_lsm_h%rrtm_aldif(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_lsm_h%rrtm_aldir(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_lsm_h%rrtm_asdif(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_lsm_h%rrtm_asdir(0:2,1:surf_lsm_h%ns) ) ALLOCATE ( surf_usm_h%aldif(0:2,1:surf_usm_h%ns) ) ALLOCATE ( surf_usm_h%aldir(0:2,1:surf_usm_h%ns) ) ALLOCATE ( surf_usm_h%asdif(0:2,1:surf_usm_h%ns) ) ALLOCATE ( surf_usm_h%asdir(0:2,1:surf_usm_h%ns) ) ALLOCATE ( surf_usm_h%rrtm_aldif(0:2,1:surf_usm_h%ns) ) ALLOCATE ( surf_usm_h%rrtm_aldir(0:2,1:surf_usm_h%ns) ) ALLOCATE ( surf_usm_h%rrtm_asdif(0:2,1:surf_usm_h%ns) ) ALLOCATE ( surf_usm_h%rrtm_asdir(0:2,1:surf_usm_h%ns) ) ! !-- Allocate broadband albedo (temporary for the current radiation !-- implementations) IF ( .NOT. ALLOCATED(surf_lsm_h%albedo) ) & ALLOCATE( surf_lsm_h%albedo(0:2,1:surf_lsm_h%ns) ) IF ( .NOT. ALLOCATED(surf_usm_h%albedo) ) & ALLOCATE( surf_usm_h%albedo(0:2,1:surf_usm_h%ns) ) ! !-- Allocate albedos for short/longwave radiation, vertical surfaces DO l = 0, 3 ALLOCATE ( surf_lsm_v(l)%aldif(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_lsm_v(l)%aldir(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_lsm_v(l)%asdif(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_lsm_v(l)%asdir(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_lsm_v(l)%rrtm_aldif(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_lsm_v(l)%rrtm_aldir(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_lsm_v(l)%rrtm_asdif(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_lsm_v(l)%rrtm_asdir(0:2,1:surf_lsm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%aldif(0:2,1:surf_usm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%aldir(0:2,1:surf_usm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%asdif(0:2,1:surf_usm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%asdir(0:2,1:surf_usm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%rrtm_aldif(0:2,1:surf_usm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%rrtm_aldir(0:2,1:surf_usm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%rrtm_asdif(0:2,1:surf_usm_v(l)%ns) ) ALLOCATE ( surf_usm_v(l)%rrtm_asdir(0:2,1:surf_usm_v(l)%ns) ) ! !-- Allocate broadband albedo (temporary for the current radiation !-- implementations) IF ( .NOT. ALLOCATED( surf_lsm_v(l)%albedo ) ) & ALLOCATE( surf_lsm_v(l)%albedo(0:2,1:surf_lsm_v(l)%ns) ) IF ( .NOT. ALLOCATED( surf_usm_v(l)%albedo ) ) & ALLOCATE( surf_usm_v(l)%albedo(0:2,1:surf_usm_v(l)%ns) ) ENDDO ! !-- Level 1 initialization of spectral albedos via namelist !-- paramters. Please note, this case all surface tiles are initialized !-- the same. IF ( surf_lsm_h%ns > 0 ) THEN surf_lsm_h%aldif = albedo_lw_dif surf_lsm_h%aldir = albedo_lw_dir surf_lsm_h%asdif = albedo_sw_dif surf_lsm_h%asdir = albedo_sw_dir surf_lsm_h%albedo = albedo_sw_dif ENDIF IF ( surf_usm_h%ns > 0 ) THEN IF ( surf_usm_h%albedo_from_ascii ) THEN surf_usm_h%aldif = surf_usm_h%albedo surf_usm_h%aldir = surf_usm_h%albedo surf_usm_h%asdif = surf_usm_h%albedo surf_usm_h%asdir = surf_usm_h%albedo ELSE surf_usm_h%aldif = albedo_lw_dif surf_usm_h%aldir = albedo_lw_dir surf_usm_h%asdif = albedo_sw_dif surf_usm_h%asdir = albedo_sw_dir surf_usm_h%albedo = albedo_sw_dif ENDIF ENDIF 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 m = 1, surf_lsm_h%ns ! !-- Spectral albedos for vegetation/pavement/water surfaces DO ind_type = 0, 2 IF ( surf_lsm_h%albedo_type(ind_type,m) /= 0 ) THEN surf_lsm_h%aldif(ind_type,m) = & albedo_pars(1,surf_lsm_h%albedo_type(ind_type,m)) surf_lsm_h%asdif(ind_type,m) = & albedo_pars(2,surf_lsm_h%albedo_type(ind_type,m)) surf_lsm_h%aldir(ind_type,m) = & albedo_pars(1,surf_lsm_h%albedo_type(ind_type,m)) surf_lsm_h%asdir(ind_type,m) = & albedo_pars(2,surf_lsm_h%albedo_type(ind_type,m)) surf_lsm_h%albedo(ind_type,m) = & albedo_pars(0,surf_lsm_h%albedo_type(ind_type,m)) 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%albedo_from_ascii ) THEN DO m = 1, surf_usm_h%ns ! !-- Spectral albedos for wall/green/window surfaces DO ind_type = 0, 2 IF ( surf_usm_h%albedo_type(ind_type,m) /= 0 ) THEN surf_usm_h%aldif(ind_type,m) = & albedo_pars(1,surf_usm_h%albedo_type(ind_type,m)) surf_usm_h%asdif(ind_type,m) = & albedo_pars(2,surf_usm_h%albedo_type(ind_type,m)) surf_usm_h%aldir(ind_type,m) = & albedo_pars(1,surf_usm_h%albedo_type(ind_type,m)) surf_usm_h%asdir(ind_type,m) = & albedo_pars(2,surf_usm_h%albedo_type(ind_type,m)) surf_usm_h%albedo(ind_type,m) = & albedo_pars(0,surf_usm_h%albedo_type(ind_type,m)) ENDIF ENDDO ENDDO ENDIF 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(ind_type,m) /= 0 ) THEN surf_lsm_v(l)%aldif(ind_type,m) = & albedo_pars(1,surf_lsm_v(l)%albedo_type(ind_type,m)) surf_lsm_v(l)%asdif(ind_type,m) = & albedo_pars(2,surf_lsm_v(l)%albedo_type(ind_type,m)) surf_lsm_v(l)%aldir(ind_type,m) = & albedo_pars(1,surf_lsm_v(l)%albedo_type(ind_type,m)) surf_lsm_v(l)%asdir(ind_type,m) = & albedo_pars(2,surf_lsm_v(l)%albedo_type(ind_type,m)) surf_lsm_v(l)%albedo(ind_type,m) = & albedo_pars(0,surf_lsm_v(l)%albedo_type(ind_type,m)) 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(ind_type,m) /= 0 ) THEN surf_usm_v(l)%aldif(ind_type,m) = & albedo_pars(1,surf_usm_v(l)%albedo_type(ind_type,m)) surf_usm_v(l)%asdif(ind_type,m) = & albedo_pars(2,surf_usm_v(l)%albedo_type(ind_type,m)) surf_usm_v(l)%aldir(ind_type,m) = & albedo_pars(1,surf_usm_v(l)%albedo_type(ind_type,m)) surf_usm_v(l)%asdir(ind_type,m) = & albedo_pars(2,surf_usm_v(l)%albedo_type(ind_type,m)) surf_usm_v(l)%albedo(ind_type,m) = & albedo_pars(0,surf_usm_v(l)%albedo_type(ind_type,m)) 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 m = 1, surf_lsm_h%ns i = surf_lsm_h%i(m) j = surf_lsm_h%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%albedo(ind_type,m) = & albedo_pars_f%pars_xy(0,j,i) IF ( albedo_pars_f%pars_xy(1,j,i) /= albedo_pars_f%fill ) & surf_lsm_h%aldir(ind_type,m) = & albedo_pars_f%pars_xy(1,j,i) IF ( albedo_pars_f%pars_xy(1,j,i) /= albedo_pars_f%fill ) & surf_lsm_h%aldif(ind_type,m) = & albedo_pars_f%pars_xy(1,j,i) IF ( albedo_pars_f%pars_xy(2,j,i) /= albedo_pars_f%fill ) & surf_lsm_h%asdir(ind_type,m) = & albedo_pars_f%pars_xy(2,j,i) IF ( albedo_pars_f%pars_xy(2,j,i) /= albedo_pars_f%fill ) & surf_lsm_h%asdif(ind_type,m) = & 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%albedo_from_ascii ) THEN DO m = 1, surf_usm_h%ns i = surf_usm_h%i(m) j = surf_usm_h%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%albedo(ind_type,m) = & 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%aldir(ind_veg_wall,m) = & albedo_pars_f%pars_xy(1,j,i) surf_usm_h%aldif(ind_veg_wall,m) = & 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%asdir(ind_veg_wall,m) = & albedo_pars_f%pars_xy(2,j,i) surf_usm_h%asdif(ind_veg_wall,m) = & 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%aldir(ind_pav_green,m) = & albedo_pars_f%pars_xy(3,j,i) surf_usm_h%aldif(ind_pav_green,m) = & 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%asdir(ind_pav_green,m) = & albedo_pars_f%pars_xy(4,j,i) surf_usm_h%asdif(ind_pav_green,m) = & 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%aldir(ind_wat_win,m) = & albedo_pars_f%pars_xy(5,j,i) surf_usm_h%aldif(ind_wat_win,m) = & 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%asdir(ind_wat_win,m) = & albedo_pars_f%pars_xy(6,j,i) surf_usm_h%asdif(ind_wat_win,m) = & albedo_pars_f%pars_xy(6,j,i) ENDIF ENDDO ENDIF ! !-- 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(ind_type,m) = & 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(ind_type,m) = & 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(ind_type,m) = & 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(ind_type,m) = & 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(ind_type,m) = & 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(ind_type,m) = & 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(ind_veg_wall,m) = & albedo_pars_f%pars_xy(1,j+joff,i+ioff) surf_usm_v(l)%aldif(ind_veg_wall,m) = & 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(ind_veg_wall,m) = & albedo_pars_f%pars_xy(2,j+joff,i+ioff) surf_usm_v(l)%asdif(ind_veg_wall,m) = & 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(ind_pav_green,m) = & albedo_pars_f%pars_xy(3,j+joff,i+ioff) surf_usm_v(l)%aldif(ind_pav_green,m) = & 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(ind_pav_green,m) = & albedo_pars_f%pars_xy(4,j+joff,i+ioff) surf_usm_v(l)%asdif(ind_pav_green,m) = & 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(ind_wat_win,m) = & albedo_pars_f%pars_xy(5,j+joff,i+ioff) surf_usm_v(l)%aldif(ind_wat_win,m) = & 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(ind_wat_win,m) = & albedo_pars_f%pars_xy(6,j+joff,i+ioff) surf_usm_v(l)%asdif(ind_wat_win,m) = & 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 a albedo_type !-- to zero in order to take effect. IF ( building_surface_pars_f%from_file ) THEN DO m = 1, surf_usm_h%ns i = surf_usm_h%i(m) j = surf_usm_h%j(m) k = surf_usm_h%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%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%albedo(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_b_wall,is) surf_usm_h%albedo_type(ind_veg_wall,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_l_wall,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%aldir(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_l_wall,is) surf_usm_h%aldif(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_l_wall,is) surf_usm_h%albedo_type(ind_veg_wall,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_s_wall,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%asdir(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_s_wall,is) surf_usm_h%asdif(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_s_wall,is) surf_usm_h%albedo_type(ind_veg_wall,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_b_win,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%albedo(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_b_win,is) surf_usm_h%albedo_type(ind_wat_win,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_l_win,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%aldir(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_l_win,is) surf_usm_h%aldif(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_l_win,is) surf_usm_h%albedo_type(ind_wat_win,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_s_win,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%asdir(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_s_win,is) surf_usm_h%asdif(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_s_win,is) surf_usm_h%albedo_type(ind_wat_win,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_b_green,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%albedo(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_b_green,is) surf_usm_h%albedo_type(ind_pav_green,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_l_green,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%aldir(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_l_green,is) surf_usm_h%aldif(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_l_green,is) surf_usm_h%albedo_type(ind_pav_green,m) = 0 ENDIF IF ( building_surface_pars_f%pars(ind_s_alb_s_green,is) /= & building_surface_pars_f%fill ) THEN surf_usm_h%asdir(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_s_green,is) surf_usm_h%asdif(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_s_green,is) surf_usm_h%albedo_type(ind_pav_green,m) = 0 ENDIF EXIT ! surface was found and processed ENDIF 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(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_b_wall,is) surf_usm_v(l)%albedo_type(ind_veg_wall,m) = 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(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_l_wall,is) surf_usm_v(l)%aldif(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_l_wall,is) surf_usm_v(l)%albedo_type(ind_veg_wall,m) = 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(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_s_wall,is) surf_usm_v(l)%asdif(ind_veg_wall,m) = & building_surface_pars_f%pars(ind_s_alb_s_wall,is) surf_usm_v(l)%albedo_type(ind_veg_wall,m) = 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(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_b_win,is) surf_usm_v(l)%albedo_type(ind_wat_win,m) = 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(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_l_win,is) surf_usm_v(l)%aldif(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_l_win,is) surf_usm_v(l)%albedo_type(ind_wat_win,m) = 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(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_s_win,is) surf_usm_v(l)%asdif(ind_wat_win,m) = & building_surface_pars_f%pars(ind_s_alb_s_win,is) surf_usm_v(l)%albedo_type(ind_wat_win,m) = 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(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_b_green,is) surf_usm_v(l)%albedo_type(ind_pav_green,m) = 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(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_l_green,is) surf_usm_v(l)%aldif(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_l_green,is) surf_usm_v(l)%albedo_type(ind_pav_green,m) = 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(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_s_green,is) surf_usm_v(l)%asdif(ind_pav_green,m) = & building_surface_pars_f%pars(ind_s_alb_s_green,is) surf_usm_v(l)%albedo_type(ind_pav_green,m) = 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 CALL calc_albedo( surf_lsm_h ) CALL calc_albedo( surf_usm_h ) ! !-- 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 IF ( surf_lsm_h%ns > 0 ) THEN surf_lsm_h%rrtm_aldir = surf_lsm_h%aldir surf_lsm_h%rrtm_asdir = surf_lsm_h%asdir surf_lsm_h%rrtm_aldif = surf_lsm_h%aldif surf_lsm_h%rrtm_asdif = surf_lsm_h%asdif ENDIF IF ( surf_usm_h%ns > 0 ) THEN surf_usm_h%rrtm_aldir = surf_usm_h%aldir surf_usm_h%rrtm_asdir = surf_usm_h%asdir surf_usm_h%rrtm_aldif = surf_usm_h%aldif surf_usm_h%rrtm_asdif = surf_usm_h%asdif ENDIF ! !-- 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.nc', EXIST=lw_exists ) IF ( .NOT. lw_exists ) THEN message_string = 'Input file rrtmg_lw.nc' // & '&for rrtmg missing. ' // & '&Please provide _lsw file in the INPUT directory.' CALL message( 'radiation_init', 'PA0583', 1, 2, 0, 6, 0 ) ENDIF INQUIRE( FILE='rrtmg_sw.nc', EXIST=sw_exists ) IF ( .NOT. sw_exists ) THEN message_string = 'Input file rrtmg_sw.nc' // & '&for rrtmg missing. ' // & '&Please provide _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.nc" 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 do 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 ! !-- Find all discretized apparent solar positions for radiation interaction. IF ( radiation_interactions ) CALL radiation_presimulate_solar_pos ! !-- If required, read or calculate and write out the SVF IF ( radiation_interactions .AND. read_svf) THEN ! !-- Read sky-view factors and further required data from file CALL radiation_read_svf() ELSEIF ( radiation_interactions .AND. .NOT. read_svf) THEN ! !-- calculate SFV and CSF CALL radiation_calc_svf() ENDIF IF ( radiation_interactions .AND. 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. IF ( radiation_interactions ) THEN CALL radiation_interaction ENDIF IF ( debug_output ) CALL debug_message( 'radiation_init', 'end' ) RETURN !todo: remove, I don't see what we need this for here END SUBROUTINE radiation_init !------------------------------------------------------------------------------! ! Description: ! ------------ !> A simple clear sky radiation model !------------------------------------------------------------------------------! 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 ) & / ( 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. surf => surf_lsm_h CALL radiation_external_surf surf => surf_usm_h CALL radiation_external_surf 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 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(ind_veg_wall,m) * & surf%albedo(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%albedo(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%albedo(ind_wat_win,m) ) & * surf%rad_sw_in(m) surf%rad_lw_out(m) = ( surf%frac(ind_veg_wall,m) * & surf%emissivity(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%emissivity(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%emissivity(ind_wat_win,m) & ) & * sigma_sb & * ( surf%pt_surface(m) * exner(k) )**4 surf%rad_lw_out_change_0(m) = & ( surf%frac(ind_veg_wall,m) * & surf%emissivity(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%emissivity(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%emissivity(ind_wat_win,m) & ) * 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(ind_veg_wall,m) * & surf%albedo(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%albedo(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%albedo(ind_wat_win,m) ) & * surf%rad_sw_in(m) surf%rad_lw_out(m) = ( surf%frac(ind_veg_wall,m) * & surf%emissivity(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%emissivity(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%emissivity(ind_wat_win,m) & ) & * sigma_sb & * ( surf%pt_surface(m) * exner(k) )**4 surf%rad_lw_out_change_0(m) = & ( surf%frac(ind_veg_wall,m) * & surf%emissivity(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%emissivity(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%emissivity(ind_wat_win,m) & ) * 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. surf => surf_lsm_h CALL radiation_clearsky_surf surf => surf_usm_h CALL radiation_clearsky_surf 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 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(ind_veg_wall,m) * & surf%albedo(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%albedo(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%albedo(ind_wat_win,m) ) & * surf%rad_sw_in(m) surf%rad_lw_out(m) = ( surf%frac(ind_veg_wall,m) * & surf%emissivity(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%emissivity(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%emissivity(ind_wat_win,m) & ) & * sigma_sb & * ( surf%pt_surface(m) * exner(nzb) )**4 surf%rad_lw_out_change_0(m) = & ( surf%frac(ind_veg_wall,m) * & surf%emissivity(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%emissivity(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%emissivity(ind_wat_win,m) & ) * 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. surf => surf_lsm_h CALL radiation_constant_surf surf => surf_usm_h CALL radiation_constant_surf 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 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 be this 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(ind_veg_wall,m) * & surf%emissivity(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%emissivity(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%emissivity(ind_wat_win,m) & ) & * 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(ind_veg_wall,m) * & surf%albedo(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%albedo(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%albedo(ind_wat_win,m) ) & ) surf%rad_sw_out(m) = ( surf%frac(ind_veg_wall,m) * & surf%albedo(ind_veg_wall,m) & + surf%frac(ind_pav_green,m) * & surf%albedo(ind_pav_green,m) & + surf%frac(ind_wat_win,m) * & surf%albedo(ind_wat_win,m) ) & * 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=80) :: line !< dummy string that contains the current line of the parameter file NAMELIST /radiation_par/ albedo, albedo_lw_dif, albedo_lw_dir, & albedo_sw_dif, albedo_sw_dir, albedo_type, & 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, sw_radiation, & unscheduled_radiation_calls NAMELIST /radiation_parameters/ albedo, albedo_lw_dif, albedo_lw_dir, & albedo_sw_dif, albedo_sw_dir, albedo_type, & 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, sw_radiation, & unscheduled_radiation_calls line = ' ' ! !-- Try to find radiation model namelist REWIND ( 11 ) line = ' ' DO WHILE ( INDEX( line, '&radiation_parameters' ) == 0 ) READ ( 11, '(A)', END=12 ) line ENDDO BACKSPACE ( 11 ) ! !-- Read user-defined namelist READ ( 11, radiation_parameters, ERR = 10 ) ! !-- Set flag that indicates that the radiation model is switched on radiation = .TRUE. GOTO 14 10 BACKSPACE( 11 ) READ( 11 , '(A)') line CALL parin_fail_message( 'radiation_parameters', line ) ! !-- Try to find old namelist 12 REWIND ( 11 ) line = ' ' DO WHILE ( INDEX( line, '&radiation_par' ) == 0 ) READ ( 11, '(A)', END=14 ) line ENDDO BACKSPACE ( 11 ) ! !-- Read user-defined namelist READ ( 11, radiation_par, ERR = 13, END = 14 ) message_string = 'namelist radiation_par is deprecated and will be ' // & 'removed in near future. Please use namelist ' // & 'radiation_parameters instead' CALL message( 'radiation_parin', 'PA0487', 0, 1, 0, 6, 0 ) ! !-- Set flag that indicates that the radiation model is switched on radiation = .TRUE. IF ( .NOT. radiation_interactions_on .AND. surface_reflections ) THEN message_string = 'surface_reflections is allowed only when ' // & 'radiation_interactions_on is set to TRUE' CALL message( 'radiation_parin', 'PA0293',1, 2, 0, 6, 0 ) ENDIF GOTO 14 13 BACKSPACE( 11 ) READ( 11 , '(A)') line CALL parin_fail_message( 'radiation_par', line ) 14 CONTINUE END SUBROUTINE radiation_parin !------------------------------------------------------------------------------! ! Description: ! ------------ !> Implementation of the RRTMG radiation_scheme !------------------------------------------------------------------------------! SUBROUTINE radiation_rrtmg #if defined ( __rrtmg ) 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:nzt+1) :: pt_av, q_av, ql_av REAL(wp), DIMENSION(0:0) :: zenith !< to provide indexed array ! !-- 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 CALL calc_albedo( surf_lsm_h ) CALL calc_albedo( surf_usm_h ) ! !-- 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 ) pt_av = hom(:, 1, 4, 0) IF ( humidity ) THEN CALL calc_mean_profile( q, 41 ) 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 ) ! 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 interpolate 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 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 give 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 k = nzb, nzt+1 rad_lw_in(k,:,:) = rrtm_lwdflx(0,k) rad_lw_out(k,:,:) = rrtm_lwuflx(0,k) ENDDO rad_lw_in_diff(:,:) = rad_lw_in(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) * d_hours_day rad_lw_cs_hr(k,j,i) = rrtm_lwhrc(0,k-k_topo_l) * 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 give 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 k = nzb, nzt+1 rad_sw_in(k,:,:) = rrtm_swdflx(0,k) rad_sw_out(k,:,:) = rrtm_swuflx(0,k) 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 k = nzb+1, nzt+1 rad_sw_hr(k,:,:) = rrtm_swhr(0,k) * d_hours_day rad_sw_cs_hr(k,:,:) = rrtm_swhrc(0,k) * d_hours_day 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 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%start_index(j,i), surf_lsm_h%end_index(j,i) rrtm_tlev(0,nzb+1) = surf_lsm_h%pt_surface(m) * exner(nzb) ENDDO DO m = surf_usm_h%start_index(j,i), surf_usm_h%end_index(j,i) rrtm_tlev(0,nzb+1) = surf_usm_h%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 interpolate 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 ! !-- Calculete 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 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%start_index(j,i), surf_lsm_h%end_index(j,i) rrtm_emis = surf_lsm_h%frac(ind_veg_wall,m) * & surf_lsm_h%emissivity(ind_veg_wall,m) + & surf_lsm_h%frac(ind_pav_green,m) * & surf_lsm_h%emissivity(ind_pav_green,m) + & surf_lsm_h%frac(ind_wat_win,m) * & surf_lsm_h%emissivity(ind_wat_win,m) rrtm_tsfc = surf_lsm_h%pt_surface(m) * exner(nzb) ENDDO DO m = surf_usm_h%start_index(j,i), surf_usm_h%end_index(j,i) rrtm_emis = surf_usm_h%frac(ind_veg_wall,m) * & surf_usm_h%emissivity(ind_veg_wall,m) + & surf_usm_h%frac(ind_pav_green,m) * & surf_usm_h%emissivity(ind_pav_green,m) + & surf_usm_h%frac(ind_wat_win,m) * & surf_usm_h%emissivity(ind_wat_win,m) rrtm_tsfc = surf_usm_h%pt_surface(m) * exner(nzb) ENDDO ! !-- Obtain topography top index (lower bound of RRTMG) 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 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 give 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 m = surf_lsm_h%start_index(j,i), & surf_lsm_h%end_index(j,i) surf_lsm_h%rad_lw_in(m) = rrtm_lwdflx(0,k_topo) surf_lsm_h%rad_lw_out(m) = rrtm_lwuflx(0,k_topo) surf_lsm_h%rad_lw_out_change_0(m) = rrtm_lwuflx_dt(0,k_topo) ENDDO DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) surf_usm_h%rad_lw_in(m) = rrtm_lwdflx(0,k_topo) surf_usm_h%rad_lw_out(m) = rrtm_lwuflx(0,k_topo) surf_usm_h%rad_lw_out_change_0(m) = rrtm_lwuflx_dt(0,k_topo) 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 horizontal surfaces, as RRTMG is a single !-- column model !-- (Please note, only one loop will entered, controlled by !-- start-end index.) DO m = surf_lsm_h%start_index(j,i), & surf_lsm_h%end_index(j,i) rrtm_asdir(1) = SUM( surf_lsm_h%frac(:,m) * & surf_lsm_h%rrtm_asdir(:,m) ) rrtm_asdif(1) = SUM( surf_lsm_h%frac(:,m) * & surf_lsm_h%rrtm_asdif(:,m) ) rrtm_aldir(1) = SUM( surf_lsm_h%frac(:,m) * & surf_lsm_h%rrtm_aldir(:,m) ) rrtm_aldif(1) = SUM( surf_lsm_h%frac(:,m) * & surf_lsm_h%rrtm_aldif(:,m) ) ENDDO DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) rrtm_asdir(1) = SUM( surf_usm_h%frac(:,m) * & surf_usm_h%rrtm_asdir(:,m) ) rrtm_asdif(1) = SUM( surf_usm_h%frac(:,m) * & surf_usm_h%rrtm_asdif(:,m) ) rrtm_aldir(1) = SUM( surf_usm_h%frac(:,m) * & surf_usm_h%rrtm_aldir(:,m) ) rrtm_aldif(1) = SUM( surf_usm_h%frac(:,m) * & surf_usm_h%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 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 give 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 m = surf_lsm_h%start_index(j,i), & surf_lsm_h%end_index(j,i) surf_lsm_h%rad_sw_in(m) = rrtm_swdflx(0,k_topo) surf_lsm_h%rad_sw_out(m) = rrtm_swuflx(0,k_topo) ENDDO DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) surf_usm_h%rad_sw_in(m) = rrtm_swdflx(0,k_topo) surf_usm_h%rad_sw_out(m) = rrtm_swuflx(0,k_topo) 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 !-- !!!!!!!! ATTENSION !!!!!!!!!!!!!!! !-- Surface radiative fluxes should be also set to zero here !-- Save surface radiative fluxes onto respective surface elements !-- Horizontal surfaces DO m = surf_lsm_h%start_index(j,i), & surf_lsm_h%end_index(j,i) surf_lsm_h%rad_sw_in(m) = 0.0_wp surf_lsm_h%rad_sw_out(m) = 0.0_wp ENDDO DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) surf_usm_h%rad_sw_in(m) = 0.0_wp surf_usm_h%rad_sw_out(m) = 0.0_wp 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) = 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 m = 1, surf_lsm_h%ns surf_lsm_h%rad_net(m) = surf_lsm_h%rad_sw_in(m) & - surf_lsm_h%rad_sw_out(m) & + surf_lsm_h%rad_lw_in(m) & - surf_lsm_h%rad_lw_out(m) ENDDO DO m = 1, surf_usm_h%ns surf_usm_h%rad_net(m) = surf_usm_h%rad_sw_in(m) & - surf_usm_h%rad_sw_out(m) & + surf_usm_h%rad_lw_in(m) & - surf_usm_h%rad_lw_out(m) 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, 1 ) - 1 ! !-- Ocean IF ( surf%albedo_type(ind_type,m) == 1 ) THEN surf%rrtm_aldir(ind_type,m) = 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(ind_type,m) = surf%rrtm_aldir(ind_type,m) ! !-- Snow ELSEIF ( surf%albedo_type(ind_type,m) == 16 ) THEN IF ( cos_zenith < 0.5_wp ) THEN surf%rrtm_aldir(ind_type,m) = & 0.5_wp * ( 1.0_wp - surf%aldif(ind_type,m) ) & * ( ( 3.0_wp / ( 1.0_wp + 4.0_wp & * cos_zenith ) ) - 1.0_wp ) surf%rrtm_asdir(ind_type,m) = & 0.5_wp * ( 1.0_wp - surf%asdif(ind_type,m) ) & * ( ( 3.0_wp / ( 1.0_wp + 4.0_wp & * cos_zenith ) ) - 1.0_wp ) surf%rrtm_aldir(ind_type,m) = & MIN(0.98_wp, surf%rrtm_aldir(ind_type,m)) surf%rrtm_asdir(ind_type,m) = & MIN(0.98_wp, surf%rrtm_asdir(ind_type,m)) ELSE surf%rrtm_aldir(ind_type,m) = surf%aldif(ind_type,m) surf%rrtm_asdir(ind_type,m) = surf%asdif(ind_type,m) ENDIF ! !-- Sea ice ELSEIF ( surf%albedo_type(ind_type,m) == 15 ) THEN surf%rrtm_aldir(ind_type,m) = surf%aldif(ind_type,m) surf%rrtm_asdir(ind_type,m) = surf%asdif(ind_type,m) ! !-- Asphalt ELSEIF ( surf%albedo_type(ind_type,m) == 17 ) THEN surf%rrtm_aldir(ind_type,m) = surf%aldif(ind_type,m) surf%rrtm_asdir(ind_type,m) = surf%asdif(ind_type,m) ! !-- Bare soil ELSEIF ( surf%albedo_type(ind_type,m) == 18 ) THEN surf%rrtm_aldir(ind_type,m) = surf%aldif(ind_type,m) surf%rrtm_asdir(ind_type,m) = surf%asdif(ind_type,m) ! !-- Land surfaces ELSE SELECT CASE ( surf%albedo_type(ind_type,m) ) ! !-- Surface types with strong zenith dependence CASE ( 1, 2, 3, 4, 11, 12, 13 ) surf%rrtm_aldir(ind_type,m) = & surf%aldif(ind_type,m) * 1.4_wp / & ( 1.0_wp + 0.8_wp * cos_zenith ) surf%rrtm_asdir(ind_type,m) = & surf%asdif(ind_type,m) * 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(ind_type,m) = & surf%aldif(ind_type,m) * 1.1_wp / & ( 1.0_wp + 0.2_wp * cos_zenith ) surf%rrtm_asdir(ind_type,m) = & surf%asdif(ind_type,m) * 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(ind_type,m) = surf%aldif(ind_type,m) surf%rrtm_asdif(ind_type,m) = surf%asdif(ind_type,m) 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 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 ) USE indices, & ONLY: nxl, nxr, nyn, nys 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 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 rewriten 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, ll 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 INTEGER(iwp), DIMENSION(0:3) :: reorder = (/ 1, 0, 3, 2 /) REAL(wp), DIMENSION(3,3) :: mrot !< grid rotation matrix (zyx) REAL(wp), DIMENSION(3,0:nsurf_type):: vnorm !< face direction normal vectors (zyx) 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(0:nsurf_type) :: costheta !< direct irradiance factor of solar angle REAL(wp), DIMENSION(nz_urban_b:nz_urban_t) :: pchf_prep !< precalculated factor for canopy temperature tendency REAL(wp) :: pc_box_area, pc_abs_frac, pc_abs_eff REAL(wp) :: asrc !< area of source face REAL(wp) :: pcrad !< irradiance from plant canopy REAL(wp) :: pabsswl = 0.0_wp !< total absorbed SW radiation energy in local processor (W) REAL(wp) :: pabssw = 0.0_wp !< total absorbed SW radiation energy in all processors (W) REAL(wp) :: pabslwl = 0.0_wp !< total absorbed LW radiation energy in local processor (W) REAL(wp) :: pabslw = 0.0_wp !< total absorbed LW radiation energy in all processors (W) REAL(wp) :: pemitlwl = 0.0_wp !< total emitted LW radiation energy in all processors (W) REAL(wp) :: pemitlw = 0.0_wp !< total emitted LW radiation energy in all processors (W) REAL(wp) :: pinswl = 0.0_wp !< total received SW radiation energy in local processor (W) REAL(wp) :: pinsw = 0.0_wp !< total received SW radiation energy in all processor (W) REAL(wp) :: pinlwl = 0.0_wp !< total received LW radiation energy in local processor (W) REAL(wp) :: pinlw = 0.0_wp !< total received LW radiation energy in all processor (W) REAL(wp) :: emiss_sum_surfl !< sum of emissisivity of surfaces in local processor REAL(wp) :: emiss_sum_surf !< sum of emissisivity of surfaces in all processor REAL(wp) :: area_surfl !< total area of surfaces in local processor REAL(wp) :: area_surf !< total area of surfaces in all processor REAL(wp) :: area_hor !< total horizontal area of domain in all processor #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 ) CALL debug_message( 'radiation_interaction', 'start' ) 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 vnorm(1,:) = kdir(:) vnorm(2,:) = jdir(:) vnorm(3,:) = idir(:) mrot(1, :) = (/ 1._wp, 0._wp, 0._wp /) mrot(2, :) = (/ 0._wp, COS(rotation_angle), SIN(rotation_angle) /) mrot(3, :) = (/ 0._wp, -SIN(rotation_angle), COS(rotation_angle) /) sunorig = (/ cos_zenith, sun_dir_lat, sun_dir_lon /) sunorig = MATMUL(mrot, sunorig) DO d = 0, nsurf_type costheta(d) = DOT_PRODUCT(sunorig, vnorm(:,d)) 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 need 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: direct + diffuse irradiance + thermal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! surfinswdir = 0._wp !nsurfl surfins = 0._wp !nsurfl surfinl = 0._wp !nsurfl surfoutsl(:) = 0.0_wp !start-end surfoutll(:) = 0.0_wp !start-end IF ( nmrtbl > 0 ) THEN mrtinsw(:) = 0._wp mrtinlw(:) = 0._wp ENDIF surfinlg(:) = 0._wp !global !-- Set up thermal radiation from surfaces !-- emiss_surf is defined only for surfaces for which energy balance is calculated !-- Workaround: reorder surface data type back on 1D array including all surfaces, !-- which implies to reorder horizontal and vertical surfaces ! !-- Horizontal walls mm = 1 DO i = nxl, nxr DO j = nys, nyn !-- urban DO m = surf_usm_h%start_index(j,i), surf_usm_h%end_index(j,i) surfoutll(mm) = SUM ( surf_usm_h%frac(:,m) * & surf_usm_h%emissivity(:,m) ) & * sigma_sb & * surf_usm_h%pt_surface(m)**4 albedo_surf(mm) = SUM ( surf_usm_h%frac(:,m) * & surf_usm_h%albedo(:,m) ) emiss_surf(mm) = SUM ( surf_usm_h%frac(:,m) * & surf_usm_h%emissivity(:,m) ) mm = mm + 1 ENDDO !-- land DO m = surf_lsm_h%start_index(j,i), surf_lsm_h%end_index(j,i) surfoutll(mm) = SUM ( surf_lsm_h%frac(:,m) * & surf_lsm_h%emissivity(:,m) ) & * sigma_sb & * surf_lsm_h%pt_surface(m)**4 albedo_surf(mm) = SUM ( surf_lsm_h%frac(:,m) * & surf_lsm_h%albedo(:,m) ) emiss_surf(mm) = SUM ( surf_lsm_h%frac(:,m) * & surf_lsm_h%emissivity(:,m) ) mm = mm + 1 ENDDO ENDDO ENDDO ! !-- Vertical walls DO i = nxl, nxr DO j = nys, nyn DO ll = 0, 3 l = reorder(ll) !-- 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._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 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 surfinl(isurf) = surfinl(isurf) + svf(1,isvf) * svf(2,isvf) * surfoutl(isurfsrc) ELSE surfinl(isurf) = surfinl(isurf) + svf(1,isvf) * surfoutl(isurfsrc) ENDIF ENDDO ENDIF ! !-- diffuse radiation using sky view factor DO isurf = 1, nsurfl j = surfl(iy, isurf) i = surfl(ix, isurf) surfinswdif(isurf) = rad_sw_in_diff(j,i) * skyvft(isurf) 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 ENDDO ! !-- MRT diffuse irradiance 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 !--Identify solar direction vector (discretized number) 1) !-- j = FLOOR(ACOS(cos_zenith) / pi * raytrace_discrete_elevs) i = MODULO(NINT(ATAN2(sun_dir_lon, sun_dir_lat) & / (2._wp*pi) * raytrace_discrete_azims-.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 DO isurf = 1, nsurfl j = surfl(iy, isurf) i = surfl(ix, isurf) surfinswdir(isurf) = rad_sw_in_dir(j,i) * & costheta(surfl(id, isurf)) * dsitrans(isurf, isd) / cos_zenith ENDDO ! !-- MRT direct irradiance 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) & / cos_zenith / 4._wp ! normal to sphere ENDDO ENDIF ! !-- MRT first pass thermal DO imrtf = 1, nmrtf imrt = mrtfsurf(1, imrtf) isurfsrc = mrtfsurf(2, imrtf) mrtinlw(imrt) = mrtinlw(imrt) + mrtf(imrtf) * surfoutl(isurfsrc) ENDDO ! !-- Absorption in each local plant canopy grid box from the first atmospheric !-- pass of radiation IF ( npcbl > 0 ) THEN pcbinswdir(:) = 0._wp pcbinswdif(:) = 0._wp pcbinlw(:) = 0._wp DO icsf = 1, ncsfl ipcgb = csfsurf(1, icsf) i = pcbl(ix,ipcgb) j = pcbl(iy,ipcgb) k = pcbl(iz,ipcgb) isurfsrc = csfsurf(2, icsf) IF ( isurfsrc == -1 ) THEN ! !-- Diffuse radiation from sky pcbinswdif(ipcgb) = csf(1,icsf) * rad_sw_in_diff(j,i) ! !-- 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) ENDIF ! !-- Direct solar radiation IF ( cos_zenith > 0 ) THEN !-- Estimate directed box absorption pc_abs_frac = 1._wp - exp(pc_abs_eff * lad_s(k,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) 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 ENDIF ENDIF ENDDO pcbinsw(:) = pcbinswdir(:) + pcbinswdif(:) ENDIF IF ( trace_fluxes_above >= 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._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._wp - emiss_surf) * surfinl surfoutsw = surfoutsw + surfoutsl surfoutlw = surfoutlw + surfoutll ENDIF !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !-- Next passes - reflections !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DO refstep = 1, nrefsteps surfoutsl = albedo_surf * surfins ! !-- for non-transparent surfaces, longwave albedo is 1 - emissivity surfoutll = (1._wp - emiss_surf) * surfinl IF ( trace_fluxes_above >= 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._wp surfinl = 0._wp ! !-- Reflected radiation 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 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)) pcbinsw(ipcgb) = pcbinsw(ipcgb) + csf(1,icsf) * surfouts(isurfsrc) * asrc IF ( plant_lw_interact ) THEN pcbinlw(ipcgb) = pcbinlw(ipcgb) + csf(1,icsf) * surfoutl(isurfsrc) * asrc ENDIF ENDDO ! !-- MRT reflected DO imrtf = 1, nmrtf imrt = mrtfsurf(1, imrtf) isurfsrc = mrtfsurf(2, imrtf) mrtinsw(imrt) = mrtinsw(imrt) + mrtft(imrtf) * surfouts(isurfsrc) mrtinlw(imrt) = mrtinlw(imrt) + mrtf(imrtf) * surfoutl(isurfsrc) ENDDO IF ( trace_fluxes_above >= 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 ) CALL radiation_print_debug_pcb( 'pcbinlw after reflected pass', pcbinlw, refstep ) CALL radiation_print_debug_pcb( 'pcbinsw after reflected pass', pcbinsw, refstep ) 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 IF ( npcbl > 0 ) THEN pcm_heating_rate(:,:,:) = 0.0_wp 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 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 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) ** .25_wp ELSE mrt(:) = (mrtinlw(:) / sigma_sb) ** .25_wp ENDIF ENDIF ! !-- Transfer radiation arrays required for energy balance to the respective data types DO i = 1, nsurfl m = surfl(im,i) ! !-- (1) Urban surfaces !-- upward-facing IF ( surfl(1,i) == iup_u ) THEN surf_usm_h%rad_sw_in(m) = surfinsw(i) surf_usm_h%rad_sw_out(m) = surfoutsw(i) surf_usm_h%rad_sw_dir(m) = surfinswdir(i) surf_usm_h%rad_sw_dif(m) = surfinswdif(i) surf_usm_h%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_usm_h%rad_sw_res(m) = surfins(i) surf_usm_h%rad_lw_in(m) = surfinlw(i) surf_usm_h%rad_lw_out(m) = surfoutlw(i) surf_usm_h%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_usm_h%rad_net_l(m) = surf_usm_h%rad_net(m) surf_usm_h%rad_lw_dif(m) = surfinlwdif(i) surf_usm_h%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_usm_h%rad_lw_res(m) = surfinl(i) ! !-- northward-facding ELSEIF ( surfl(1,i) == inorth_u ) THEN surf_usm_v(0)%rad_sw_in(m) = surfinsw(i) surf_usm_v(0)%rad_sw_out(m) = surfoutsw(i) surf_usm_v(0)%rad_sw_dir(m) = surfinswdir(i) surf_usm_v(0)%rad_sw_dif(m) = surfinswdif(i) surf_usm_v(0)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_usm_v(0)%rad_sw_res(m) = surfins(i) surf_usm_v(0)%rad_lw_in(m) = surfinlw(i) surf_usm_v(0)%rad_lw_out(m) = surfoutlw(i) surf_usm_v(0)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_usm_v(0)%rad_net_l(m) = surf_usm_v(0)%rad_net(m) surf_usm_v(0)%rad_lw_dif(m) = surfinlwdif(i) surf_usm_v(0)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_usm_v(0)%rad_lw_res(m) = surfinl(i) ! !-- southward-facding ELSEIF ( surfl(1,i) == isouth_u ) THEN surf_usm_v(1)%rad_sw_in(m) = surfinsw(i) surf_usm_v(1)%rad_sw_out(m) = surfoutsw(i) surf_usm_v(1)%rad_sw_dir(m) = surfinswdir(i) surf_usm_v(1)%rad_sw_dif(m) = surfinswdif(i) surf_usm_v(1)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_usm_v(1)%rad_sw_res(m) = surfins(i) surf_usm_v(1)%rad_lw_in(m) = surfinlw(i) surf_usm_v(1)%rad_lw_out(m) = surfoutlw(i) surf_usm_v(1)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_usm_v(1)%rad_net_l(m) = surf_usm_v(1)%rad_net(m) surf_usm_v(1)%rad_lw_dif(m) = surfinlwdif(i) surf_usm_v(1)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_usm_v(1)%rad_lw_res(m) = surfinl(i) ! !-- eastward-facing ELSEIF ( surfl(1,i) == ieast_u ) THEN surf_usm_v(2)%rad_sw_in(m) = surfinsw(i) surf_usm_v(2)%rad_sw_out(m) = surfoutsw(i) surf_usm_v(2)%rad_sw_dir(m) = surfinswdir(i) surf_usm_v(2)%rad_sw_dif(m) = surfinswdif(i) surf_usm_v(2)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_usm_v(2)%rad_sw_res(m) = surfins(i) surf_usm_v(2)%rad_lw_in(m) = surfinlw(i) surf_usm_v(2)%rad_lw_out(m) = surfoutlw(i) surf_usm_v(2)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_usm_v(2)%rad_net_l(m) = surf_usm_v(2)%rad_net(m) surf_usm_v(2)%rad_lw_dif(m) = surfinlwdif(i) surf_usm_v(2)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_usm_v(2)%rad_lw_res(m) = surfinl(i) ! !-- westward-facding ELSEIF ( surfl(1,i) == iwest_u ) THEN surf_usm_v(3)%rad_sw_in(m) = surfinsw(i) surf_usm_v(3)%rad_sw_out(m) = surfoutsw(i) surf_usm_v(3)%rad_sw_dir(m) = surfinswdir(i) surf_usm_v(3)%rad_sw_dif(m) = surfinswdif(i) surf_usm_v(3)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_usm_v(3)%rad_sw_res(m) = surfins(i) surf_usm_v(3)%rad_lw_in(m) = surfinlw(i) surf_usm_v(3)%rad_lw_out(m) = surfoutlw(i) surf_usm_v(3)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_usm_v(3)%rad_net_l(m) = surf_usm_v(3)%rad_net(m) surf_usm_v(3)%rad_lw_dif(m) = surfinlwdif(i) surf_usm_v(3)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_usm_v(3)%rad_lw_res(m) = surfinl(i) ! !-- (2) land surfaces !-- upward-facing ELSEIF ( surfl(1,i) == iup_l ) THEN surf_lsm_h%rad_sw_in(m) = surfinsw(i) surf_lsm_h%rad_sw_out(m) = surfoutsw(i) surf_lsm_h%rad_sw_dir(m) = surfinswdir(i) surf_lsm_h%rad_sw_dif(m) = surfinswdif(i) surf_lsm_h%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_lsm_h%rad_sw_res(m) = surfins(i) surf_lsm_h%rad_lw_in(m) = surfinlw(i) surf_lsm_h%rad_lw_out(m) = surfoutlw(i) surf_lsm_h%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_lsm_h%rad_lw_dif(m) = surfinlwdif(i) surf_lsm_h%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_lsm_h%rad_lw_res(m) = surfinl(i) ! !-- northward-facding ELSEIF ( surfl(1,i) == inorth_l ) THEN surf_lsm_v(0)%rad_sw_in(m) = surfinsw(i) surf_lsm_v(0)%rad_sw_out(m) = surfoutsw(i) surf_lsm_v(0)%rad_sw_dir(m) = surfinswdir(i) surf_lsm_v(0)%rad_sw_dif(m) = surfinswdif(i) surf_lsm_v(0)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_lsm_v(0)%rad_sw_res(m) = surfins(i) surf_lsm_v(0)%rad_lw_in(m) = surfinlw(i) surf_lsm_v(0)%rad_lw_out(m) = surfoutlw(i) surf_lsm_v(0)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_lsm_v(0)%rad_lw_dif(m) = surfinlwdif(i) surf_lsm_v(0)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_lsm_v(0)%rad_lw_res(m) = surfinl(i) ! !-- southward-facding ELSEIF ( surfl(1,i) == isouth_l ) THEN surf_lsm_v(1)%rad_sw_in(m) = surfinsw(i) surf_lsm_v(1)%rad_sw_out(m) = surfoutsw(i) surf_lsm_v(1)%rad_sw_dir(m) = surfinswdir(i) surf_lsm_v(1)%rad_sw_dif(m) = surfinswdif(i) surf_lsm_v(1)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_lsm_v(1)%rad_sw_res(m) = surfins(i) surf_lsm_v(1)%rad_lw_in(m) = surfinlw(i) surf_lsm_v(1)%rad_lw_out(m) = surfoutlw(i) surf_lsm_v(1)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_lsm_v(1)%rad_lw_dif(m) = surfinlwdif(i) surf_lsm_v(1)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_lsm_v(1)%rad_lw_res(m) = surfinl(i) ! !-- eastward-facing ELSEIF ( surfl(1,i) == ieast_l ) THEN surf_lsm_v(2)%rad_sw_in(m) = surfinsw(i) surf_lsm_v(2)%rad_sw_out(m) = surfoutsw(i) surf_lsm_v(2)%rad_sw_dir(m) = surfinswdir(i) surf_lsm_v(2)%rad_sw_dif(m) = surfinswdif(i) surf_lsm_v(2)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_lsm_v(2)%rad_sw_res(m) = surfins(i) surf_lsm_v(2)%rad_lw_in(m) = surfinlw(i) surf_lsm_v(2)%rad_lw_out(m) = surfoutlw(i) surf_lsm_v(2)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_lsm_v(2)%rad_lw_dif(m) = surfinlwdif(i) surf_lsm_v(2)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_lsm_v(2)%rad_lw_res(m) = surfinl(i) ! !-- westward-facing ELSEIF ( surfl(1,i) == iwest_l ) THEN surf_lsm_v(3)%rad_sw_in(m) = surfinsw(i) surf_lsm_v(3)%rad_sw_out(m) = surfoutsw(i) surf_lsm_v(3)%rad_sw_dir(m) = surfinswdir(i) surf_lsm_v(3)%rad_sw_dif(m) = surfinswdif(i) surf_lsm_v(3)%rad_sw_ref(m) = surfinsw(i) - surfinswdir(i) - & surfinswdif(i) surf_lsm_v(3)%rad_sw_res(m) = surfins(i) surf_lsm_v(3)%rad_lw_in(m) = surfinlw(i) surf_lsm_v(3)%rad_lw_out(m) = surfoutlw(i) surf_lsm_v(3)%rad_net(m) = surfinsw(i) - surfoutsw(i) + & surfinlw(i) - surfoutlw(i) surf_lsm_v(3)%rad_lw_dif(m) = surfinlwdif(i) surf_lsm_v(3)%rad_lw_ref(m) = surfinlw(i) - surfinlwdif(i) surf_lsm_v(3)%rad_lw_res(m) = surfinl(i) ENDIF ENDDO DO m = 1, surf_usm_h%ns surf_usm_h%surfhf(m) = surf_usm_h%rad_sw_in(m) + & surf_usm_h%rad_lw_in(m) - & surf_usm_h%rad_sw_out(m) - & surf_usm_h%rad_lw_out(m) ENDDO DO m = 1, surf_lsm_h%ns surf_lsm_h%surfhf(m) = surf_lsm_h%rad_sw_in(m) + & surf_lsm_h%rad_lw_in(m) - & surf_lsm_h%rad_sw_out(m) - & surf_lsm_h%rad_lw_out(m) ENDDO DO l = 0, 3 !-- urban 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 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 ! !-- Calculate the average temperature, albedo, and emissivity for urban/land !-- domain when using average_radiation in the respective radiation model !-- calculate horizontal area ! !!! ATTENTION!!! uniform grid is assumed here area_hor = (nx+1) * (ny+1) * dx * dy ! !-- absorbed/received SW & LW and emitted LW energy of all physical !-- surfaces (land and urban) in local processor pinswl = 0._wp pinlwl = 0._wp pabsswl = 0._wp pabslwl = 0._wp pemitlwl = 0._wp emiss_sum_surfl = 0._wp area_surfl = 0._wp DO i = 1, nsurfl d = surfl(id, i) !-- received SW & LW pinswl = pinswl + (surfinswdir(i) + surfinswdif(i)) * facearea(d) pinlwl = pinlwl + surfinlwdif(i) * facearea(d) !-- absorbed SW & LW pabsswl = pabsswl + (1._wp - albedo_surf(i)) * & surfinsw(i) * facearea(d) pabslwl = pabslwl + emiss_surf(i) * surfinlw(i) * facearea(d) !-- emitted LW pemitlwl = pemitlwl + surfemitlwl(i) * facearea(d) !-- emissivity and area sum emiss_sum_surfl = emiss_sum_surfl + emiss_surf(i) * facearea(d) area_surfl = area_surfl + facearea(d) END DO ! !-- add the absorbed SW energy by plant canopy IF ( npcbl > 0 ) THEN pabsswl = pabsswl + SUM(pcbinsw) pabslwl = pabslwl + SUM(pcbinlw) pinswl = pinswl + SUM(pcbinswdir) + SUM(pcbinswdif) ENDIF ! !-- 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) = emiss_sum_surfl combine_allreduce_l(7) = area_surfl 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) emiss_sum_surf = combine_allreduce(6) area_surf = combine_allreduce(7) #else pinsw = pinswl pinlw = pinlwl pabssw = pabsswl pabslw = pabslwl pemitlw = pemitlwl emiss_sum_surf = emiss_sum_surfl area_surf = area_surfl #endif !-- (1) albedo IF ( pinsw /= 0.0_wp ) albedo_urb = ( pinsw - pabssw ) / pinsw !-- (2) average emmsivity IF ( area_surf /= 0.0_wp ) emissivity_urb = emiss_sum_surf / area_surf ! !-- Temporally comment out calculation of effective radiative temperature. !-- See below for more explanation. !-- (3) temperature !-- first we calculate an effective horizontal area to account for !-- the effect of vertical surfaces (which contributes to LW emission) !-- We simply use the ratio of the total LW to the incoming LW flux area_hor = pinlw / rad_lw_in_diff(nyn,nxl) t_rad_urb = ( ( pemitlw - pabslw + emissivity_urb * pinlw ) / & (emissivity_urb * sigma_sb * area_hor) )**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 REAL(wp), DIMENSION(3), INTENT(in) :: & boxsize, & !< z, y, x size of box in m uvec !< z, y, x unit vector of incoming flux INTEGER(iwp), INTENT(in) :: & resol !< No. of rays in x and y dimensions 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) :: & xshift, yshift, & xmin, xmax, ymin, ymax, & xorig, yorig, & dx1, dy1, dz1, dx2, dy2, dz2, & crdist, & transp INTEGER(iwp) :: & i, j 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) :: 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), PARAMETER :: lowest_solarUp = 0.1_wp !< limit the sun elevation to protect stability of the calculation 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=*), INTENT(in) :: description REAL(wp), DIMENSION(:), INTENT(in) :: values INTEGER(iwp), INTENT(in), OPTIONAL :: step CHARACTER (LEN=50) :: location CHARACTER (LEN=1024) :: debug_string INTEGER :: isurf REAL(wp) :: x 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 SUBROUTINE radiation_print_debug_pcb( description, values, step ) CHARACTER (LEN=*), INTENT(in) :: description REAL(wp), DIMENSION(:), INTENT(in) :: values INTEGER(iwp), INTENT(in), OPTIONAL :: step CHARACTER (LEN=50) :: location CHARACTER (LEN=1024) :: debug_string INTEGER :: ipcb REAL(wp) :: x 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 SUBROUTINE radiation_print_debug_horz( description, values, step ) CHARACTER (LEN=*), INTENT(in) :: description REAL(wp), DIMENSION(:,:), INTENT(in) :: values INTEGER(iwp), INTENT(in), OPTIONAL :: step CHARACTER (LEN=50) :: location CHARACTER (LEN=1024) :: debug_string INTEGER, DIMENSION(2) :: ji REAL(wp) :: x 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) :: k_topo !< vertical index indicating topography top for given (j,i) INTEGER(iwp) :: nzptl, nzubl, nzutl, isurf, ipcgb, imrt REAL(wp) :: mrl #if defined( __parallel ) INTEGER(iwp), DIMENSION(:), POINTER, SAVE :: gridsurf_rma !< fortran pointer, but lower bounds are 1 TYPE(c_ptr) :: gridsurf_rma_p !< allocated c pointer INTEGER(iwp) :: minfo !< MPI RMA window info handle #endif ! !-- 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,0) ) 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, 0, -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 + pch(j,i) 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 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. startland = 1 nsurfl = surf_usm_h%ns + surf_lsm_h%ns endland = nsurfl nlands = endland - startland + 1 ! !-- Number of vertical surfaces in both USM and LSM. Note that all vertical surface elements are !-- already counted in surface_mod. startwall = nsurfl+1 DO i = 0,3 nsurfl = nsurfl + surf_usm_v(i)%ns + surf_lsm_v(i)%ns ENDDO endwall = nsurfl nwalls = endwall - startwall + 1 dirstart = (/ startland, startwall, startwall, startwall, startwall /) dirend = (/ endland, endwall, endwall, endwall, endwall /) !-- 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) ipcgb = ipcgb + 1 gridpcbl(k,j,i) = ipcgb pcbl(:,ipcgb) = (/ k, j, i /) ENDDO ENDDO ENDDO ALLOCATE( pcbinsw( 1:npcbl ) ) ALLOCATE( pcbinswdir( 1:npcbl ) ) ALLOCATE( pcbinswdif( 1:npcbl ) ) ALLOCATE( pcbinlw( 1:npcbl ) ) ENDIF ! !-- Fill surfl (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) isurf = 0 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 CALL MPI_Info_set(minfo, 'same_size', 'true', ierr) IF ( ierr /= 0 ) THEN WRITE(9,*) 'Error MPI_Info_set3:', ierr FLUSH(9) 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 ENDIF !-- add horizontal surface elements (land and urban surfaces) !-- TODO: add urban overhanging surfaces (idown_u) DO i = nxl, nxr DO j = nys, nyn DO m = surf_usm_h%start_index(j,i), surf_usm_h%end_index(j,i) k = surf_usm_h%k(m) isurf = isurf + 1 surfl(:,isurf) = (/iup_u,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(iup_u,k,j,i) = isurf ENDIF ENDDO DO m = surf_lsm_h%start_index(j,i), surf_lsm_h%end_index(j,i) k = surf_lsm_h%k(m) isurf = isurf + 1 surfl(:,isurf) = (/iup_l,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(iup_u,k,j,i) = isurf ENDIF ENDDO ENDDO ENDDO !-- add vertical surface elements (land and urban surfaces) !-- TODO: remove the hard coding of l = 0 to l = idirection DO i = nxl, nxr DO j = nys, nyn l = 0 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) = (/inorth_u,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(inorth_u,k,j,i) = isurf ENDIF 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) = (/inorth_l,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(inorth_u,k,j,i) = isurf ENDIF ENDDO l = 1 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) = (/isouth_u,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(isouth_u,k,j,i) = isurf ENDIF 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) = (/isouth_l,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(isouth_u,k,j,i) = isurf ENDIF ENDDO l = 2 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) = (/ieast_u,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(ieast_u,k,j,i) = isurf ENDIF 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) = (/ieast_l,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(ieast_u,k,j,i) = isurf ENDIF ENDDO l = 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) = (/iwest_u,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(iwest_u,k,j,i) = isurf ENDIF 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) = (/iwest_l,k,j,i,m/) IF ( rad_angular_discretization ) THEN gridsurf(iwest_u,k,j,i) = isurf ENDIF ENDDO ENDDO ENDDO ! !-- Add local MRT boxes for specified number of levels nmrtbl = 0 IF ( mrt_nlevels > 0 ) THEN DO i = nxl, nxr DO j = nys, nyn DO m = surf_usm_h%start_index(j,i), surf_usm_h%end_index(j,i) ! !-- Skip roof if requested IF ( mrt_skip_roof .AND. surf_usm_h%isroof_surf(m) ) CYCLE ! !-- Cycle over specified no of levels nmrtbl = nmrtbl + mrt_nlevels ENDDO ! !-- Dtto for LSM DO m = surf_lsm_h%start_index(j,i), surf_lsm_h%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%start_index(j,i), surf_usm_h%end_index(j,i) ! !-- Skip roof if requested IF ( mrt_skip_roof .AND. surf_usm_h%isroof_surf(m) ) CYCLE ! !-- Cycle over specified no of levels l = surf_usm_h%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%start_index(j,i), surf_lsm_h%end_index(j,i) l = surf_lsm_h%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 !-- !-- 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 one 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, d, ip, jp INTEGER(iwp) :: isvf, ksvf, icsf, kcsf, npcsfl, isvf_surflt, imrt, imrtf, ipcgb INTEGER(iwp) :: sd, td INTEGER(iwp) :: iaz, izn !< azimuth, zenith counters INTEGER(iwp) :: naz, nzn !< azimuth, zenith num of steps 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) :: yxlen !< |yxdir| REAL(wp), DIMENSION(2) :: yxdir !< y,x *unit* vector of ray direction (in grid units) 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 :: vffrac !< view factor fractions for individual rays REAL(wp), DIMENSION(:), ALLOCATABLE :: vffrac0 !< dtto (original values) REAL(wp), DIMENSION(:), ALLOCATABLE :: ztransp !< array of transparency in z steps INTEGER(iwp) :: lowest_free_ray !< index into zdirs INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: itarget !< face indices of detected obstacles INTEGER(iwp) :: itarg0, itarg1 INTEGER(iwp) :: udim INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET:: nzterrl_l INTEGER(iwp), DIMENSION(:,:), POINTER :: nzterrl REAL(wp), DIMENSION(:), ALLOCATABLE,TARGET:: csflt_l, pcsflt_l REAL(wp), DIMENSION(:,:), POINTER :: csflt, pcsflt INTEGER(iwp), DIMENSION(:), ALLOCATABLE,TARGET:: kcsflt_l,kpcsflt_l INTEGER(iwp), DIMENSION(:,:), POINTER :: kcsflt,kpcsflt INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: icsflt,dcsflt,ipcsflt,dpcsflt REAL(wp), DIMENSION(3) :: uv LOGICAL :: visible REAL(wp), DIMENSION(3) :: sa, ta !< real coordinates z,y,x of source and target REAL(wp) :: difvf !< differential view factor REAL(wp) :: transparency, rirrf, sqdist, svfsum INTEGER(iwp) :: isurflt, isurfs, isurflt_prev INTEGER(idp) :: ray_skip_maxdist, ray_skip_minval !< skipped raytracing counts INTEGER(iwp) :: max_track_len !< maximum 2d track length INTEGER(iwp) :: minfo REAL(wp), DIMENSION(:), POINTER, SAVE :: lad_s_rma !< fortran 1D pointer TYPE(c_ptr) :: lad_s_rma_p !< allocated c pointer #if defined( __parallel ) INTEGER(kind=MPI_ADDRESS_KIND) :: size_lad_rma #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( nzterr(0:(nx+1)*(ny+1)-1) ) #if defined( __parallel ) !ALLOCATE( nzterrl(nys:nyn,nxl:nxr) ) ALLOCATE( nzterrl_l((nyn-nys+1)*(nxr-nxl+1)) ) nzterrl(nys:nyn,nxl:nxr) => nzterrl_l(1:(nyn-nys+1)*(nxr-nxl+1)) nzterrl = topo_top_ind(nys:nyn,nxl:nxr,0) CALL MPI_AllGather( nzterrl_l, nnx*nny, MPI_INTEGER, & nzterr, nnx*nny, MPI_INTEGER, comm2d, ierr ) IF ( ierr /= 0 ) THEN WRITE(9,*) 'Error MPI_AllGather1:', ierr, SIZE(nzterrl_l), nnx*nny, & SIZE(nzterr), nnx*nny FLUSH(9) ENDIF DEALLOCATE(nzterrl_l) #else nzterr = 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_AllGather( pct, nnx*nny, MPI_INTEGER, & plantt, nnx*nny, 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 CALL MPI_Info_set(minfo, 'same_size', 'true', ierr) IF ( ierr /= 0 ) THEN WRITE(9,*) 'Error MPI_Info_set7:', ierr FLUSH(9) 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_AllGather( sub_lad, nnx*nny*nz_plant, MPI_REAL, & sub_lad_g, nnx*nny*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 !-- prepare the MPI_Win for collecting the surface indices !-- from the reverse index arrays gridsurf from processors of target surfaces #if defined( __parallel ) IF ( rad_angular_discretization ) THEN ! !-- 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 !--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_u, iup_l ) 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 ( isouth_u, isouth_l ) 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_u, inorth_l ) 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_u, iwest_l ) 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_u, ieast_l ) 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) ) !FIXME allocate itarget only !in case of rad_angular_discretization 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_u .OR. td == iup_l ) 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 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_u .AND. td /= iup_l ) 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., lowest_free_ray, & ztransp(itarg0:itarg1), & itarget(itarg0:itarg1)) skyvf(isurflt) = skyvf(isurflt) + & SUM(vffrac(itarg0:itarg0+lowest_free_ray-1)) skyvft(isurflt) = skyvft(isurflt) + & SUM(ztransp(itarg0:itarg0+lowest_free_ray-1) & * vffrac(itarg0:itarg0+lowest_free_ray-1)) !-- Save direct solar transparency j = MODULO(NINT(azmid/ & (2._wp*pi)*raytrace_discrete_azims-.5_wp, iwp), & raytrace_discrete_azims) DO k = 1, raytrace_discrete_elevs/2 i = dsidir_rev(k-1, j) IF ( i /= -1 .AND. k <= lowest_free_ray ) & dsitrans(isurflt, i) = ztransp(itarg0+k-1) ENDDO ! !-- 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) /= -1 ) 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 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 = 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 optimize 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., & lowest_free_ray, ztransp, itarget) !-- Save direct solar transparency j = MODULO(NINT(azmid/ & (2._wp*pi)*raytrace_discrete_azims-.5_wp, iwp), & raytrace_discrete_azims) DO k = 1, raytrace_discrete_elevs/2 i = dsidir_rev(k-1, j) IF ( i /= -1 .AND. k <= lowest_free_ray ) & 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) ) !FIXME allocate itarget only !in case of rad_angular_discretization 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., lowest_free_ray, & ztransp(itarg0:itarg1), & itarget(itarg0:itarg1)) !-- Sky view factors for MRT mrtsky(imrt) = mrtsky(imrt) + & SUM(vffrac(itarg0:itarg0+lowest_free_ray-1)) mrtskyt(imrt) = mrtskyt(imrt) + & SUM(ztransp(itarg0:itarg0+lowest_free_ray-1) & * vffrac(itarg0:itarg0+lowest_free_ray-1)) !-- Direct solar transparency for MRT j = MODULO(NINT(azmid/ & (2._wp*pi)*raytrace_discrete_azims-.5_wp, iwp), & raytrace_discrete_azims) DO k = 1, raytrace_discrete_elevs/2 i = dsidir_rev(k-1, j) IF ( i /= -1 .AND. k <= lowest_free_ray ) & 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) ! !-- find the first valid position itarg0 = 1 DO WHILE ( itarg0 <= nzn*naz ) IF ( itarget(itarg0) /= -1 ) 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) CYCLE ENDIF ENDIF ! !-- 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) 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(nzterr) 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) ) ALLOCATE( dcsflt(0:numprocs-1) ) ALLOCATE( ipcsflt(0:numprocs-1) ) ALLOCATE( dpcsflt(0:numprocs-1) ) !-- fill out arrays of csf values and !-- arrays of number of elements and displacements !-- for particular precessors icsflt = 0 dcsflt = 0 ip = -1 j = -1 d = 0 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 d = d+j !-- blank blocks DO jp = ip+1, acsf(kcsf)%ip-1 !-- number of elements is zero, displacement is equal to previous icsflt(jp) = 0 dcsflt(jp) = d ENDDO !-- the actual block ip = acsf(kcsf)%ip dcsflt(ip) = d 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 d = d+j DO jp = ip+1, numprocs-1 !-- number of elements is zero, displacement is equal to previous icsflt(jp) = 0 dcsflt(jp) = d 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 ) !-- scatter and gather the number of elements to and from all processor !-- and calculate displacements IF ( debug_output ) CALL debug_message( 'Scatter and gather the number of elements to and from all processor', 'info' ) CALL MPI_AlltoAll(icsflt,1,MPI_INTEGER,ipcsflt,1,MPI_INTEGER,comm2d, ierr) IF ( ierr /= 0 ) THEN WRITE(9,*) 'Error MPI_AlltoAll1:', ierr, SIZE(icsflt), SIZE(ipcsflt) FLUSH(9) ENDIF npcsfl = SUM(ipcsflt) d = 0 DO i = 0, numprocs-1 dpcsflt(i) = d d = d + ipcsflt(i) ENDDO !-- exchange csf fields between processors IF ( debug_output ) CALL debug_message( 'Exchange csf fields between processors', 'info' ) udim = max(npcsfl,1) ALLOCATE( pcsflt_l(ndcsf*udim) ) pcsflt(1:ndcsf,1:udim) => pcsflt_l(1:ndcsf*udim) ALLOCATE( kpcsflt_l(kdcsf*udim) ) kpcsflt(1:kdcsf,1:udim) => kpcsflt_l(1:kdcsf*udim) CALL MPI_AlltoAllv(csflt_l, ndcsf*icsflt, ndcsf*dcsflt, MPI_REAL, & pcsflt_l, ndcsf*ipcsflt, ndcsf*dpcsflt, MPI_REAL, comm2d, ierr) IF ( ierr /= 0 ) THEN WRITE(9,*) 'Error MPI_AlltoAllv1:', ierr, SIZE(ipcsflt), ndcsf*icsflt, & ndcsf*dcsflt, SIZE(pcsflt_l),ndcsf*ipcsflt, ndcsf*dpcsflt FLUSH(9) ENDIF CALL MPI_AlltoAllv(kcsflt_l, kdcsf*icsflt, kdcsf*dcsflt, MPI_INTEGER, & kpcsflt_l, kdcsf*ipcsflt, kdcsf*dpcsflt, MPI_INTEGER, comm2d, ierr) IF ( ierr /= 0 ) THEN WRITE(9,*) 'Error MPI_AlltoAllv2:', ierr, SIZE(kcsflt_l),kdcsf*icsflt, & kdcsf*dcsflt, SIZE(kpcsflt_l), kdcsf*ipcsflt, kdcsf*dpcsflt FLUSH(9) ENDIF #else npcsfl = ncsfl ALLOCATE( pcsflt(ndcsf,max(npcsfl,ndcsf)) ) ALLOCATE( kpcsflt(kdcsf,max(npcsfl,kdcsf)) ) pcsflt = csflt kpcsflt = kcsflt #endif !-- deallocate temporary arrays DEALLOCATE( csflt_l ) DEALLOCATE( kcsflt_l ) DEALLOCATE( icsflt ) DEALLOCATE( dcsflt ) DEALLOCATE( ipcsflt ) DEALLOCATE( dpcsflt ) !-- 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 REAL(wp), DIMENSION(3), INTENT(in) :: src, targ !< real coordinates z,y,x INTEGER(iwp), INTENT(in) :: isrc !< index of source face for csf REAL(wp), INTENT(in) :: difvf !< differential view factor for csf REAL(wp), INTENT(in) :: atarg !< target surface area for csf LOGICAL, INTENT(in) :: create_csf !< whether to generate new CSFs during raytracing LOGICAL, INTENT(out) :: visible REAL(wp), INTENT(out) :: transparency !< along whole path INTEGER(iwp) :: i, k, d INTEGER(iwp) :: seldim !< dimension to be incremented INTEGER(iwp) :: ncsb !< no of written plant canopy sinkboxes INTEGER(iwp) :: maxboxes !< max no of gridboxes visited REAL(wp) :: distance !< euclidean along path REAL(wp) :: crlen !< length of gridbox crossing 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) :: crmid !< midpoint of crossing REAL(wp) :: cursink !< sink factor for current canopy box REAL(wp), DIMENSION(3) :: delta !< path vector REAL(wp), DIMENSION(3) :: uvect !< unit vector REAL(wp), DIMENSION(3) :: dimnextdist !< distance for each dimension increments 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 INTEGER(iwp) :: px, py !< number of processors in x and y dir before !< the processor in the question INTEGER(iwp) :: ip !< number of processor where gridbox reside INTEGER(iwp) :: ig !< 1D index of gridbox in global 2D array REAL(wp) :: eps = 1E-10_wp !< epsilon for value comparison REAL(wp) :: lad_s_target !< recieved lad_s of particular grid box ! !-- Maximum number of gridboxes visited equals to 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 px = box(3)/nnx py = box(2)/nny ip = px*pdims(2)+py ig = ip*nnx*nny + (box(3)-px*nnx)*nny + box(2)-py*nny IF ( box(1) <= nzterr(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 ) lad_ip(ncsb) = ip lad_disp(ncsb) = (box(3)-px*nnx)*(nny*nz_plant) + (box(2)-py*nny)*nz_plant + box(1)-nz_urban_b #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 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 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, & lowest_free_ray, transparency, itarget) IMPLICIT NONE REAL(wp), DIMENSION(3), INTENT(IN) :: origin !< z,y,x coordinates of ray origin REAL(wp), DIMENSION(2), INTENT(IN) :: yxdir !< y,x *unit* vector of ray direction (in grid units) INTEGER(iwp) :: nrays !< number of rays (z directions) to raytrace REAL(wp), DIMENSION(nrays), INTENT(IN) :: zdirs !< list of z directions to raytrace (z/hdist, grid, zenith->nadir) INTEGER(iwp), INTENT(in) :: iorig !< index of origin face for csf REAL(wp), INTENT(in) :: aorig !< origin face area for csf REAL(wp), DIMENSION(nrays), INTENT(in) :: vffrac !< view factor fractions of each ray for csf 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 INTEGER(iwp), INTENT(out) :: lowest_free_ray !< index into zdirs REAL(wp), DIMENSION(nrays), INTENT(OUT) :: transparency !< transparencies of zdirs paths INTEGER(iwp), DIMENSION(nrays), INTENT(OUT) :: itarget !< global indices of target faces for zdirs INTEGER(iwp), DIMENSION(nrays) :: target_procs REAL(wp) :: horizon !< highest horizon found after raytracing (z/hdist) INTEGER(iwp) :: i, k, l, d INTEGER(iwp) :: seldim !< dimension to be incremented REAL(wp), DIMENSION(2) :: yxorigin !< horizontal copy of origin (y,x) REAL(wp) :: distance !< euclidean along path REAL(wp) :: lastdist !< beginning of current crossing REAL(wp) :: nextdist !< end of current crossing REAL(wp) :: crmid !< midpoint of crossing REAL(wp) :: horz_entry !< horizon at entry to column REAL(wp) :: horz_exit !< horizon at exit from column REAL(wp) :: bdydim !< boundary for current dimension REAL(wp), DIMENSION(2) :: crossdist !< distances to boundary for dimensions REAL(wp), DIMENSION(2) :: dimnextdist !< distance for each dimension increments 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) :: px, py !< number of processors in x and y dir before !< the processor in the question INTEGER(iwp) :: ip !< number of processor where gridbox reside INTEGER(iwp) :: ig !< 1D index of gridbox in global 2D array INTEGER(iwp) :: wcount !< RMA window item count INTEGER(iwp) :: maxboxes !< max no of CSF created INTEGER(iwp) :: nly !< maximum plant canopy height INTEGER(iwp) :: ntrack INTEGER(iwp) :: zb0 INTEGER(iwp) :: zb1 INTEGER(iwp) :: nz INTEGER(iwp) :: iz INTEGER(iwp) :: zsgn INTEGER(iwp) :: lowest_lad !< lowest column cell for which we need LAD INTEGER(iwp) :: lastdir !< wall direction before hitting this column INTEGER(iwp), DIMENSION(2) :: lastcolumn #if defined( __parallel ) INTEGER(MPI_ADDRESS_KIND) :: wdisp !< RMA window displacement #endif REAL(wp) :: eps = 1E-10_wp !< epsilon for value comparison 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 REAL(wp) :: qdist !< ratio of real distance to z coord difference REAL(wp) :: dxxyy !< square of real horizontal distance REAL(wp) :: curtrans !< transparency of current PC box crossing yxorigin(:) = origin(2:3) transparency(:) = 1._wp !-- Pre-set the all rays to transparent before reducing horizon = -HUGE(1._wp) lowest_free_ray = nrays IF ( rad_angular_discretization .AND. calc_svf ) THEN ALLOCATE(target_surfl(nrays)) target_surfl(:) = -1 lastdir = -999 lastcolumn(:) = -999 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 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 nzterr and plantt and id of the coresponding processor px = column(2)/nnx py = column(1)/nny ip = px*pdims(2)+py ig = ip*nnx*nny + (column(2)-px*nnx)*nny + column(1)-py*nny IF ( lastdist == 0._wp ) THEN horz_entry = -HUGE(1._wp) ELSE horz_entry = (REAL(nzterr(ig), wp) + .5_wp - origin(1)) / lastdist ENDIF horz_exit = (REAL(nzterr(ig), wp) + .5_wp - origin(1)) / nextdist IF ( rad_angular_discretization .AND. calc_svf ) THEN ! !-- Identify vertical obstacles hit by rays in current column DO WHILE ( lowest_free_ray > 0 ) IF ( zdirs(lowest_free_ray) > horz_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_free_ray)*lastdist), & lastcolumn(1), lastcolumn(2), & target_surfl(lowest_free_ray), target_procs(lowest_free_ray)) lowest_free_ray = lowest_free_ray - 1 ENDDO ! !-- Identify horizontal obstacles hit by rays in current column DO WHILE ( lowest_free_ray > 0 ) IF ( zdirs(lowest_free_ray) > horz_exit ) EXIT CALL request_itarget(iup_u, nzterr(ig)+1, column(1), column(2), & target_surfl(lowest_free_ray), & target_procs(lowest_free_ray)) lowest_free_ray = lowest_free_ray - 1 ENDDO ENDIF horizon = MAX(horizon, horz_entry, horz_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 .AND. calc_svf ) THEN ! !-- Save wall direction of coming building column (= this air column) IF ( seldim == 1 ) THEN IF ( dimdelta(seldim) == 1 ) THEN lastdir = isouth_u ELSE lastdir = inorth_u ENDIF ELSE IF ( dimdelta(seldim) == 1 ) THEN lastdir = iwest_u ELSE lastdir = ieast_u ENDIF ENDIF lastcolumn = column ENDIF 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 px = rt2_track(2,i)/nnx py = rt2_track(1,i)/nny ip = px*pdims(2)+py ig = ip*nnx*nny + (rt2_track(2,i)-px*nnx)*nny + rt2_track(1,i)-py*nny IF ( rad_angular_discretization .AND. calc_svf ) THEN ! !-- For fixed view resolution, we need plant canopy even for rays !-- to opposing surfaces lowest_lad = nzterr(ig) + 1 ELSE ! !-- We only need LAD for rays directed above horizon (to sky) lowest_lad = CEILING( -0.5_wp + origin(1) + & MIN( horizon * rt2_track_dist(i-1), & ! entry 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 wdisp = (rt2_track(2,i)-px*nnx)*(nny*nz_plant) + (rt2_track(1,i)-py*nny)*nz_plant + lowest_lad-nz_urban_b 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 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 px = rt2_track(2,i)/nnx py = rt2_track(1,i)/nny ip = px*pdims(2)+py ig = ip*nnx*nny*nz_plant + (rt2_track(2,i)-px*nnx)*(nny*nz_plant) + (rt2_track(1,i)-py*nny)*nz_plant 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 .AND. calc_svf ) 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 ! !-- recalculate local surf indices into global ones DO i = 1, nrays IF ( target_surfl(i) == -1 ) THEN itarget(i) = -1 ELSE itarget(i) = target_surfl(i) + surfstart(target_procs(i)) ENDIF ENDDO DEALLOCATE( target_surfl ) ELSE itarget(:) = -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 ( 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 px = rt2_track(2,i)/nnx py = rt2_track(1,i)/nny ip = px*pdims(2)+py 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 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 IF ( zdirs(k) <= 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) iz = 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 )/) iz = zb0 * zsgn ENDIF DO l = 2, nz IF ( rt2_track_lad(iz, i) > 0._wp ) THEN curtrans = exp(-ext_coef * rt2_track_lad(iz, 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 = iz acsf(ncsfl)%isurfs = iorig acsf(ncsfl)%rcvf = (1._wp - curtrans)*transparency(k)*vffrac(k) ENDIF transparency(k) = transparency(k) * curtrans ENDIF iz = iz + zsgn ENDDO ! l = 1, nz - 1 ENDDO ! k = 1, nrays ENDDO ! i = 1, ntrack transparency(1:lowest_free_ray) = 1._wp !-- Reset rays above horizon to transparent (see NOTE 6778) 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 px = rt2_track(2,i)/nnx py = rt2_track(1,i)/nny ip = px*pdims(2)+py DO k = 1, nrays ! for each ray ! !-- See NOTE 6778 above IF ( zdirs(k) <= horizon ) 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) iz = 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 )/) iz = zb0 * zsgn ENDIF DO l = 2, nz IF ( rt2_track_lad(iz, i) > 0._wp ) THEN curtrans = exp(-ext_coef * rt2_track_lad(iz, 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 = iz IF ( itarget(k) /= -1 ) STOP 1 !FIXME remove after test acsf(ncsfl)%isurfs = -1 acsf(ncsfl)%rcvf = (1._wp - curtrans)*transparency(k)*aorig*vffrac(k) ENDIF ! create_csf transparency(k) = transparency(k) * curtrans ENDIF iz = iz + zsgn ENDDO ! l = 1, nz - 1 ENDDO ! k = 1, nrays ENDDO ! i = 1, ntrack ENDIF ! plant_canopy IF ( .NOT. (rad_angular_discretization .AND. calc_svf) ) THEN ! !-- Just update lowest_free_ray according to horizon DO WHILE ( lowest_free_ray > 0 ) IF ( zdirs(lowest_free_ray) > horizon ) EXIT lowest_free_ray = lowest_free_ray - 1 ENDDO ENDIF CONTAINS SUBROUTINE request_itarget( d, z, y, x, isurfl, iproc ) INTEGER(iwp), INTENT(in) :: d, z, y, x INTEGER(iwp), TARGET, INTENT(out) :: isurfl INTEGER(iwp), INTENT(out) :: iproc #if defined( __parallel ) #else INTEGER(iwp) :: target_displ !< index of the grid in the local gridsurf array #endif INTEGER(iwp) :: px, py !< number of processors in x and y direction !< before the processor in the question #if defined( __parallel ) 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 px = x / nnx py = y / nny iproc = px * pdims(2) + py target_displ = ((x-px*nnx) * nny + y - py*nny ) * nz_urban * nsurf_type_u +& ( z-nz_urban_b ) * nsurf_type_u + d ! !-- 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 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), 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) i = MODULO(NINT(ATAN2(sun_dir_lon, sun_dir_lat) & / (2._wp*pi) * raytrace_discrete_azims-.5_wp, iwp), & raytrace_discrete_azims) j = FLOOR(ACOS(cos_zenith) / pi * raytrace_discrete_elevs) IF ( dsidir_rev(j, i) == -1 ) THEN ndsidir = ndsidir + 1 dsidir_tmp(:, ndsidir) = & (/ COS((REAL(j,wp)+.5_wp) * pi / raytrace_discrete_elevs), & SIN((REAL(j,wp)+.5_wp) * pi / raytrace_discrete_elevs) & * COS((REAL(i,wp)+.5_wp) * 2_wp*pi / raytrace_discrete_azims), & SIN((REAL(j,wp)+.5_wp) * pi / raytrace_discrete_elevs) & * SIN((REAL(i,wp)+.5_wp) * 2_wp*pi / raytrace_discrete_azims) /) 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_u .OR. d==iup_l ) & .AND. (d2==iup_u .OR. d2==iup_l) ) RETURN IF ( (d==isouth_u .OR. d==isouth_l ) & .AND. (d2==isouth_u .OR. d2==isouth_l) ) RETURN IF ( (d==inorth_u .OR. d==inorth_l ) & .AND. (d2==inorth_u .OR. d2==inorth_l) ) RETURN IF ( (d==iwest_u .OR. d==iwest_l ) & .AND. (d2==iwest_u .OR. d2==iwest_l ) ) RETURN IF ( (d==ieast_u .OR. d==ieast_l ) & .AND. (d2==ieast_u .OR. d2==ieast_l ) ) RETURN !-- second check: are surfaces facing away from each other SELECT CASE (d) CASE (iup_u, iup_l) !< upward facing surfaces IF ( z2 < z ) RETURN CASE (isouth_u, isouth_l) !< southward facing surfaces IF ( y2 > y ) RETURN CASE (inorth_u, inorth_l) !< northward facing surfaces IF ( y2 < y ) RETURN CASE (iwest_u, iwest_l) !< westward facing surfaces IF ( x2 > x ) RETURN CASE (ieast_u, ieast_l) !< eastward facing surfaces IF ( x2 < x ) RETURN END SELECT SELECT CASE (d2) CASE (iup_u) !< ground, roof IF ( z < z2 ) RETURN CASE (isouth_u, isouth_l) !< south facing IF ( y > y2 ) RETURN CASE (inorth_u, inorth_l) !< north facing IF ( y < y2 ) RETURN CASE (iwest_u, iwest_l) !< west facing IF ( x > x2 ) RETURN CASE (ieast_u, ieast_l) !< 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 INTEGER(iwp) :: i INTEGER(iwp) :: ndsidir_from_file = 0 INTEGER(iwp) :: npcbl_from_file = 0 INTEGER(iwp) :: nsurfl_from_file = 0 INTEGER(iwp) :: nmrtbl_from_file = 0 CALL location_message( 'reading view factors for radiation interaction', '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_from_file, npcbl_from_file, & ndsidir_from_file, nmrtbl_from_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_from_file IF ( debug_output ) CALL debug_message( debug_string, 'info' ) ENDIF IF ( nsurfl_from_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_from_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_from_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_from_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 has to allocate 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 view factors for radiation interaction', 'finished' ) 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 INTEGER(iwp) :: i CALL location_message( 'writing view factors for radiation interaction', '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 view factors for radiation interaction', 'finished' ) 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), DIMENSION(:), INTENT(INOUT) :: itarget REAL(wp), DIMENSION(:), INTENT(INOUT) :: vffrac, ztransp INTEGER(iwp), INTENT(IN) :: first, last INTEGER(iwp) :: x, t INTEGER(iwp) :: i, j REAL(wp) :: tr 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 !-- 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 TYPE(t_svf), DIMENSION(:), INTENT(INOUT) :: svfl INTEGER(iwp), INTENT(IN) :: first, last TYPE(t_svf) :: x, t INTEGER(iwp) :: i, j 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) TYPE (t_csf), INTENT(in) :: csf1,csf2 LOGICAL :: res 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 !-- 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 TYPE(t_csf), DIMENSION(:), INTENT(INOUT) :: csfl INTEGER(iwp), INTENT(IN) :: first, last TYPE(t_csf) :: x, t INTEGER(iwp) :: i, j 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), INTENT(in) :: newsize !< new array size after grow, must be >= ncsfl !< or -1 to shrink to minimum INTEGER(iwp) :: iread, iwrite 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 !-- 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), DIMENSION(:,:), INTENT(INOUT) :: kpcsflt REAL(wp), DIMENSION(:,:), INTENT(INOUT) :: pcsflt INTEGER(iwp), INTENT(IN) :: first, last REAL(wp), DIMENSION(ndcsf) :: t2 INTEGER(iwp), DIMENSION(kdcsf) :: x, t1 INTEGER(iwp) :: i, j 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) REAL(wp), DIMENSION(:), INTENT(IN) :: athresh REAL(wp), INTENT(IN) :: val INTEGER(iwp) :: ind INTEGER(iwp) :: i 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: ! ------------ !> Subroutine for averaging 3D data !------------------------------------------------------------------------------! SUBROUTINE radiation_3d_data_averaging( mode, variable ) USE control_parameters USE indices USE kinds IMPLICIT NONE CHARACTER (LEN=*) :: mode !< CHARACTER (LEN=*) :: variable !< LOGICAL :: match_lsm !< flag indicating natural-type surface LOGICAL :: match_usm !< flag indicating urban-type surface INTEGER(iwp) :: i !< INTEGER(iwp) :: j !< INTEGER(iwp) :: k !< INTEGER(iwp) :: l, m !< index of current surface element INTEGER(iwp) :: ids, idsint_u, idsint_l, isurf CHARACTER(LEN=varnamelength) :: var !-- 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_u = dirint_u(ids) idsint_l = dirint_l(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_in_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) ) surfradnet_av = 0.0_wp ENDIF 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) ) surfinsw_av = 0.0_wp ENDIF 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) ) surfinlw_av = 0.0_wp ENDIF CASE ( 'rtm_rad_inswdir' ) !-- array of direct sw radiation falling to surface from sun IF ( .NOT. ALLOCATED(surfinswdir_av) ) THEN ALLOCATE( surfinswdir_av(nsurfl) ) surfinswdir_av = 0.0_wp ENDIF 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) ) surfinswdif_av = 0.0_wp ENDIF CASE ( 'rtm_rad_inswref' ) !-- array of sw radiation falling to surface from reflections IF ( .NOT. ALLOCATED(surfinswref_av) ) THEN ALLOCATE( surfinswref_av(nsurfl) ) surfinswref_av = 0.0_wp ENDIF 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) ) surfinlwdif_av = 0.0_wp ENDIF CASE ( 'rtm_rad_inlwref' ) !-- array of lw radiation falling to surface from reflections IF ( .NOT. ALLOCATED(surfinlwref_av) ) THEN ALLOCATE( surfinlwref_av(nsurfl) ) surfinlwref_av = 0.0_wp ENDIF 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) ) surfoutsw_av = 0.0_wp ENDIF 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) ) surfins_av = 0.0_wp ENDIF 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) ) surfinl_av = 0.0_wp ENDIF 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) ) pcbinsw_av = 0.0_wp ENDIF 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) ) pcbinswdir_av = 0.0_wp ENDIF 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) ) pcbinswdif_av = 0.0_wp ENDIF 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) ) pcbinswref_av = 0.0_wp ENDIF 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 CASE ( 'rad_net*' ) IF ( ALLOCATED( rad_net_av ) ) THEN DO i = nxl, nxr DO j = nys, nyn match_lsm = surf_lsm_h%start_index(j,i) <= & surf_lsm_h%end_index(j,i) match_usm = surf_usm_h%start_index(j,i) <= & surf_usm_h%end_index(j,i) IF ( match_lsm .AND. .NOT. match_usm ) THEN m = surf_lsm_h%end_index(j,i) rad_net_av(j,i) = rad_net_av(j,i) + & surf_lsm_h%rad_net(m) ELSEIF ( match_usm ) THEN m = surf_usm_h%end_index(j,i) rad_net_av(j,i) = rad_net_av(j,i) + & surf_usm_h%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%start_index(j,i) <= & surf_lsm_h%end_index(j,i) match_usm = surf_usm_h%start_index(j,i) <= & surf_usm_h%end_index(j,i) IF ( match_lsm .AND. .NOT. match_usm ) THEN m = surf_lsm_h%end_index(j,i) rad_lw_in_xy_av(j,i) = rad_lw_in_xy_av(j,i) + & surf_lsm_h%rad_lw_in(m) ELSEIF ( match_usm ) THEN m = surf_usm_h%end_index(j,i) rad_lw_in_xy_av(j,i) = rad_lw_in_xy_av(j,i) + & surf_usm_h%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%start_index(j,i) <= & surf_lsm_h%end_index(j,i) match_usm = surf_usm_h%start_index(j,i) <= & surf_usm_h%end_index(j,i) IF ( match_lsm .AND. .NOT. match_usm ) THEN m = surf_lsm_h%end_index(j,i) rad_lw_out_xy_av(j,i) = rad_lw_out_xy_av(j,i) + & surf_lsm_h%rad_lw_out(m) ELSEIF ( match_usm ) THEN m = surf_usm_h%end_index(j,i) rad_lw_out_xy_av(j,i) = rad_lw_out_xy_av(j,i) + & surf_usm_h%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%start_index(j,i) <= & surf_lsm_h%end_index(j,i) match_usm = surf_usm_h%start_index(j,i) <= & surf_usm_h%end_index(j,i) IF ( match_lsm .AND. .NOT. match_usm ) THEN m = surf_lsm_h%end_index(j,i) rad_sw_in_xy_av(j,i) = rad_sw_in_xy_av(j,i) + & surf_lsm_h%rad_sw_in(m) ELSEIF ( match_usm ) THEN m = surf_usm_h%end_index(j,i) rad_sw_in_xy_av(j,i) = rad_sw_in_xy_av(j,i) + & surf_usm_h%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%start_index(j,i) <= & surf_lsm_h%end_index(j,i) match_usm = surf_usm_h%start_index(j,i) <= & surf_usm_h%end_index(j,i) IF ( match_lsm .AND. .NOT. match_usm ) THEN m = surf_lsm_h%end_index(j,i) rad_sw_out_xy_av(j,i) = rad_sw_out_xy_av(j,i) + & surf_lsm_h%rad_sw_out(m) ELSEIF ( match_usm ) THEN m = surf_usm_h%end_index(j,i) rad_sw_out_xy_av(j,i) = rad_sw_out_xy_av(j,i) + & surf_usm_h%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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) THEN 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) THEN surfinswdir_av(isurf) = surfinswdir_av(isurf) + surfinswdir(isurf) ENDIF ENDDO CASE ( 'rtm_rad_inswdif' ) !-- array of difusion sw radiation falling to surface from sky and borders of the domain DO isurf = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 ( 'rad_mrt_sw' ) IF ( ALLOCATED( mrtinsw_av ) ) THEN mrtinsw_av(:) = mrtinsw_av(:) + mrtinsw(:) ENDIF CASE ( 'rad_mrt_lw' ) IF ( ALLOCATED( mrtinlw_av ) ) THEN mrtinlw_av(:) = mrtinlw_av(:) + mrtinlw(:) ENDIF CASE ( 'rad_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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) THEN surfradnet_av(isurf) = surfinsw_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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) THEN surfinswdir_av(isurf) = surfinswdir_av(isurf) / REAL( average_count_3d, kind=wp ) ENDIF ENDDO CASE ( 'rtm_rad_inswdif' ) !-- array of difusion sw radiation falling to surface from sky and borders of the domain DO isurf = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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(:) = pcbinlw_av(:) / REAL( average_count_3d, kind=wp ) ENDDO CASE ( 'rtm_rad_pc_insw' ) DO l = 1, npcbl pcbinsw_av(:) = pcbinsw_av(:) / REAL( average_count_3d, kind=wp ) ENDDO CASE ( 'rtm_rad_pc_inswdir' ) DO l = 1, npcbl pcbinswdir_av(:) = pcbinswdir_av(:) / REAL( average_count_3d, kind=wp ) ENDDO CASE ( 'rtm_rad_pc_inswdif' ) DO l = 1, npcbl pcbinswdif_av(:) = pcbinswdif_av(:) / REAL( average_count_3d, kind=wp ) ENDDO CASE ( 'rtm_rad_pc_inswref' ) DO l = 1, npcbl pcbinswref_av(:) = pcbinswref_av(:) / REAL( average_count_3d, kind=wp ) ENDDO CASE ( 'rad_mrt_lw' ) IF ( ALLOCATED( mrtinlw_av ) ) THEN mrtinlw_av(:) = mrtinlw_av(:) / REAL( average_count_3d, KIND=wp ) ENDIF CASE ( 'rad_mrt' ) IF ( ALLOCATED( mrt_av ) ) THEN mrt_av(:) = mrt_av(:) / REAL( average_count_3d, KIND=wp ) 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 !< LOGICAL, INTENT(OUT) :: found !< CHARACTER (LEN=*), INTENT(OUT) :: grid_x !< CHARACTER (LEN=*), INTENT(OUT) :: grid_y !< CHARACTER (LEN=*), INTENT(OUT) :: grid_z !< CHARACTER (len=varnamelength) :: var 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', & 'rad_mrt', 'rad_mrt_sw', 'rad_mrt_lw' ) 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 ) 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 = -999.0_wp !< 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 !-- Natural-type surfaces DO m = surf_lsm_h%start_index(j,i), & surf_lsm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_lsm_h%rad_net(m) ENDDO ! !-- Urban-type surfaces DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_usm_h%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%start_index(j,i), & surf_lsm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_lsm_h%rad_lw_in(m) ENDDO ! !-- Urban-type surfaces DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_usm_h%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%start_index(j,i), & surf_lsm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_lsm_h%rad_lw_out(m) ENDDO ! !-- Urban-type surfaces DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_usm_h%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%start_index(j,i), & surf_lsm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_lsm_h%rad_sw_in(m) ENDDO ! !-- Urban-type surfaces DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_usm_h%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%start_index(j,i), & surf_lsm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_lsm_h%rad_sw_out(m) ENDDO ! !-- Urban-type surfaces DO m = surf_usm_h%start_index(j,i), & surf_usm_h%end_index(j,i) local_pf(i,j,nzb+1) = surf_usm_h%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) = rad_lw_in(k,j,i) 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) = rad_lw_out(k,j,i) 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) = rad_lw_cs_hr(k,j,i) 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) = rad_lw_hr(k,j,i) 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) = rad_sw_in(k,j,i) 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) = rad_sw_out(k,j,i) 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) = rad_sw_cs_hr(k,j,i) 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) = rad_sw_hr(k,j,i) 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, nzb_do, nzt_do ) USE indices USE kinds IMPLICIT NONE CHARACTER (LEN=*) :: variable !< INTEGER(iwp) :: av !< INTEGER(iwp) :: i, j, k, l !< INTEGER(iwp) :: nzb_do !< INTEGER(iwp) :: nzt_do !< LOGICAL :: found !< REAL(wp) :: fill_value = -999.0_wp !< value for the _FillValue attribute REAL(sp), DIMENSION(nxl:nxr,nys:nyn,nzb_do:nzt_do) :: local_pf !< CHARACTER (len=varnamelength) :: var, surfid INTEGER(iwp) :: ids,idsint_u,idsint_l,isurf,isvf,isurfs,isurflt,ipcgb INTEGER(iwp) :: is, js, ks, istat 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_u = dirint_u(ids) idsint_l = dirint_l(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) = rad_sw_in(k,j,i) 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) = rad_sw_out(k,j,i) 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) = rad_sw_cs_hr(k,j,i) 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) = rad_sw_hr(k,j,i) 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) = rad_lw_in(k,j,i) 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) = rad_lw_out(k,j,i) 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) = rad_lw_cs_hr(k,j,i) 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) = rad_lw_hr(k,j,i) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 analyse purposes CASE ( 'rtm_skyvf' ) ! !-- sky view factor DO isurf = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) THEN local_pf(surfl(ix,isurf),surfl(iy,isurf),surfl(iz,isurf)) = skyvf(isurf) ENDIF ENDDO CASE ( 'rtm_skyvft' ) ! !-- sky view factor DO isurf = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == ids ) 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. & (surf(id,isurfs) == idsint_u .OR. surfl(id,isurfs) == idsint_l ) ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 = dirstart(ids), dirend(ids) IF ( surfl(id,isurf) == idsint_u .OR. surfl(id,isurf) == idsint_l ) 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 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 END SUBROUTINE radiation_wrd_local !------------------------------------------------------------------------------! ! Description: ! ------------ !> Subroutine reads local (subdomain) restart data !------------------------------------------------------------------------------! SUBROUTINE radiation_rrd_local( 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 END MODULE radiation_model_mod