Changeset 4853 for LMDZ6/trunk/libf/phylmd/ecrad
- Timestamp:
- Mar 19, 2024, 3:34:21 PM (11 months ago)
- Location:
- LMDZ6/trunk/libf/phylmd/ecrad
- Files:
-
- 8 added
- 7 deleted
- 33 edited
Legend:
- Unmodified
- Added
- Removed
-
LMDZ6/trunk/libf/phylmd/ecrad/CHANGELOG
r4773 r4853 15 15 - Increased security value in single-precision SW 16 16 reflectance-transmittance calculation from 1e-12 to 1e-6 17 - Added radiation/ecrad_config.h file to provide site-specific 18 optimization options as preprocessor parameters 19 - Replaced slow "sum" intrinsic function in McICA and Tripleclouds 20 solvers with optimized versions for x86-64 and DWD's NEC 21 - Enable different gas optics models for shortwave and longwave: 22 namelist gas_model_name can still be used, or use 23 sw_gas_model_name and lw_gas_model_name to specify separate models 24 - Fix the general aerosol optics + RRTMG combination, so that 25 optical properties correctly weighted by solar or terrestrial 26 Planck function, rather than unweighted. This changes fluxes by up 27 to 0.3 W m-2 in SW and 0.03 in LW, heating rates by up to 0.015 28 K/d in SW and 0.0015 in LW. Reverts bug introduced between git 29 commits a405cca (5 Dec 2022) and 7182230 (8 Dec 2022). 30 - Added ifs/satur.F90, used in the IFS to compute relative 31 humidity for aerosol hydration, and the ability to call it from 32 ecrad_driver.F90, but note that this routine computes saturation 33 with respect to ice at colder temperatures. If used, the impact on 34 fluxes is up to around 1 W m-2 in the SW and 0.05 in the LW, and 35 for heating rates 0.002 K/d in the SW and 0.003 in the LW. 17 36 18 37 version 1.6.0 (27 April 2023) -
LMDZ6/trunk/libf/phylmd/ecrad/driver/Makefile
r4773 r4853 20 20 test_programs: $(TEST_PROGRAMS) 21 21 22 # Link ecrad executable; add "-lifs" if you want to use the "satur" 23 # routine in ecrad_driver.F90 22 24 $(EXECUTABLE): $(OBJECTS) ../lib/*.a ecrad_driver.o 23 25 $(FC) $(FCFLAGS) ecrad_driver.o $(OBJECTS) $(LIBS) -o $(EXECUTABLE) -
LMDZ6/trunk/libf/phylmd/ecrad/driver/ecrad_driver.F90
r4773 r4853 55 55 implicit none 56 56 57 ! Uncomment this if you want to use the "satur" routine below 58 !#include "satur.intfb.h" 59 57 60 ! The NetCDF file containing the input profiles 58 61 type(netcdf_file) :: file … … 269 272 270 273 ! Compute saturation with respect to liquid (needed for aerosol 271 ! hydration) call 274 ! hydration) call... 272 275 call thermodynamics%calc_saturation_wrt_liquid(driver_config%istartcol,driver_config%iendcol) 273 276 277 ! ...or alternatively use the "satur" function in the IFS (requires 278 ! adding -lifs to the linker command line) but note that this 279 ! computes saturation with respect to ice at colder temperatures, 280 ! which is almost certainly incorrect 281 !allocate(thermodynamics%h2o_sat_liq(ncol,nlev)) 282 !call satur(driver_config%istartcol, driver_config%iendcol, ncol, 1, nlev, .false., & 283 ! 0.5_jprb * (thermodynamics.pressure_hl(:,1:nlev)+thermodynamics.pressure_hl(:,2:nlev)), & 284 ! 0.5_jprb * (thermodynamics.temperature_hl(:,1:nlev)+thermodynamics.temperature_hl(:,2:nlev)), & 285 ! thermodynamics%h2o_sat_liq, 2) 286 274 287 ! Check inputs are within physical bounds, printing message if not 275 288 is_out_of_bounds = gas%out_of_physical_bounds(driver_config%istartcol, driver_config%iendcol, & -
LMDZ6/trunk/libf/phylmd/ecrad/ifs/Makefile
r4773 r4853 2 2 radiation_scheme.F90 radiation_setup.F90 yoerdu.F90 \ 3 3 yomrip.F90 yoephy.F90 yoecld.F90 yoe_spectral_planck.F90 \ 4 cloud_overlap_decorr_len.F90 yoerad.F90 4 cloud_overlap_decorr_len.F90 yoerad.F90 yoethf.F90 satur.F90 5 5 6 6 OBJECTS := $(SOURCES:.F90=.o) … … 31 31 cos_sza.o ice_effective_radius.o liquid_effective_radius.o radiation_scheme.o radiation_setup.o: yoerad.o 32 32 yoerad.o: yoe_spectral_planck.o 33 satur.o: yoethf.o -
LMDZ6/trunk/libf/phylmd/ecrad/ifs/yoephy.F90
r4773 r4853 11 11 12 12 USE PARKIND1, ONLY : JPRB, JPIM 13 USE ISO_C_BINDING13 !USE ISO_C_BINDING 14 14 15 15 IMPLICIT NONE -
LMDZ6/trunk/libf/phylmd/ecrad/ifsaux/yomcst.F90
r4773 r4853 71 71 REAL(KIND=JPRB), PARAMETER :: RMCCL4 = 153.823_JPRB 72 72 73 REAL(KIND=JPRB), PARAMETER :: RCPD = 3.5_JPRB*RD 74 REAL(KIND=JPRB), PARAMETER :: RLMLT = RLSTT-RLVTT 75 73 76 END MODULE YOMCST -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/Makefile
r4773 r4853 111 111 112 112 radiation_general_cloud_optics.o: radiation_config.o radiation_cloud.o radiation_thermodynamics.o radiation_constants.o 113 114 *.o: ecrad_config.h -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_aerosol_optics.F90
r4773 r4853 19 19 ! 2022-11-22 P. Ukkonen / R. Hogan Optimizations to enhance vectorization 20 20 21 #include "ecrad_config.h" 22 21 23 module radiation_aerosol_optics 22 24 … … 96 98 use parkind1, only : jprb 97 99 use yomhook, only : lhook, dr_hook, jphook 100 #ifdef EASY_NETCDF_READ_MPI 101 use easy_netcdf_read_mpi, only : netcdf_file 102 #else 98 103 use easy_netcdf, only : netcdf_file 104 #endif 99 105 use radiation_config, only : config_type 100 106 use radiation_aerosol_optics_data, only : aerosol_optics_type … … 341 347 use parkind1, only : jprb 342 348 use yomhook, only : lhook, dr_hook, jphook 349 #ifdef EASY_NETCDF_READ_MPI 350 use easy_netcdf_read_mpi, only : netcdf_file 351 #else 343 352 use easy_netcdf, only : netcdf_file 353 #endif 344 354 use radiation_config, only : config_type 345 355 use radiation_aerosol_optics_data, only : aerosol_optics_type -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_aerosol_optics_data.F90
r4773 r4853 17 17 ! 2018-04-20 A. Bozzo Read optical properties at selected wavelengths 18 18 19 #include "ecrad_config.h" 19 20 20 21 module radiation_aerosol_optics_data … … 157 158 158 159 use yomhook, only : lhook, dr_hook, jphook 160 #ifdef EASY_NETCDF_READ_MPI 161 use easy_netcdf_read_mpi, only : netcdf_file 162 #else 159 163 use easy_netcdf, only : netcdf_file 164 #endif 160 165 use radiation_io, only : nulerr, radiation_abort 161 166 … … 401 406 subroutine save_aerosol_optics(this, file_name, iverbose) 402 407 403 use yomhook, only : lhook, dr_hook, jphook404 use easy_netcdf, only : netcdf_file408 use yomhook, only : lhook, dr_hook, jphook 409 use easy_netcdf, only : netcdf_file 405 410 406 411 class(aerosol_optics_type), intent(inout) :: this -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_aerosol_optics_description.F90
r4773 r4853 13 13 ! Email: r.j.hogan@ecmwf.int 14 14 ! 15 16 #include "ecrad_config.h" 15 17 16 18 module radiation_aerosol_optics_description … … 60 62 logical, allocatable :: is_preferred_philic(:) 61 63 64 ! Verbosity level 65 integer :: iverbose 66 62 67 contains 63 68 procedure :: read … … 75 80 76 81 use yomhook, only : lhook, dr_hook, jphook 82 #ifdef EASY_NETCDF_READ_MPI 83 use easy_netcdf_read_mpi, only : netcdf_file 84 #else 77 85 use easy_netcdf, only : netcdf_file 86 #endif 78 87 79 88 class(aerosol_optics_description_type), intent(inout) :: this … … 84 93 type(netcdf_file) :: file 85 94 86 real(jphook) :: hook_handle95 real(jphook) :: hook_handle 87 96 88 97 if (lhook) call dr_hook('radiation_aerosol_optics_description:load',0,hook_handle) … … 108 117 call file%close() 109 118 119 if (present(iverbose)) then 120 this%iverbose = iverbose 121 else 122 this%iverbose = 3 123 end if 124 110 125 if (lhook) call dr_hook('radiation_aerosol_optics_description:load',1,hook_handle) 111 126 … … 124 139 125 140 use yomhook, only : lhook, dr_hook, jphook 126 141 use radiation_io, only : nulout, nulerr, radiation_abort 142 127 143 class(aerosol_optics_description_type), intent(inout) :: this 128 144 character(len=2), intent(in) :: code_str … … 132 148 integer :: ja 133 149 134 real(jphook) :: hook_handle 150 logical :: is_found, is_philic, is_phobic 151 152 real(jphook) :: hook_handle 135 153 136 154 if (lhook) call dr_hook('radiation_aerosol_optics_description:preferred_optical_model',0,hook_handle) … … 138 156 ! Check for empty string 139 157 if (optical_model_str == ' ') then 158 if (lhook) call dr_hook('radiation_aerosol_optics_description:preferred_optical_model',1,hook_handle) 140 159 return 141 160 end if 161 162 is_found = .false. 163 is_philic = .false. 164 is_phobic = .false. 142 165 143 166 ! Loop over hydrophilic types … … 145 168 ! Check if we have a match 146 169 if (to_string(this%code_philic(:,ja)) == code_str & 147 & .and. t o_string(this%optical_model_philic(1:len(optical_model_str),ja)) &170 & .and. trim(to_string(this%optical_model_philic(:,ja))) & 148 171 & == optical_model_str) then 149 172 this%is_preferred_philic(ja) = .true. 173 is_found = .true. 174 is_philic = .true. 150 175 end if 151 176 end do … … 153 178 do ja = 1,size(this%bin_phobic) 154 179 if (to_string(this%code_phobic(:,ja)) == code_str & 155 & .and. t o_string(this%optical_model_phobic(1:len(optical_model_str),ja)) &180 & .and. trim(to_string(this%optical_model_phobic(:,ja))) & 156 181 & == optical_model_str) then 157 182 this%is_preferred_phobic(ja) = .true. 183 is_found = .true. 184 is_phobic = .true. 158 185 end if 159 186 end do 160 187 188 if (.not. is_found) then 189 write(nulerr,'(a,a2,a,a,a)') '*** Error: Preferred "', code_str ,'" aerosol optical model "', & 190 & trim(optical_model_str), '" not found in file' 191 call radiation_abort() 192 else if (this%iverbose > 2) then 193 write(nulout,'(a,a2,a,a,a)',advance='no') 'Preferred "', code_str, '" aerosol optical model set to "', & 194 & trim(optical_model_str), '" (' 195 if (is_phobic) then 196 write(nulout,'(a)',advance='no') ' hydrophobic' 197 end if 198 if (is_philic) then 199 write(nulout,'(a)',advance='no') ' hydrophilic' 200 end if 201 write(nulout,'(a)') ' )' 202 end if 203 161 204 if (lhook) call dr_hook('radiation_aerosol_optics_description:preferred_optical_model',1,hook_handle) 162 205 163 206 end subroutine preferred_optical_model 164 207 208 165 209 !--------------------------------------------------------------------- 166 210 ! Return the index to the aerosol optical properties corresponding … … 179 223 180 224 use yomhook, only : lhook, dr_hook, jphook 181 use easy_netcdf, only : netcdf_file182 225 use radiation_io, only : nulout 183 226 … … 234 277 end if 235 278 if (present(optical_model_str)) then 236 if (t o_string(this%optical_model_philic(1:len(optical_model_str),ja)) &279 if (trim(to_string(this%optical_model_philic(:,ja))) & 237 280 & == optical_model_str) then 238 281 ! Requested optical model matches … … 285 328 end if 286 329 if (present(optical_model_str)) then 287 if (t o_string(this%optical_model_phobic(1:len(optical_model_str),ja)) &330 if (trim(to_string(this%optical_model_phobic(:,ja))) & 288 331 & == optical_model_str) then 289 332 ! Requested optical model matches … … 315 358 316 359 if (is_ambiguous) then 317 write(nulout,'(a,a2,a,l1,a)') 'Warning: get_index("', code_str, '",', lhydrophilic, & 360 write(nulout,'(a,a2,a,l,a)') 'Warning: radiation_aerosol_optics_description:get_index("', & 361 & code_str, '",', lhydrophilic, & 318 362 & ',...) does not unambiguously identify an aerosol optical property index' 319 363 end if 320 364 321 365 if (lhook) call dr_hook('radiation_aerosol_optics_description:get_index',1,hook_handle) 322 366 … … 325 369 !--------------------------------------------------------------------- 326 370 ! Utility function to convert an array of single characters to a 327 ! character string (yes Fortran's string handling is a bit rubbish) 371 ! character string (yes Fortran's string handling is a bit 372 ! rubbish). We set NULL characters (ASCII code 0) returned from the 373 ! NetCDF library to spaces, so that TRIM can remove them. 328 374 pure function to_string(arr) result(str) 329 375 character, intent(in) :: arr(:) … … 331 377 integer :: jc 332 378 do jc = 1,size(arr) 333 str(jc:jc) = arr(jc) 379 if (ichar(arr(jc)) == 0) then 380 ! Replace NULL character with a space 381 str(jc:jc) = ' ' 382 else 383 str(jc:jc) = arr(jc) 384 end if 334 385 end do 335 386 end function to_string -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_cloud.F90
r4773 r4853 64 64 ! gridbox area for use in representing 3D effects. This variable 65 65 ! is dimensioned (ncol,nlev). 66 real(jprb), allocatable, 66 real(jprb), allocatable, dimension(:,:) :: inv_cloud_effective_size ! m-1 67 67 68 68 ! Similarly for the in-cloud heterogeneities, used to compute the … … 606 606 607 607 use yomhook, only : lhook, dr_hook, jphook 608 ! USE mod_phys_lmdz_para609 608 610 609 class(cloud_type), intent(inout) :: this -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_cloud_cover.F90
r4773 r4853 19 19 ! 2020-10-07 R. Hogan Ensure iobj1 initialized in case of alpha_obj==0 20 20 21 #include "ecrad_config.h" 22 21 23 module radiation_cloud_cover 22 24 … … 254 256 & * (frac(jlev)+frac(jlev+1)-frac(jlev)*frac(jlev+1)) 255 257 ! Added for DWD (2020) 256 #ifdef __SX__258 #ifdef DWD_VECTOR_OPTIMIZATIONS 257 259 end do 258 260 do jlev = 1,nlev-1 -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_cloud_generator.F90
r4773 r4853 540 540 use radiation_pdf_sampler, only : pdf_sampler_type 541 541 implicit none 542 !#if defined(__GFORTRAN__) || defined(__PGI) || defined(__NEC__)543 !#else544 !!$omp declare simd(sample_from_pdf_simd) uniform(this) &545 !!$omp linear(ref(fsd)) linear(ref(cdf))546 !#endif542 #if defined(__GFORTRAN__) || defined(__PGI) || defined(__NEC__) || defined(__INTEL_LLVM_COMPILER) 543 #else 544 !!$omp declare simd(sample_from_pdf_simd) uniform(this) & 545 !!$omp linear(ref(fsd)) linear(ref(cdf)) 546 #endif 547 547 type(pdf_sampler_type), intent(in) :: this 548 548 -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_cloud_optics_data.F90
r4773 r4853 13 13 ! Email: r.j.hogan@ecmwf.int 14 14 ! 15 16 #include "ecrad_config.h" 15 17 16 18 module radiation_cloud_optics_data … … 48 50 subroutine setup_cloud_optics(this, liq_file_name, ice_file_name, iverbose) 49 51 50 use yomhook, only : lhook, dr_hook, jphook 51 use easy_netcdf, only : netcdf_file 52 use yomhook, only : lhook, dr_hook, jphook 53 #ifdef EASY_NETCDF_READ_MPI 54 use easy_netcdf_read_mpi, only : netcdf_file 55 #else 56 use easy_netcdf, only : netcdf_file 57 #endif 52 58 53 59 class(cloud_optics_type), intent(inout) :: this -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_config.F90
r4773 r4853 34 34 ! 35 35 36 #include "ecrad_config.h" 37 36 38 module radiation_config 37 39 … … 202 204 ! more random numbers being generated? This is the default on NEC 203 205 ! SX. 204 #ifdef __SX__206 #ifdef DWD_VECTOR_OPTIMIZATIONS 205 207 logical :: use_vectorizable_generator = .true. 206 208 #else … … 276 278 277 279 ! Codes describing the gas model 278 integer :: i_gas_model = IGasModelIFSRRTMG 280 integer :: i_gas_model_sw = IGasModelIFSRRTMG 281 integer :: i_gas_model_lw = IGasModelIFSRRTMG 279 282 280 283 ! Optics if i_gas_model==IGasModelMonochromatic. … … 702 705 character(511) :: ssi_override_file_name 703 706 character(63) :: liquid_model_name, ice_model_name, gas_model_name 707 character(63) :: sw_gas_model_name, lw_gas_model_name 704 708 character(63) :: sw_solver_name, lw_solver_name, overlap_scheme_name 705 709 character(63) :: sw_entrapment_name, sw_encroachment_name, cloud_pdf_shape_name … … 709 713 & .false.,.false.,.false.,.false.,.false.,.false.] 710 714 integer :: i_aerosol_type_map(NMaxAerosolTypes) ! More than 256 is an error 711 715 712 716 logical :: do_nearest_spectral_sw_albedo 713 717 logical :: do_nearest_spectral_lw_emiss … … 716 720 integer :: i_sw_albedo_index(NMaxAlbedoIntervals) 717 721 integer :: i_lw_emiss_index (NMaxAlbedoIntervals) 722 integer :: i_gas_model 718 723 719 724 integer :: iunit ! Unit number of namelist file … … 726 731 & do_surface_sw_spectral_flux, do_lw_derivatives, do_toa_spectral_flux, & 727 732 & do_lw_aerosol_scattering, do_lw_cloud_scattering, & 728 & n_regions, directory_name, gas_model_name, &733 & n_regions, directory_name, gas_model_name, sw_gas_model_name, lw_gas_model_name, & 729 734 & ice_optics_override_file_name, liq_optics_override_file_name, & 730 735 & aerosol_optics_override_file_name, cloud_pdf_override_file_name, & … … 815 820 encroachment_scaling = -1.0_jprb 816 821 gas_model_name = '' !DefaultGasModelName 822 sw_gas_model_name = '' !DefaultGasModelName 823 lw_gas_model_name = '' !DefaultGasModelName 817 824 liquid_model_name = '' !DefaultLiquidModelName 818 825 ice_model_name = '' !DefaultIceModelName … … 1014 1021 & 'ice_model_name', this%i_ice_model) 1015 1022 1016 ! Determine gas optics model 1023 ! Determine gas optics model(s) - firstly try the generic gas_model_name 1024 i_gas_model = -1 1017 1025 call get_enum_code(gas_model_name, GasModelName, & 1018 & 'gas_model_name', this%i_gas_model) 1019 1026 & 'gas_model_name', i_gas_model) 1027 if (i_gas_model > -1) then 1028 this%i_gas_model_sw = i_gas_model 1029 this%i_gas_model_lw = i_gas_model 1030 end if 1031 ! ...then the band-specific values 1032 call get_enum_code(sw_gas_model_name, GasModelName, & 1033 & 'sw_gas_model_name', this%i_gas_model_sw) 1034 call get_enum_code(lw_gas_model_name, GasModelName, & 1035 & 'lw_gas_model_name', this%i_gas_model_lw) 1036 1020 1037 ! Determine solvers 1021 1038 call get_enum_code(sw_solver_name, SolverName, & … … 1055 1072 end if 1056 1073 1057 if (this%i_gas_model == IGasModelIFSRRTMG & 1058 & .and. (this%use_general_cloud_optics & 1059 & .or. this%use_general_aerosol_optics)) then 1060 if (this%do_sw .and. this%do_cloud_aerosol_per_sw_g_point) then 1074 if (this%use_general_cloud_optics .or. this%use_general_aerosol_optics) then 1075 if (this%do_sw .and. this%do_cloud_aerosol_per_sw_g_point & 1076 & .and. this%i_gas_model_sw == IGasModelIFSRRTMG) then 1061 1077 write(nulout,'(a)') 'Warning: RRTMG SW only supports cloud/aerosol/surface optical properties per band, not per g-point' 1062 1078 this%do_cloud_aerosol_per_sw_g_point = .false. 1063 1079 end if 1064 if (this%do_lw .and. this%do_cloud_aerosol_per_lw_g_point) then 1080 if (this%do_lw .and. this%do_cloud_aerosol_per_lw_g_point & 1081 & .and. this%i_gas_model_lw == IGasModelIFSRRTMG) then 1065 1082 write(nulout,'(a)') 'Warning: RRTMG LW only supports cloud/aerosol/surface optical properties per band, not per g-point' 1066 1083 this%do_cloud_aerosol_per_lw_g_point = .false. … … 1128 1145 1129 1146 ! If ecCKD gas optics model is being used set relevant file names 1130 if (this%i_gas_model == IGasModelECCKD) then1147 if (this%i_gas_model_sw == IGasModelECCKD .or. this%i_gas_model_lw == IGasModelECCKD) then 1131 1148 1132 1149 ! This gas optics model usually used with general cloud and … … 1138 1155 write(nulout,'(a)') 'Warning: ecCKD gas optics model usually used with general aerosol optics' 1139 1156 end if 1157 1158 end if 1159 1160 if (this%i_gas_model_sw == IGasModelECCKD) then 1140 1161 1141 1162 if (len_trim(this%gas_optics_sw_override_file_name) > 0) then … … 1153 1174 end if 1154 1175 1176 end if 1177 1178 if (this%i_gas_model_lw == IGasModelECCKD) then 1179 1155 1180 if (len_trim(this%gas_optics_lw_override_file_name) > 0) then 1156 1181 if (this%gas_optics_lw_override_file_name(1:1) == '/') then … … 1170 1195 1171 1196 if (this%use_spectral_solar_cycle) then 1172 if (this%i_gas_model /= IGasModelECCKD) then1197 if (this%i_gas_model_sw /= IGasModelECCKD) then 1173 1198 write(nulerr,'(a)') '*** Error: solar cycle only available with ecCKD gas optics model' 1174 1199 call radiation_abort('Radiation configuration error') … … 1278 1303 end if 1279 1304 1280 ! In the monochromatic case we need to override the liquid, ice 1281 ! and aerosol models to ensure compatibility 1282 if (this%i_gas_model == IGasModelMonochromatic) then 1305 if (this%i_gas_model_sw == IGasModelMonochromatic .or. this%i_gas_model_lw == IGasModelMonochromatic) then 1306 1307 if (this%i_gas_model_sw /= this%i_gas_model_lw) then 1308 write(nulerr,'(a,i0)') '*** Error: Monochromatic gas optics model must be used in shortwave and longwave' 1309 call radiation_abort('Radiation configuration error') 1310 end if 1311 1312 ! In the monochromatic case we need to override the liquid, ice 1313 ! and aerosol models to ensure compatibility 1283 1314 this%i_liq_model = ILiquidModelMonochromatic 1284 1315 this%i_ice_model = IIceModelMonochromatic 1285 1316 this%use_aerosols = .false. 1317 1286 1318 end if 1287 1319 … … 1392 1424 call print_logical(' Saving spectral flux profiles', & 1393 1425 & 'do_save_spectral_flux', this%do_save_spectral_flux) 1394 call print_enum(' Gas model is', GasModelName, 'i_gas_model', & 1395 & this%i_gas_model) 1426 call print_enum(' Shortwave gas model is', GasModelName, 'i_gas_model_sw', & 1427 & this%i_gas_model_sw) 1428 call print_enum(' Longwave gas model is', GasModelName, 'i_gas_model_lw', & 1429 & this%i_gas_model_lw) 1396 1430 call print_logical(' Aerosols are', 'use_aerosols', this%use_aerosols) 1397 1431 if (this%use_aerosols) then … … 1481 1515 & 'i_solver_sw', this%i_solver_sw) 1482 1516 1483 if (this%i_gas_model == IGasModelMonochromatic) then1517 if (this%i_gas_model_sw == IGasModelMonochromatic) then 1484 1518 call print_real(' Shortwave atmospheric optical depth', & 1485 1519 & 'mono_sw_total_od', this%mono_sw_total_od) … … 1502 1536 & this%i_solver_lw) 1503 1537 1504 if (this%i_gas_model == IGasModelMonochromatic) then1538 if (this%i_gas_model_lw == IGasModelMonochromatic) then 1505 1539 if (this%mono_lw_wavelength > 0.0_jprb) then 1506 1540 call print_real(' Longwave effective wavelength (m)', & -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_ecckd.F90
r4773 r4853 15 15 ! 16 16 17 #include "ecrad_config.h" 18 17 19 module radiation_ecckd 18 20 … … 105 107 ! Vectorized version of the optical depth look-up performs better on 106 108 ! NEC, but slower on x86 107 #ifdef __SX__109 #ifdef DWD_VECTOR_OPTIMIZATIONS 108 110 procedure :: calc_optical_depth => calc_optical_depth_ckd_model_vec 109 111 #else … … 125 127 subroutine read_ckd_model(this, filename, iverbose) 126 128 127 use easy_netcdf, only : netcdf_file 129 #ifdef EASY_NETCDF_READ_MPI 130 use easy_netcdf_read_mpi, only : netcdf_file 131 #else 132 use easy_netcdf, only : netcdf_file 133 #endif 128 134 !use radiation_io, only : nulerr, radiation_abort 129 use yomhook, only : lhook, dr_hook, jphook135 use yomhook, only : lhook, dr_hook, jphook 130 136 131 137 class(ckd_model_type), intent(inout) :: this … … 166 172 this%d_log_pressure = log(pressure_lut(2)) - this%log_pressure1 167 173 call file%get('temperature', temperature_full) 168 ! AI oct 2023 ajout pour le double appel de ecrad169 if (allocated(this%temperature1)) deallocate(this%temperature1)170 174 allocate(this%temperature1(this%npress)); 171 175 this%temperature1 = temperature_full(:,1) … … 200 204 ! Read gases 201 205 call file%get('n_gases', this%ngas) 202 if (allocated(this%single_gas)) deallocate(this%single_gas)203 206 allocate(this%single_gas(this%ngas)) 204 207 call file%get_global_attribute('constituent_id', constituent_id) … … 292 295 subroutine read_spectral_solar_cycle(this, filename, iverbose, use_updated_solar_spectrum) 293 296 294 use easy_netcdf, only : netcdf_file 295 use radiation_io, only : nulout, nulerr, radiation_abort 296 use yomhook, only : lhook, dr_hook, jphook 297 #ifdef EASY_NETCDF_READ_MPI 298 use easy_netcdf_read_mpi, only : netcdf_file 299 #else 300 use easy_netcdf, only : netcdf_file 301 #endif 302 use radiation_io, only : nulout, nulerr, radiation_abort 303 use yomhook, only : lhook, dr_hook, jphook 297 304 298 305 ! Reference total solar irradiance (W m-2) … … 450 457 subroutine calc_optical_depth_ckd_model(this, ncol, nlev, istartcol, iendcol, nmaxgas, & 451 458 & pressure_hl, temperature_fl, mole_fraction_fl, & 452 & optical_depth_fl, rayleigh_od_fl )459 & optical_depth_fl, rayleigh_od_fl, concentration_scaling) 453 460 454 461 use yomhook, only : lhook, dr_hook, jphook … … 466 473 ! Gas mole fractions at full levels (mol mol-1), dimensioned (ncol,nlev,nmaxgas) 467 474 real(jprb), intent(in) :: mole_fraction_fl(ncol,nlev,nmaxgas) 475 ! Optional concentration scaling of each gas 476 real(jprb), optional, intent(in) :: concentration_scaling(nmaxgas) 468 477 469 478 ! Output variables … … 486 495 487 496 real(jprb) :: multiplier(nlev), simple_multiplier(nlev), global_multiplier, temperature1 497 real(jprb) :: scaling 488 498 489 499 ! Indices and weights in temperature, pressure and concentration interpolation … … 547 557 multiplier = simple_multiplier * mole_fraction_fl(jcol,:,igascode) 548 558 559 if (present(concentration_scaling)) then 560 multiplier = multiplier * concentration_scaling(igascode) 561 end if 562 549 563 do jlev = 1,nlev 550 564 optical_depth_fl(:,jlev,jcol) = optical_depth_fl(:,jlev,jcol) & … … 557 571 case (IConcDependenceRelativeLinear) 558 572 molar_abs => this%single_gas(jgas)%molar_abs 559 multiplier = simple_multiplier * (mole_fraction_fl(jcol,:,igascode) & 560 & - single_gas%reference_mole_frac) 573 574 if (present(concentration_scaling)) then 575 multiplier = simple_multiplier & 576 & * (mole_fraction_fl(jcol,:,igascode)*concentration_scaling(igascode) & 577 & - single_gas%reference_mole_frac) 578 else 579 multiplier = simple_multiplier * (mole_fraction_fl(jcol,:,igascode) & 580 & - single_gas%reference_mole_frac) 581 end if 582 561 583 do jlev = 1,nlev 562 584 optical_depth_fl(:,jlev,jcol) = optical_depth_fl(:,jlev,jcol) & … … 579 601 580 602 case (IConcDependenceLUT) 603 604 if (present(concentration_scaling)) then 605 scaling = concentration_scaling(igascode) 606 else 607 scaling = 1.0_jprb 608 end if 609 581 610 ! Logarithmic interpolation in concentration space 582 611 molar_abs_conc => this%single_gas(jgas)%molar_abs_conc … … 584 613 do jlev = 1,nlev 585 614 ! Take care of mole_fraction == 0 586 log_conc = log(max(mole_fraction_fl(jcol,jlev,igascode) , mole_frac1))615 log_conc = log(max(mole_fraction_fl(jcol,jlev,igascode)*scaling, mole_frac1)) 587 616 cindex1 = (log_conc - single_gas%log_mole_frac1) / single_gas%d_log_mole_frac 588 617 cindex1 = 1.0_jprb + max(0.0_jprb, min(cindex1, single_gas%n_mole_frac-1.0001_jprb)) … … 601 630 do jlev = 1,nlev 602 631 optical_depth_fl(:,jlev,jcol) = optical_depth_fl(:,jlev,jcol) & 603 & + (simple_multiplier(jlev) * mole_fraction_fl(jcol,jlev,igascode) ) * ( &632 & + (simple_multiplier(jlev) * mole_fraction_fl(jcol,jlev,igascode) * scaling) * ( & 604 633 & (cw1(jlev) * tw1(jlev) * pw1(jlev)) * molar_abs_conc(:,ip1(jlev),it1(jlev),ic1(jlev)) & 605 634 & +(cw1(jlev) * tw1(jlev) * pw2(jlev)) * molar_abs_conc(:,ip1(jlev)+1,it1(jlev),ic1(jlev)) & -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_ecckd_gas.F90
r4773 r4853 14 14 ! License: see the COPYING file for details 15 15 ! 16 17 #include "ecrad_config.h" 16 18 17 19 module radiation_ecckd_gas … … 82 84 subroutine read_ckd_gas(this, file, gas_name, i_gas_code) 83 85 84 use easy_netcdf, only : netcdf_file 86 #ifdef EASY_NETCDF_READ_MPI 87 use easy_netcdf_read_mpi, only : netcdf_file 88 #else 89 use easy_netcdf, only : netcdf_file 90 #endif 85 91 86 92 class(ckd_gas_type), intent(inout) :: this -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_ecckd_interface.F90
r4773 r4853 39 39 if (lhook) call dr_hook('radiation_ecckd_interface:setup_gas_optics',0,hook_handle) 40 40 41 if (config%do_sw ) then41 if (config%do_sw .and. config%i_gas_model_sw == IGasModelECCKD) then 42 42 43 43 ! Read shortwave ecCKD gas optics NetCDF file … … 57 57 end if 58 58 59 ! if (allocated(config%i_band_from_g_sw)) deallocate(config%i_band_from_g_sw) 60 ! allocate(config%i_band_from_g_sw(config%n_g_sw)) 61 ! if (allocated(config%i_band_from_reordered_g_sw)) deallocate(config%i_band_from_reordered_g_sw) 62 ! allocate(config%i_band_from_reordered_g_sw(config%n_g_sw)) 63 ! if (allocated(config%i_g_from_reordered_g_sw)) deallocate(config%i_g_from_reordered_g_sw) 64 ! allocate(config%i_g_from_reordered_g_sw(config%n_g_sw)) 65 if (.not.allocated(config%i_band_from_g_sw)) & 66 allocate(config%i_band_from_g_sw(config%n_g_sw)) 67 if (.not.allocated(config%i_band_from_reordered_g_sw)) & 68 allocate(config%i_band_from_reordered_g_sw(config%n_g_sw)) 69 if (.not.allocated(config%i_g_from_reordered_g_sw)) & 70 allocate(config%i_g_from_reordered_g_sw(config%n_g_sw)) 59 allocate(config%i_band_from_g_sw (config%n_g_sw)) 60 allocate(config%i_band_from_reordered_g_sw(config%n_g_sw)) 61 allocate(config%i_g_from_reordered_g_sw (config%n_g_sw)) 71 62 72 63 if (config%do_cloud_aerosol_per_sw_g_point) then … … 93 84 end if 94 85 95 if (config%do_lw ) then86 if (config%do_lw .and. config%i_gas_model_lw == IGasModelECCKD) then 96 87 97 88 ! Read longwave ecCKD gas optics NetCDF file … … 111 102 end if 112 103 113 ! if (allocated(config%i_band_from_g_lw)) deallocate(config%i_band_from_g_lw) 114 ! allocate(config%i_band_from_g_lw (config%n_g_lw)) 115 ! if (allocated(config%i_band_from_reordered_g_lw)) deallocate(config%i_band_from_reordered_g_lw) 116 ! allocate(config%i_band_from_reordered_g_lw(config%n_g_lw)) 117 ! if (allocated(config%i_g_from_reordered_g_lw)) deallocate(config%i_g_from_reordered_g_lw) 118 ! allocate(config%i_g_from_reordered_g_lw (config%n_g_lw)) 119 if (.not.allocated(config%i_band_from_g_lw)) & 120 allocate(config%i_band_from_g_lw (config%n_g_lw)) 121 if (.not.allocated(config%i_band_from_reordered_g_lw)) & 122 allocate(config%i_band_from_reordered_g_lw(config%n_g_lw)) 123 if (.not.allocated(config%i_g_from_reordered_g_lw)) & 124 allocate(config%i_g_from_reordered_g_lw (config%n_g_lw)) 125 104 allocate(config%i_band_from_g_lw (config%n_g_lw)) 105 allocate(config%i_band_from_reordered_g_lw(config%n_g_lw)) 106 allocate(config%i_g_from_reordered_g_lw (config%n_g_lw)) 126 107 127 108 if (config%do_cloud_aerosol_per_lw_g_point) then … … 199 180 use yomhook, only : lhook, dr_hook, jphook 200 181 201 use radiation_config, only : config_type 182 use radiation_config, only : config_type, IGasModelECCKD 202 183 use radiation_thermodynamics, only : thermodynamics_type 203 184 use radiation_single_level, only : single_level_type … … 242 223 real(jprb) :: temperature_fl(istartcol:iendcol,nlev) 243 224 244 integer :: jcol 225 real(jprb) :: concentration_scaling(NMaxGases) 226 227 logical :: is_volume_mixing_ratio 228 229 integer :: jcol, jlev, jg 245 230 246 231 real(jphook) :: hook_handle … … 259 244 & / (thermodynamics%pressure_hl(istartcol:iendcol,1:nlev) & 260 245 & +thermodynamics%pressure_hl(istartcol:iendcol,2:nlev+1)) 261 262 if (config%do_sw) then 263 264 call config%gas_optics_sw%calc_optical_depth(ncol,nlev,istartcol,iendcol, & 265 & NMaxGases, thermodynamics%pressure_hl, & 266 & temperature_fl, & 267 & gas%mixing_ratio, & 268 ! & reshape(gas%mixing_ratio(istartcol:iendcol,:,:), & 269 ! & [nlev,iendcol-istartcol+1,NMaxGases],order=[2,1,3]), & 270 & od_sw, rayleigh_od_fl=ssa_sw) 246 247 ! Check that the gas concentrations are stored in volume mixing 248 ! ratio with no scaling; if not, return a vector of scalings 249 call gas%assert_units(IVolumeMixingRatio, scale_factor=1.0_jprb, & 250 & istatus=is_volume_mixing_ratio) 251 if (.not. is_volume_mixing_ratio) then 252 call gas%get_scaling(IVolumeMixingRatio, concentration_scaling) 253 else 254 concentration_scaling = 1.0_jprb 255 end if 256 257 if (config%do_sw .and. config%i_gas_model_sw == IGasModelECCKD) then 258 259 if (is_volume_mixing_ratio) then 260 call config%gas_optics_sw%calc_optical_depth(ncol,nlev,istartcol,iendcol, & 261 & NMaxGases, thermodynamics%pressure_hl, & 262 & temperature_fl, gas%mixing_ratio, & 263 & od_sw, rayleigh_od_fl=ssa_sw) 264 else 265 call config%gas_optics_sw%calc_optical_depth(ncol,nlev,istartcol,iendcol, & 266 & NMaxGases, thermodynamics%pressure_hl, & 267 & temperature_fl, gas%mixing_ratio, & 268 & od_sw, rayleigh_od_fl=ssa_sw, concentration_scaling=concentration_scaling) 269 end if 270 271 271 ! At this point od_sw = absorption optical depth and ssa_sw = 272 272 ! rayleigh optical depth: convert to total optical depth and 273 273 ! single-scattering albedo 274 od_sw = od_sw + ssa_sw 275 ssa_sw = ssa_sw / od_sw 274 do jcol = istartcol,iendcol 275 do jlev = 1, nlev 276 do jg = 1, config%n_g_sw 277 od_sw(jg,jlev,jcol) = od_sw(jg,jlev,jcol) + ssa_sw(jg,jlev,jcol) 278 ssa_sw(jg,jlev,jcol) = ssa_sw(jg,jlev,jcol) / od_sw(jg,jlev,jcol) 279 end do 280 end do 281 end do 276 282 277 283 if (present(incoming_sw)) then … … 287 293 end if 288 294 289 if (config%do_lw) then 290 291 call config%gas_optics_lw%calc_optical_depth(ncol,nlev,istartcol,iendcol, & 292 & NMaxGases, thermodynamics%pressure_hl, & 293 & temperature_fl, & 294 & gas%mixing_ratio, & 295 ! & reshape(gas%mixing_ratio(istartcol:iendcol,:,:), & 296 ! & [nlev,iendcol-istartcol+1,NMaxGases],order=[2,1,3]), & 297 & od_lw) 295 if (config%do_lw .and. config%i_gas_model_lw == IGasModelECCKD) then 296 297 if (is_volume_mixing_ratio) then 298 call config%gas_optics_lw%calc_optical_depth(ncol,nlev,istartcol,iendcol, & 299 & NMaxGases, thermodynamics%pressure_hl, & 300 & temperature_fl, gas%mixing_ratio, & 301 & od_lw) 302 else 303 call config%gas_optics_lw%calc_optical_depth(ncol,nlev,istartcol,iendcol, & 304 & NMaxGases, thermodynamics%pressure_hl, & 305 & temperature_fl, gas%mixing_ratio, & 306 & od_lw, concentration_scaling=concentration_scaling) 307 end if 298 308 299 309 ! Calculate the Planck function for each g point … … 305 315 & single_level%skin_temperature(istartcol:iendcol), & 306 316 & lw_emission(:,:)) 317 !NEC$ forced_collapse 307 318 lw_emission = lw_emission * (1.0_jprb - lw_albedo) 308 319 -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_flux.F90
r4773 r4853 20 20 ! 2021-01-20 R. Hogan Added heating_rate_out_of_physical_bounds function 21 21 ! 2022-12-07 R. Hogan Added top-of-atmosphere spectral output 22 23 #include "ecrad_config.h" 22 24 23 25 module radiation_flux … … 117 119 118 120 ! Added for DWD (2020) 119 #ifdef __SX__121 #ifdef DWD_VECTOR_OPTIMIZATIONS 120 122 logical, parameter :: use_indexed_sum_vec = .true. 121 123 #else -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_gas.F90
r4773 r4853 72 72 procedure :: assert_units => assert_units_gas 73 73 procedure :: get => get_gas 74 procedure :: get_scaling 74 75 procedure :: reverse => reverse_gas 75 76 procedure :: out_of_physical_bounds … … 355 356 real(jprb), optional, intent(in) :: scale_factor 356 357 357 integer :: ig358 integer :: jg 358 359 359 360 ! Scaling factor to convert from old to new … … 396 397 end if 397 398 else 398 do ig = 1,this%ntype399 call this%set_units(iunits, igas=this%icode( ig), scale_factor=new_sf)399 do jg = 1,this%ntype 400 call this%set_units(iunits, igas=this%icode(jg), scale_factor=new_sf) 400 401 end do 401 402 end if … … 403 404 end subroutine set_units_gas 404 405 405 406 407 !--------------------------------------------------------------------- 408 ! Return a vector indicating the scaling that one would need to 409 ! apply to each gas in order to obtain the dimension units in 410 ! "iunits" (which can be IVolumeMixingRatio or IMassMixingRatio) 411 subroutine get_scaling(this, iunits, scaling) 412 class(gas_type), intent(in) :: this 413 integer, intent(in) :: iunits 414 real(jprb), intent(out) :: scaling(NMaxGases) 415 integer :: jg 416 417 scaling = this%scale_factor 418 do jg = 1,NMaxGases 419 if (iunits == IMassMixingRatio .and. this%iunits(jg) == IVolumeMixingRatio) then 420 scaling(jg) = scaling(jg) * GasMolarMass(jg) / AirMolarMass 421 else if (iunits == IVolumeMixingRatio .and. this%iunits(jg) == IMassMixingRatio) then 422 scaling(jg) = scaling(jg) * AirMolarMass / GasMolarMass(jg) 423 end if 424 end do 425 426 end subroutine get_scaling 427 428 406 429 !--------------------------------------------------------------------- 407 430 ! Assert that gas mixing ratio units are "iunits", applying to gas 408 431 ! with ID "igas" if present, otherwise to all gases. Otherwise the 409 ! program will exit. Otional argument scale factor specifies any 410 ! subsequent multiplication to apply; for PPMV one would use 411 ! iunits=IVolumeMixingRatio and scale_factor=1.0e6. 412 recursive subroutine assert_units_gas(this, iunits, igas, scale_factor) 432 ! program will exit, except if the optional argument "istatus" is 433 ! provided in which case it will return true if the units are 434 ! correct and false if they are not. Optional argument scale factor 435 ! specifies any subsequent multiplication to apply; for PPMV one 436 ! would use iunits=IVolumeMixingRatio and scale_factor=1.0e6. 437 recursive subroutine assert_units_gas(this, iunits, igas, scale_factor, istatus) 413 438 414 439 use radiation_io, only : nulerr, radiation_abort 415 440 416 class(gas_type), intent(in) :: this 417 integer, intent(in) :: iunits 418 integer, optional, intent(in) :: igas 419 real(jprb), optional, intent(in) :: scale_factor 420 421 integer :: ig 441 class(gas_type), intent(in) :: this 442 integer, intent(in) :: iunits 443 integer, optional, intent(in) :: igas 444 real(jprb), optional, intent(in) :: scale_factor 445 logical, optional, intent(out) :: istatus 446 447 integer :: jg 422 448 423 449 real(jprb) :: sf … … 429 455 end if 430 456 457 if (present(istatus)) then 458 istatus = .true. 459 end if 460 431 461 if (present(igas)) then 432 462 if (this%is_present(igas)) then 433 463 if (iunits /= this%iunits(igas)) then 434 write(nulerr,'(a,a,a)') '*** Error: ', trim(GasName(igas)), & 435 & ' is not in the required units' 436 call radiation_abort() 464 if (present(istatus)) then 465 istatus = .false. 466 else 467 write(nulerr,'(a,a,a)') '*** Error: ', trim(GasName(igas)), & 468 & ' is not in the required units' 469 call radiation_abort() 470 end if 437 471 else if (sf /= this%scale_factor(igas)) then 438 write(nulerr,'(a,a,a,e12.4,a,e12.4)') '*** Error: ', GasName(igas), & 439 & ' scaling of ', this%scale_factor(igas), & 440 & ' does not match required ', sf 441 call radiation_abort() 472 if (present(istatus)) then 473 istatus = .false. 474 else 475 write(nulerr,'(a,a,a,e12.4,a,e12.4)') '*** Error: ', GasName(igas), & 476 & ' scaling of ', this%scale_factor(igas), & 477 & ' does not match required ', sf 478 call radiation_abort() 479 end if 442 480 end if 443 481 end if 444 482 else 445 do ig = 1,this%ntype446 call this%assert_units(iunits, igas=this%icode( ig), scale_factor=sf)483 do jg = 1,this%ntype 484 call this%assert_units(iunits, igas=this%icode(jg), scale_factor=sf, istatus=istatus) 447 485 end do 448 486 end if -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_general_cloud_optics.F90
r4773 r4853 75 75 ! Allocate structures 76 76 if (config%do_sw) then 77 if (allocated(config%cloud_optics_sw)) deallocate(config%cloud_optics_sw)78 77 allocate(config%cloud_optics_sw(config%n_cloud_types)) 79 78 end if 80 79 81 80 if (config%do_lw) then 82 if (allocated(config%cloud_optics_lw)) deallocate(config%cloud_optics_lw)83 81 allocate(config%cloud_optics_lw(config%n_cloud_types)) 84 82 end if … … 172 170 real(jprb), dimension(istartcol:iendcol,nlev) :: water_path 173 171 174 integer :: jtype, jcol, jlev 172 integer :: jtype, jcol, jlev, jg 175 173 176 174 real(jphook) :: hook_handle … … 275 273 if (cloud%fraction(jcol,jlev) > 0.0_jprb) then 276 274 ! Scale to get asymmetry factor and single scattering albedo 277 g_sw_cloud(:,jlev,jcol) = g_sw_cloud(:,jlev,jcol) & 278 & / max(ssa_sw_cloud(:,jlev,jcol), 1.0e-15_jprb) 279 ssa_sw_cloud(:,jlev,jcol) = ssa_sw_cloud(:,jlev,jcol) & 280 & / max(od_sw_cloud(:,jlev,jcol), 1.0e-15_jprb) 275 do jg = 1, config%n_bands_sw 276 g_sw_cloud(jg,jlev,jcol) = g_sw_cloud(jg,jlev,jcol) & 277 & / max(ssa_sw_cloud(jg,jlev,jcol), 1.0e-15_jprb) 278 ssa_sw_cloud(jg,jlev,jcol) = ssa_sw_cloud(jg,jlev,jcol) & 279 & / max(od_sw_cloud(jg,jlev,jcol), 1.0e-15_jprb) 280 end do 281 281 end if 282 282 end do -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_general_cloud_optics_data.F90
r4802 r4853 15 15 ! 16 16 17 #include "ecrad_config.h" 18 17 19 module radiation_general_cloud_optics_data 18 20 … … 73 75 74 76 use yomhook, only : lhook, dr_hook, jphook 75 use easy_netcdf, only : netcdf_file 77 #ifdef EASY_NETCDF_READ_MPI 78 use easy_netcdf_read_mpi, only : netcdf_file 79 #else 80 use easy_netcdf, only : netcdf_file 81 #endif 76 82 use radiation_spectral_definition, only : spectral_definition_type 77 83 use radiation_io, only : nulout, nulerr, radiation_abort … … 181 187 182 188 ! Thin averaging 183 184 ! Circumvent ifort bug (see https://github.com/ecmwf-ifs/ecrad/issues/13):185 allocate(this%mass_ext(size(mapping, 1), nre))186 187 189 this%mass_ext = matmul(mapping, mass_ext) 188 190 this%ssa = matmul(mapping, mass_ext*ssa) / this%mass_ext … … 267 269 & scat_asymmetry ! Scattering optical depth x asymmetry factor 268 270 269 real(jprb) :: od_local (ng)271 real(jprb) :: od_local 270 272 271 273 real(jprb) :: re_index, weight1, weight2 272 274 integer :: ire 273 275 274 integer :: jcol, jlev 276 integer :: jcol, jlev, jg 275 277 276 278 real(jphook) :: hook_handle … … 287 289 weight2 = re_index - ire 288 290 weight1 = 1.0_jprb - weight2 289 od_local = water_path(jcol, jlev) * (weight1*this%mass_ext(:,ire) & 290 & +weight2*this%mass_ext(:,ire+1)) 291 od(:,jlev,jcol) = od(:,jlev,jcol) + od_local 292 od_local = od_local * (weight1*this%ssa(:,ire) & 293 & +weight2*this%ssa(:,ire+1)) 294 scat_od(:,jlev,jcol) = scat_od(:,jlev,jcol) + od_local 295 scat_asymmetry(:,jlev,jcol) = scat_asymmetry(:,jlev,jcol) & 296 & + od_local * (weight1*this%asymmetry(:,ire) & 297 & +weight2*this%asymmetry(:,ire+1)) 291 do jg = 1, ng 292 od_local = water_path(jcol, jlev) * (weight1*this%mass_ext(jg,ire) & 293 & +weight2*this%mass_ext(jg,ire+1)) 294 od(jg,jlev,jcol) = od(jg,jlev,jcol) + od_local 295 od_local = od_local * (weight1*this%ssa(jg,ire) & 296 & +weight2*this%ssa(jg,ire+1)) 297 scat_od(jg,jlev,jcol) = scat_od(jg,jlev,jcol) + od_local 298 scat_asymmetry(jg,jlev,jcol) = scat_asymmetry(jg,jlev,jcol) & 299 & + od_local * (weight1*this%asymmetry(jg,ire) & 300 & +weight2*this%asymmetry(jg,ire+1)) 301 end do 302 298 303 end if 299 304 end do -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_ifs_rrtm.F90
r4773 r4853 41 41 42 42 use radiation_config 43 use radiation_spectral_definition, only & 44 & : SolarReferenceTemperature, TerrestrialReferenceTemperature 43 45 44 46 type(config_type), intent(inout), target :: config … … 65 67 & 44, 107, 94, 14, 108, 15, 16, 109, 17, 18, 110, 111, 112 & 66 68 & /) 69 70 logical :: do_sw, do_lw 67 71 68 72 real(jphook) :: hook_handle … … 77 81 if (lhook) call dr_hook('radiation_ifs_rrtm:setup_gas_optics',0,hook_handle) 78 82 83 do_sw = (config%do_sw .and. config%i_gas_model_sw == IGasModelIFSRRTMG) 84 do_lw = (config%do_lw .and. config%i_gas_model_lw == IGasModelIFSRRTMG) 85 79 86 ! The IFS implementation of RRTMG uses many global variables. In 80 87 ! the IFS these will have been set up already; otherwise set them … … 85 92 call SURRTPK 86 93 call SURRTRF 87 call RRTM_INIT_140GP(directory) 88 call SRTM_INIT(directory) 94 if (do_lw) then 95 call RRTM_INIT_140GP(directory) 96 end if 97 if (do_sw) then 98 call SRTM_INIT(directory) 99 end if 89 100 end if 90 101 91 ! Cloud and aerosol properties can only be defined per band 92 config%do_cloud_aerosol_per_sw_g_point = .false. 93 config%do_cloud_aerosol_per_lw_g_point = .false. 94 95 config%n_g_sw = jpgsw 96 config%n_g_lw = jpglw 97 config%n_bands_sw = 14 98 config%n_bands_lw = 16 99 100 ! Wavenumber ranges of each band may be needed so that the user 101 ! can compute UV and photosynthetically active radiation for a 102 ! particular wavelength range 103 call config%gas_optics_sw%spectral_def%allocate_bands_only( & 104 & [2600.0_jprb, 3250.0_jprb, 4000.0_jprb, 4650.0_jprb, 5150.0_jprb, 6150.0_jprb, 7700.0_jprb, & 105 & 8050.0_jprb, 12850.0_jprb, 16000.0_jprb, 22650.0_jprb, 29000.0_jprb, 38000.0_jprb, 820.0_jprb], & 106 & [3250.0_jprb, 4000.0_jprb, 4650.0_jprb, 5150.0_jprb, 6150.0_jprb, 7700.0_jprb, 8050.0_jprb, & 107 & 12850.0_jprb, 16000.0_jprb, 22650.0_jprb, 29000.0_jprb, 38000.0_jprb, 50000.0_jprb, 2600.0_jprb]) 108 call config%gas_optics_lw%spectral_def%allocate_bands_only( & 109 & [10.0_jprb, 350.0_jprb, 500.0_jprb, 630.0_jprb, 700.0_jprb, 820.0_jprb, 980.0_jprb, 1080.0_jprb, & 110 & 1180.0_jprb, 1390.0_jprb, 1480.0_jprb, 1800.0_jprb, 2080.0_jprb, 2250.0_jprb, 2380.0_jprb, 2600.0_jprb], & 111 & [350.0_jprb, 500.0_jprb, 630.0_jprb, 700.0_jprb, 820.0_jprb, 980.0_jprb, 1080.0_jprb, 1180.0_jprb, & 112 & 1390.0_jprb, 1480.0_jprb, 1800.0_jprb, 2080.0_jprb, 2250.0_jprb, 2380.0_jprb, 2600.0_jprb, 3250.0_jprb]) 113 114 allocate(config%i_band_from_g_sw (config%n_g_sw)) 115 allocate(config%i_band_from_g_lw (config%n_g_lw)) 116 allocate(config%i_band_from_reordered_g_sw(config%n_g_sw)) 117 allocate(config%i_band_from_reordered_g_lw(config%n_g_lw)) 118 allocate(config%i_g_from_reordered_g_sw(config%n_g_sw)) 119 allocate(config%i_g_from_reordered_g_lw(config%n_g_lw)) 120 121 ! Shortwave starts at 16: need to start at 1 122 config%i_band_from_g_sw = ngb_sw - ngb_sw(1)+1 123 config%i_band_from_g_lw = ngb_lw 124 125 if (config%i_solver_sw == ISolverSpartacus) then 126 ! SPARTACUS requires g points ordered in approximately 127 ! increasing order of optical depth 128 config%i_g_from_reordered_g_sw = RRTM_GPOINT_REORDERING_SW 129 else 130 ! Implied-do for no reordering 131 ! config%i_g_from_reordered_g_sw = RRTM_GPOINT_REORDERING_SW 132 config%i_g_from_reordered_g_sw = (/ (irep, irep=1,config%n_g_sw) /) 102 if (do_sw) then 103 104 ! Cloud and aerosol properties can only be defined per band 105 config%do_cloud_aerosol_per_sw_g_point = .false. 106 config%n_g_sw = jpgsw 107 config%n_bands_sw = 14 108 ! Wavenumber ranges of each band may be needed so that the user 109 ! can compute UV and photosynthetically active radiation for a 110 ! particular wavelength range 111 call config%gas_optics_sw%spectral_def%allocate_bands_only(SolarReferenceTemperature, & 112 & [2600.0_jprb, 3250.0_jprb, 4000.0_jprb, 4650.0_jprb, 5150.0_jprb, 6150.0_jprb, 7700.0_jprb, & 113 & 8050.0_jprb, 12850.0_jprb, 16000.0_jprb, 22650.0_jprb, 29000.0_jprb, 38000.0_jprb, 820.0_jprb], & 114 & [3250.0_jprb, 4000.0_jprb, 4650.0_jprb, 5150.0_jprb, 6150.0_jprb, 7700.0_jprb, 8050.0_jprb, & 115 & 12850.0_jprb, 16000.0_jprb, 22650.0_jprb, 29000.0_jprb, 38000.0_jprb, 50000.0_jprb, 2600.0_jprb]) 116 allocate(config%i_band_from_g_sw (config%n_g_sw)) 117 allocate(config%i_band_from_reordered_g_sw(config%n_g_sw)) 118 allocate(config%i_g_from_reordered_g_sw (config%n_g_sw)) 119 ! Shortwave starts at 16: need to start at 1 120 config%i_band_from_g_sw = ngb_sw - ngb_sw(1)+1 121 122 if (config%i_solver_sw == ISolverSpartacus) then 123 ! SPARTACUS requires g points ordered in approximately 124 ! increasing order of optical depth 125 config%i_g_from_reordered_g_sw = RRTM_GPOINT_REORDERING_SW 126 else 127 ! Implied-do for no reordering 128 ! config%i_g_from_reordered_g_sw = RRTM_GPOINT_REORDERING_SW 129 config%i_g_from_reordered_g_sw = (/ (irep, irep=1,config%n_g_sw) /) 130 end if 131 132 config%i_band_from_reordered_g_sw & 133 = config%i_band_from_g_sw(config%i_g_from_reordered_g_sw) 134 135 ! The i_spec_* variables are used solely for storing spectral 136 ! data, and this can either be by band or by g-point 137 if (config%do_save_spectral_flux .or. config%do_toa_spectral_flux) then 138 if (config%do_save_gpoint_flux) then 139 config%n_spec_sw = config%n_g_sw 140 config%i_spec_from_reordered_g_sw => config%i_g_from_reordered_g_sw 141 else 142 config%n_spec_sw = config%n_bands_sw 143 config%i_spec_from_reordered_g_sw => config%i_band_from_reordered_g_sw 144 end if 145 else 146 config%n_spec_sw = 0 147 nullify(config%i_spec_from_reordered_g_sw) 148 end if 149 133 150 end if 134 151 135 if (config%i_solver_lw == ISolverSpartacus) then 136 ! SPARTACUS requires g points ordered in approximately 137 ! increasing order of optical depth 138 config%i_g_from_reordered_g_lw = RRTM_GPOINT_REORDERING_LW 139 else 140 ! Implied-do for no reordering 141 config%i_g_from_reordered_g_lw = (/ (irep, irep=1,config%n_g_lw) /) 152 if (do_lw) then 153 ! Cloud and aerosol properties can only be defined per band 154 config%do_cloud_aerosol_per_lw_g_point = .false. 155 config%n_g_lw = jpglw 156 config%n_bands_lw = 16 157 call config%gas_optics_lw%spectral_def%allocate_bands_only(TerrestrialReferenceTemperature, & 158 & [10.0_jprb, 350.0_jprb, 500.0_jprb, 630.0_jprb, 700.0_jprb, 820.0_jprb, 980.0_jprb, 1080.0_jprb, & 159 & 1180.0_jprb, 1390.0_jprb, 1480.0_jprb, 1800.0_jprb, 2080.0_jprb, 2250.0_jprb, 2380.0_jprb, 2600.0_jprb], & 160 & [350.0_jprb, 500.0_jprb, 630.0_jprb, 700.0_jprb, 820.0_jprb, 980.0_jprb, 1080.0_jprb, 1180.0_jprb, & 161 & 1390.0_jprb, 1480.0_jprb, 1800.0_jprb, 2080.0_jprb, 2250.0_jprb, 2380.0_jprb, 2600.0_jprb, 3250.0_jprb]) 162 allocate(config%i_band_from_g_lw (config%n_g_lw)) 163 allocate(config%i_band_from_reordered_g_lw(config%n_g_lw)) 164 allocate(config%i_g_from_reordered_g_lw (config%n_g_lw)) 165 config%i_band_from_g_lw = ngb_lw 166 167 if (config%i_solver_lw == ISolverSpartacus) then 168 ! SPARTACUS requires g points ordered in approximately 169 ! increasing order of optical depth 170 config%i_g_from_reordered_g_lw = RRTM_GPOINT_REORDERING_LW 171 else 172 ! Implied-do for no reordering 173 config%i_g_from_reordered_g_lw = (/ (irep, irep=1,config%n_g_lw) /) 174 end if 175 176 config%i_band_from_reordered_g_lw & 177 = config%i_band_from_g_lw(config%i_g_from_reordered_g_lw) 178 179 ! The i_spec_* variables are used solely for storing spectral 180 ! data, and this can either be by band or by g-point 181 if (config%do_save_spectral_flux .or. config%do_toa_spectral_flux) then 182 if (config%do_save_gpoint_flux) then 183 config%n_spec_lw = config%n_g_lw 184 config%i_spec_from_reordered_g_lw => config%i_g_from_reordered_g_lw 185 else 186 config%n_spec_lw = config%n_bands_lw 187 config%i_spec_from_reordered_g_lw => config%i_band_from_reordered_g_lw 188 end if 189 else 190 config%n_spec_lw = 0 191 nullify(config%i_spec_from_reordered_g_lw) 192 end if 193 142 194 end if 143 144 config%i_band_from_reordered_g_sw & 145 = config%i_band_from_g_sw(config%i_g_from_reordered_g_sw) 146 147 config%i_band_from_reordered_g_lw & 148 = config%i_band_from_g_lw(config%i_g_from_reordered_g_lw) 149 150 ! The i_spec_* variables are used solely for storing spectral 151 ! data, and this can either be by band or by g-point 152 if (config%do_save_spectral_flux .or. config%do_toa_spectral_flux) then 153 if (config%do_save_gpoint_flux) then 154 config%n_spec_sw = config%n_g_sw 155 config%n_spec_lw = config%n_g_lw 156 config%i_spec_from_reordered_g_sw => config%i_g_from_reordered_g_sw 157 config%i_spec_from_reordered_g_lw => config%i_g_from_reordered_g_lw 158 else 159 config%n_spec_sw = config%n_bands_sw 160 config%n_spec_lw = config%n_bands_lw 161 config%i_spec_from_reordered_g_sw => config%i_band_from_reordered_g_sw 162 config%i_spec_from_reordered_g_lw => config%i_band_from_reordered_g_lw 163 end if 164 else 165 config%n_spec_sw = 0 166 config%n_spec_lw = 0 167 nullify(config%i_spec_from_reordered_g_sw) 168 nullify(config%i_spec_from_reordered_g_lw) 169 end if 170 195 171 196 if (lhook) call dr_hook('radiation_ifs_rrtm:setup_gas_optics',1,hook_handle) 172 197 … … 201 226 use yomhook , only : lhook, dr_hook, jphook 202 227 203 use radiation_config, only : config_type, ISolverSpartacus 228 use radiation_config, only : config_type, ISolverSpartacus, IGasModelIFSRRTMG 204 229 use radiation_thermodynamics, only : thermodynamics_type 205 230 use radiation_single_level, only : single_level_type … … 334 359 integer :: istartlev, iendlev 335 360 361 logical :: do_sw, do_lw 362 336 363 integer :: jlev, jgreorder, jg, ig, iband, jcol 337 364 … … 345 372 346 373 if (lhook) call dr_hook('radiation_ifs_rrtm:gas_optics',0,hook_handle) 374 375 do_sw = (config%do_sw .and. config%i_gas_model_sw == IGasModelIFSRRTMG) 376 do_lw = (config%do_lw .and. config%i_gas_model_lw == IGasModelIFSRRTMG) 347 377 348 378 ! Compute start and end levels for indexing the gas mixing ratio … … 392 422 & ZPAVEL , ZTAVEL , ZPZ , ZTZ, IREFLECT) 393 423 394 CALL RRTM_SETCOEF_140GP & 395 &( istartcol, iendcol, nlev , ZCOLDRY , ZWBRODL , ZWKL , & 396 & ZFAC00 , ZFAC01 , ZFAC10 , ZFAC11 , ZFORFAC,ZFORFRAC,INDFOR, JP, JT, JT1 , & 397 & ZCOLH2O, ZCOLCO2 , ZCOLO3 , ZCOLN2O, ZCOLCH4, ZCOLO2,ZCO2MULT , ZCOLBRD, & 398 & ILAYTROP,ILAYSWTCH, ILAYLOW, ZPAVEL , ZTAVEL , ZSELFFAC, ZSELFFRAC, INDSELF, & 399 & INDMINOR,ZSCALEMINOR,ZSCALEMINORN2,ZMINORFRAC,& 400 & ZRAT_H2OCO2, ZRAT_H2OCO2_1, ZRAT_H2OO3, ZRAT_H2OO3_1, & 401 & ZRAT_H2ON2O, ZRAT_H2ON2O_1, ZRAT_H2OCH4, ZRAT_H2OCH4_1, & 402 & ZRAT_N2OCO2, ZRAT_N2OCO2_1, ZRAT_O3CO2, ZRAT_O3CO2_1) 403 404 ZTAUAERL(istartcol:iendcol,:,:) = 0.0_jprb 405 406 CALL RRTM_GAS_OPTICAL_DEPTH & 407 &( istartcol, iendcol, nlev, ZOD_LW, ZPAVEL, ZCOLDRY, ZCOLBRD, ZWX ,& 408 & ZTAUAERL, ZFAC00 , ZFAC01, ZFAC10 , ZFAC11 , ZFORFAC,ZFORFRAC,INDFOR, & 409 & JP, JT, JT1, ZONEMINUS ,& 410 & ZCOLH2O , ZCOLCO2, ZCOLO3, ZCOLN2O, ZCOLCH4, ZCOLO2,ZCO2MULT ,& 411 & ILAYTROP, ILAYSWTCH,ILAYLOW, ZSELFFAC, ZSELFFRAC, INDSELF, ZPFRAC, & 412 & INDMINOR,ZSCALEMINOR,ZSCALEMINORN2,ZMINORFRAC,& 413 & ZRAT_H2OCO2, ZRAT_H2OCO2_1, ZRAT_H2OO3, ZRAT_H2OO3_1, & 414 & ZRAT_H2ON2O, ZRAT_H2ON2O_1, ZRAT_H2OCH4, ZRAT_H2OCH4_1, & 415 & ZRAT_N2OCO2, ZRAT_N2OCO2_1, ZRAT_O3CO2, ZRAT_O3CO2_1) 416 417 if (present(lw_albedo)) then 418 419 call planck_function_atmos(nlev, istartcol, iendcol, config, & 420 & thermodynamics, ZPFRAC, planck_hl) 421 422 if (single_level%is_simple_surface) then 423 call planck_function_surf(istartcol, iendcol, config, & 424 & single_level%skin_temperature, ZPFRAC(:,:,1), & 425 & lw_emission) 424 if (do_lw) then 425 426 CALL RRTM_SETCOEF_140GP & 427 &( istartcol, iendcol, nlev , ZCOLDRY , ZWBRODL , ZWKL , & 428 & ZFAC00 , ZFAC01 , ZFAC10 , ZFAC11 , ZFORFAC,ZFORFRAC,INDFOR, JP, JT, JT1 , & 429 & ZCOLH2O, ZCOLCO2 , ZCOLO3 , ZCOLN2O, ZCOLCH4, ZCOLO2,ZCO2MULT , ZCOLBRD, & 430 & ILAYTROP,ILAYSWTCH, ILAYLOW, ZPAVEL , ZTAVEL , ZSELFFAC, ZSELFFRAC, INDSELF, & 431 & INDMINOR,ZSCALEMINOR,ZSCALEMINORN2,ZMINORFRAC,& 432 & ZRAT_H2OCO2, ZRAT_H2OCO2_1, ZRAT_H2OO3, ZRAT_H2OO3_1, & 433 & ZRAT_H2ON2O, ZRAT_H2ON2O_1, ZRAT_H2OCH4, ZRAT_H2OCH4_1, & 434 & ZRAT_N2OCO2, ZRAT_N2OCO2_1, ZRAT_O3CO2, ZRAT_O3CO2_1) 435 436 ZTAUAERL(istartcol:iendcol,:,:) = 0.0_jprb 437 438 CALL RRTM_GAS_OPTICAL_DEPTH & 439 &( istartcol, iendcol, nlev, ZOD_LW, ZPAVEL, ZCOLDRY, ZCOLBRD, ZWX ,& 440 & ZTAUAERL, ZFAC00 , ZFAC01, ZFAC10 , ZFAC11 , ZFORFAC,ZFORFRAC,INDFOR, & 441 & JP, JT, JT1, ZONEMINUS ,& 442 & ZCOLH2O , ZCOLCO2, ZCOLO3, ZCOLN2O, ZCOLCH4, ZCOLO2,ZCO2MULT ,& 443 & ILAYTROP, ILAYSWTCH,ILAYLOW, ZSELFFAC, ZSELFFRAC, INDSELF, ZPFRAC, & 444 & INDMINOR,ZSCALEMINOR,ZSCALEMINORN2,ZMINORFRAC,& 445 & ZRAT_H2OCO2, ZRAT_H2OCO2_1, ZRAT_H2OO3, ZRAT_H2OO3_1, & 446 & ZRAT_H2ON2O, ZRAT_H2ON2O_1, ZRAT_H2OCH4, ZRAT_H2OCH4_1, & 447 & ZRAT_N2OCO2, ZRAT_N2OCO2_1, ZRAT_O3CO2, ZRAT_O3CO2_1) 448 449 if (present(lw_albedo)) then 450 451 call planck_function_atmos(nlev, istartcol, iendcol, config, & 452 & thermodynamics, ZPFRAC, planck_hl) 453 454 if (single_level%is_simple_surface) then 455 call planck_function_surf(istartcol, iendcol, config, & 456 & single_level%skin_temperature, ZPFRAC(:,:,1), & 457 & lw_emission) 458 459 ! The following can be used to extract the parameters defined at 460 ! the top of the planck_function routine below: 461 !write(*,'(a,140(e12.5,","),a)') 'ZPFRAC_surf=[', & 462 !& sum(ZPFRAC(istartcol:iendcol,:,1),1) / (iendcol+1-istartcol), ']' 426 463 427 ! The following can be used to extract the parameters defined at 428 ! the top of the planck_function routine below: 429 !write(*,'(a,140(e12.5,","),a)') 'ZPFRAC_surf=[', & 430 !& sum(ZPFRAC(istartcol:iendcol,:,1),1) / (iendcol+1-istartcol), ']' 431 432 ! lw_emission at this point is actually the planck function of 433 ! the surface 434 lw_emission = lw_emission * (1.0_jprb - lw_albedo) 464 ! lw_emission at this point is actually the planck function of 465 ! the surface 466 lw_emission = lw_emission * (1.0_jprb - lw_albedo) 467 else 468 ! Longwave emission has already been computed 469 if (config%use_canopy_full_spectrum_lw) then 470 lw_emission = transpose(single_level%lw_emission(istartcol:iendcol,:)) 471 else 472 lw_emission = transpose(single_level%lw_emission(istartcol:iendcol, & 473 & config%i_emiss_from_band_lw(config%i_band_from_reordered_g_lw))) 474 end if 475 end if 476 477 end if 478 479 if (config%i_solver_lw == ISolverSpartacus) then 480 ! We need to rearrange the gas optics info in memory: reordering 481 ! the g points in order of approximately increasing optical 482 ! depth (for efficient 3D processing on only the regions of the 483 ! spectrum that are optically thin for gases) and reorder in 484 ! pressure since the the functions above treat pressure 485 ! decreasing with increasing index. Note that the output gas 486 ! arrays have dimensions in a different order to the inputs, 487 ! so there is some inefficiency here. 488 do jgreorder = 1,config%n_g_lw 489 iband = config%i_band_from_reordered_g_lw(jgreorder) 490 ig = config%i_g_from_reordered_g_lw(jgreorder) 491 492 ! Top-of-atmosphere half level 493 do jlev = 1,nlev 494 do jcol = istartcol,iendcol 495 ! Some g points can return negative optical depths; 496 ! specifically original g points 54-56 which causes 497 ! unphysical single-scattering albedo when combined with 498 ! aerosol 499 od_lw(jgreorder,jlev,jcol) & 500 & = max(config%min_gas_od_lw, ZOD_LW(ig,nlev+1-jlev,jcol)) 501 end do 502 end do 503 end do 435 504 else 436 ! Longwave emission has already been computed437 if (config%use_canopy_full_spectrum_lw) then438 lw_emission = transpose(single_level%lw_emission(istartcol:iendcol,:))439 else440 lw_emission = transpose(single_level%lw_emission(istartcol:iendcol, &441 & config%i_emiss_from_band_lw(config%i_band_from_reordered_g_lw)))442 end if505 ! G points have not been reordered 506 do jcol = istartcol,iendcol 507 do jlev = 1,nlev 508 ! Check for negative optical depth 509 od_lw(:,jlev,jcol) = max(config%min_gas_od_lw, ZOD_LW(:,nlev+1-jlev,jcol)) 510 end do 511 end do 443 512 end if 444 513 445 514 end if 446 515 447 if (config%i_solver_lw == ISolverSpartacus) then 448 ! We need to rearrange the gas optics info in memory: reordering 449 ! the g points in order of approximately increasing optical 450 ! depth (for efficient 3D processing on only the regions of the 451 ! spectrum that are optically thin for gases) and reorder in 452 ! pressure since the the functions above treat pressure 453 ! decreasing with increasing index. Note that the output gas 454 ! arrays have dimensions in a different order to the inputs, 455 ! so there is some inefficiency here. 456 do jgreorder = 1,config%n_g_lw 457 iband = config%i_band_from_reordered_g_lw(jgreorder) 458 ig = config%i_g_from_reordered_g_lw(jgreorder) 459 460 ! Top-of-atmosphere half level 461 do jlev = 1,nlev 462 do jcol = istartcol,iendcol 463 ! Some g points can return negative optical depths; 464 ! specifically original g points 54-56 which causes 465 ! unphysical single-scattering albedo when combined with 466 ! aerosol 467 od_lw(jgreorder,jlev,jcol) & 468 & = max(config%min_gas_od_lw, ZOD_LW(ig,nlev+1-jlev,jcol)) 516 if (do_sw) then 517 518 CALL SRTM_SETCOEF & 519 & ( istartcol, iendcol, nlev,& 520 & ZPAVEL , ZTAVEL,& 521 & ZCOLDRY , ZWKL,& 522 & ILAYTROP,& 523 & ZCOLCH4 , ZCOLCO2 , ZCOLH2O , ZCOLMOL , ZCOLO2 , ZCOLO3,& 524 & ZFORFAC , ZFORFRAC , INDFOR , ZSELFFAC, ZSELFFRAC, INDSELF, & 525 & ZFAC00 , ZFAC01 , ZFAC10 , ZFAC11,& 526 & JP , JT , JT1 , single_level%cos_sza(istartcol:iendcol) & 527 & ) 528 529 ! SRTM_GAS_OPTICAL_DEPTH will not initialize profiles when the sun 530 ! is below the horizon, so we do it here 531 ZOD_SW(istartcol:iendcol,:,:) = 0.0_jprb 532 ZSSA_SW(istartcol:iendcol,:,:) = 0.0_jprb 533 ZINCSOL(istartcol:iendcol,:) = 0.0_jprb 534 535 CALL SRTM_GAS_OPTICAL_DEPTH & 536 &( istartcol, iendcol , nlev , ZONEMINUS_ARRAY,& 537 & single_level%cos_sza(istartcol:iendcol), ILAYTROP,& 538 & ZCOLCH4 , ZCOLCO2 , ZCOLH2O, ZCOLMOL , ZCOLO2 , ZCOLO3,& 539 & ZFORFAC , ZFORFRAC , INDFOR , ZSELFFAC, ZSELFFRAC, INDSELF,& 540 & ZFAC00 , ZFAC01 , ZFAC10 , ZFAC11 ,& 541 & JP , JT , JT1 ,& 542 & ZOD_SW , ZSSA_SW , ZINCSOL ) 543 544 ! Scale the incoming solar per band, if requested 545 if (config%use_spectral_solar_scaling) then 546 do jg = 1,JPGPT_SW 547 do jcol = istartcol,iendcol 548 ZINCSOL(jcol,jg) = ZINCSOL(jcol,jg) * & 549 & single_level%spectral_solar_scaling(config%i_band_from_reordered_g_sw(jg)) 469 550 end do 470 551 end do 471 end do 472 else 473 ! G points have not been reordered 474 do jcol = istartcol,iendcol 475 do jlev = 1,nlev 476 ! Check for negative optical depth 477 od_lw(:,jlev,jcol) = max(config%min_gas_od_lw, ZOD_LW(:,nlev+1-jlev,jcol)) 478 end do 479 end do 480 end if 481 482 CALL SRTM_SETCOEF & 483 & ( istartcol, iendcol, nlev,& 484 & ZPAVEL , ZTAVEL,& 485 & ZCOLDRY , ZWKL,& 486 & ILAYTROP,& 487 & ZCOLCH4 , ZCOLCO2 , ZCOLH2O , ZCOLMOL , ZCOLO2 , ZCOLO3,& 488 & ZFORFAC , ZFORFRAC , INDFOR , ZSELFFAC, ZSELFFRAC, INDSELF, & 489 & ZFAC00 , ZFAC01 , ZFAC10 , ZFAC11,& 490 & JP , JT , JT1 , single_level%cos_sza(istartcol:iendcol) & 491 & ) 492 493 ! SRTM_GAS_OPTICAL_DEPTH will not initialize profiles when the sun 494 ! is below the horizon, so we do it here 495 ZOD_SW(istartcol:iendcol,:,:) = 0.0_jprb 496 ZSSA_SW(istartcol:iendcol,:,:) = 0.0_jprb 497 ZINCSOL(istartcol:iendcol,:) = 0.0_jprb 498 499 CALL SRTM_GAS_OPTICAL_DEPTH & 500 &( istartcol, iendcol , nlev , ZONEMINUS_ARRAY,& 501 & single_level%cos_sza(istartcol:iendcol), ILAYTROP,& 502 & ZCOLCH4 , ZCOLCO2 , ZCOLH2O, ZCOLMOL , ZCOLO2 , ZCOLO3,& 503 & ZFORFAC , ZFORFRAC , INDFOR , ZSELFFAC, ZSELFFRAC, INDSELF,& 504 & ZFAC00 , ZFAC01 , ZFAC10 , ZFAC11 ,& 505 & JP , JT , JT1 ,& 506 & ZOD_SW , ZSSA_SW , ZINCSOL ) 507 508 ! Scale the incoming solar per band, if requested 509 if (config%use_spectral_solar_scaling) then 510 do jg = 1,JPGPT_SW 511 do jcol = istartcol,iendcol 512 ZINCSOL(jcol,jg) = ZINCSOL(jcol,jg) * & 513 & single_level%spectral_solar_scaling(config%i_band_from_reordered_g_sw(jg)) 514 end do 515 end do 516 end if 517 518 ! Scaling factor to ensure that the total solar irradiance is as 519 ! requested. Note that if the sun is below the horizon then 520 ! ZINCSOL will be zero. 521 if (present(incoming_sw)) then 522 do jcol = istartcol,iendcol 523 if (single_level%cos_sza(jcol) > 0.0_jprb) then 552 end if 553 554 ! Scaling factor to ensure that the total solar irradiance is as 555 ! requested. Note that if the sun is below the horizon then 556 ! ZINCSOL will be zero. 557 if (present(incoming_sw)) then 558 do jcol = istartcol,iendcol 559 if (single_level%cos_sza(jcol) > 0.0_jprb) then 524 560 ! Added for DWD (2020) 525 561 !NEC$ nounroll 526 incoming_sw_scale(jcol) = single_level%solar_irradiance / sum(ZINCSOL(jcol,:)) 527 else 528 incoming_sw_scale(jcol) = 1.0_jprb 529 end if 530 end do 531 end if 532 533 if (config%i_solver_sw == ISolverSpartacus) then 534 ! if (.true.) then 535 ! Account for reordered g points 536 do jgreorder = 1,config%n_g_sw 537 ig = config%i_g_from_reordered_g_sw(jgreorder) 538 do jlev = 1,nlev 539 do jcol = istartcol,iendcol 540 ! Check for negative optical depth 541 od_sw (jgreorder,nlev+1-jlev,jcol) & 542 & = max(config%min_gas_od_sw, ZOD_SW (jcol,jlev,ig)) 543 ssa_sw(jgreorder,nlev+1-jlev,jcol) = ZSSA_SW(jcol,jlev,ig) 544 end do 562 incoming_sw_scale(jcol) = single_level%solar_irradiance / sum(ZINCSOL(jcol,:)) 563 else 564 incoming_sw_scale(jcol) = 1.0_jprb 565 end if 545 566 end do 546 if (present(incoming_sw)) then 547 incoming_sw(jgreorder,:) & 548 & = incoming_sw_scale(:) * ZINCSOL(:,ig) 549 end if 550 end do 551 else 552 ! G points have not been reordered 553 do jcol = istartcol,iendcol 554 do jlev = 1,nlev 555 do jg = 1,config%n_g_sw 556 ! Check for negative optical depth 557 od_sw (jg,nlev+1-jlev,jcol) = max(config%min_gas_od_sw, ZOD_SW(jcol,jlev,jg)) 558 ssa_sw(jg,nlev+1-jlev,jcol) = ZSSA_SW(jcol,jlev,jg) 559 end do 567 end if 568 569 if (config%i_solver_sw == ISolverSpartacus) then 570 ! if (.true.) then 571 ! Account for reordered g points 572 do jgreorder = 1,config%n_g_sw 573 ig = config%i_g_from_reordered_g_sw(jgreorder) 574 do jlev = 1,nlev 575 do jcol = istartcol,iendcol 576 ! Check for negative optical depth 577 od_sw (jgreorder,nlev+1-jlev,jcol) & 578 & = max(config%min_gas_od_sw, ZOD_SW (jcol,jlev,ig)) 579 ssa_sw(jgreorder,nlev+1-jlev,jcol) = ZSSA_SW(jcol,jlev,ig) 580 end do 581 end do 582 if (present(incoming_sw)) then 583 incoming_sw(jgreorder,:) & 584 & = incoming_sw_scale(:) * ZINCSOL(:,ig) 585 end if 560 586 end do 561 if (present(incoming_sw)) then 562 do jg = 1,config%n_g_sw 563 incoming_sw(jg,jcol) = incoming_sw_scale(jcol) * ZINCSOL(jcol,jg) 564 end do 565 end if 566 end do 587 else 588 ! G points have not been reordered 589 do jcol = istartcol,iendcol 590 do jlev = 1,nlev 591 do jg = 1,config%n_g_sw 592 ! Check for negative optical depth 593 od_sw (jg,nlev+1-jlev,jcol) = max(config%min_gas_od_sw, ZOD_SW(jcol,jlev,jg)) 594 ssa_sw(jg,nlev+1-jlev,jcol) = ZSSA_SW(jcol,jlev,jg) 595 end do 596 end do 597 if (present(incoming_sw)) then 598 do jg = 1,config%n_g_sw 599 incoming_sw(jg,jcol) = incoming_sw_scale(jcol) * ZINCSOL(jcol,jg) 600 end do 601 end if 602 end do 603 end if 604 567 605 end if 568 606 -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_interface.F90
r4773 r4853 68 68 69 69 ! Load the look-up tables from files in the specified directory 70 if (config%i_gas_model == IGasModelMonochromatic) then70 if (config%i_gas_model_sw == IGasModelMonochromatic) then 71 71 call setup_gas_optics_mono(config, trim(config%directory_name)) 72 else if (config%i_gas_model == IGasModelIFSRRTMG) then 73 call setup_gas_optics_rrtmg(config, trim(config%directory_name)) 74 else if (config%i_gas_model == IGasModelECCKD) then 75 call setup_gas_optics_ecckd(config) 72 else 73 ! Note that we can run RRTMG and ECCKD for different parts of 74 ! the spectrum: the setup routines only configure the relevant 75 ! part. 76 if (config%i_gas_model_sw == IGasModelIFSRRTMG .or. config%i_gas_model_lw == IGasModelIFSRRTMG) then 77 call setup_gas_optics_rrtmg(config, trim(config%directory_name)) 78 end if 79 if (config%i_gas_model_sw == IGasModelECCKD .or. config%i_gas_model_lw == IGasModelECCKD) then 80 call setup_gas_optics_ecckd(config) 81 end if 76 82 end if 77 83 … … 122 128 123 129 if (config%do_clouds) then 124 if (config%i_gas_model == IGasModelMonochromatic) then130 if (config%i_gas_model_sw == IGasModelMonochromatic) then 125 131 ! call setup_cloud_optics_mono(config) 126 132 elseif (config%use_general_cloud_optics) then … … 132 138 133 139 if (config%use_aerosols) then 134 if (config%i_gas_model == IGasModelMonochromatic) then140 if (config%i_gas_model_sw == IGasModelMonochromatic) then 135 141 ! call setup_aerosol_optics_mono(config) 136 142 else … … 167 173 type(gas_type), intent(inout) :: gas 168 174 169 if (config%i_gas_model == IGasModelMonochromatic) then175 if (config%i_gas_model_sw == IGasModelMonochromatic) then 170 176 call set_gas_units_mono(gas) 171 elseif (config%i_gas_model == IGasModelECCKD) then 177 elseif (config%i_gas_model_sw == IGasModelIFSRRTMG & 178 & .or. config%i_gas_model_lw == IGasModelIFSRRTMG) then 179 ! Convert to mass-mixing ratio for RRTMG; note that ecCKD can 180 ! work with this but performs an internal scaling 181 call set_gas_units_ifs(gas) 182 else 183 ! Use volume mixing ratio preferred by ecCKD 172 184 call set_gas_units_ecckd(gas) 173 else174 call set_gas_units_ifs(gas)175 185 end if 176 186 … … 196 206 use radiation_io, only : nulout 197 207 use radiation_config, only : config_type, & 198 & IGasModelMonochromatic, IGasModelIFSRRTMG, &208 & IGasModelMonochromatic, IGasModelIFSRRTMG, IGasModelECCKD, & 199 209 & ISolverMcICA, ISolverSpartacus, ISolverHomogeneous, & 200 210 & ISolverTripleclouds … … 227 237 use radiation_general_cloud_optics, only : general_cloud_optics 228 238 use radiation_aerosol_optics, only : add_aerosol_optics 229 USE mod_phys_lmdz_para230 231 239 232 240 ! Inputs … … 238 246 type(thermodynamics_type),intent(in) :: thermodynamics 239 247 type(gas_type), intent(in) :: gas 240 type(cloud_type), intent(inout):: cloud248 type(cloud_type), intent(inout):: cloud 241 249 type(aerosol_type), intent(in) :: aerosol 242 250 ! Output … … 297 305 298 306 real(jphook) :: hook_handle 299 integer :: jcol, jlev300 307 301 308 if (lhook) call dr_hook('radiation_interface:radiation',0,hook_handle) 302 303 if (config%i_solver_sw == ISolverSPARTACUS) then304 print*,'Dans radiation, mpi_rank, omp_rank, size, chape inv_cloud = ',&305 mpi_rank, omp_rank, &306 shape(cloud%inv_cloud_effective_size), &307 size(cloud%inv_cloud_effective_size)308 ! do jcol=istartcol, iendcol309 ! do jlev=1,nlev310 ! print*,'Entree radiation_interf, mpi_rank, omp_rank, jcol, jlev &311 ! & cloud%inv_cloud_effective_size =',mpi_rank, omp_rank, jcol, jlev, &312 ! & cloud%inv_cloud_effective_size(jcol,jlev)313 ! enddo314 ! enddo315 endif316 ! cloud%inv_cloud_effective_size=0.05_jprb317 309 318 310 if (thermodynamics%pressure_hl(istartcol,2) & … … 339 331 ! incoming shortwave flux at each g-point, for the specified 340 332 ! range of atmospheric columns 341 if (config%i_gas_model == IGasModelMonochromatic) then333 if (config%i_gas_model_sw == IGasModelMonochromatic) then 342 334 call gas_optics_mono(ncol,nlev,istartcol,iendcol, config, & 343 335 & single_level, thermodynamics, gas, lw_albedo, & 344 336 & od_lw, od_sw, ssa_sw, & 345 337 & planck_hl, lw_emission, incoming_sw) 346 else if (config%i_gas_model == IGasModelIFSRRTMG) then347 call gas_optics_rrtmg(ncol,nlev,istartcol,iendcol, config, &348 & single_level, thermodynamics, gas, &349 & od_lw, od_sw, ssa_sw, lw_albedo=lw_albedo, &350 & planck_hl=planck_hl, lw_emission=lw_emission, &351 & incoming_sw=incoming_sw)352 338 else 353 call gas_optics_ecckd(ncol,nlev,istartcol,iendcol, config, & 354 & single_level, thermodynamics, gas, & 355 & od_lw, od_sw, ssa_sw, lw_albedo=lw_albedo, & 356 & planck_hl=planck_hl, lw_emission=lw_emission, & 357 & incoming_sw=incoming_sw) 339 if (config%i_gas_model_sw == IGasModelIFSRRTMG & 340 & .or. config%i_gas_model_lw == IGasModelIFSRRTMG) then 341 call gas_optics_rrtmg(ncol,nlev,istartcol,iendcol, config, & 342 & single_level, thermodynamics, gas, & 343 & od_lw, od_sw, ssa_sw, lw_albedo=lw_albedo, & 344 & planck_hl=planck_hl, lw_emission=lw_emission, & 345 & incoming_sw=incoming_sw) 346 end if 347 if (config%i_gas_model_sw == IGasModelECCKD & 348 & .or. config%i_gas_model_lw == IGasModelECCKD) then 349 call gas_optics_ecckd(ncol,nlev,istartcol,iendcol, config, & 350 & single_level, thermodynamics, gas, & 351 & od_lw, od_sw, ssa_sw, lw_albedo=lw_albedo, & 352 & planck_hl=planck_hl, lw_emission=lw_emission, & 353 & incoming_sw=incoming_sw) 354 end if 358 355 end if 359 356 … … 368 365 ! Compute hydrometeor absorption/scattering properties in each 369 366 ! shortwave and longwave band 370 if (config%i_gas_model == IGasModelMonochromatic) then367 if (config%i_gas_model_sw == IGasModelMonochromatic) then 371 368 call cloud_optics_mono(nlev, istartcol, iendcol, & 372 369 & config, thermodynamics, cloud, & … … 387 384 388 385 if (config%use_aerosols) then 389 if (config%i_gas_model == IGasModelMonochromatic) then386 if (config%i_gas_model_sw == IGasModelMonochromatic) then 390 387 ! call add_aerosol_optics_mono(nlev,istartcol,iendcol, & 391 388 ! & config, thermodynamics, gas, aerosol, & … … 474 471 else if (config%i_solver_sw == ISolverSPARTACUS) then 475 472 ! Compute fluxes using the SPARTACUS shortwave solver 476 ! cloud%inv_cloud_effective_size=0.05_jprb477 ! do jcol=istartcol, iendcol478 ! do jlev=1,nlev479 ! print*,'jcol, jlev, dans radiation_interf i &480 ! & cloud%inv_cloud_effective_size =',jcol, jlev, &481 ! cloud%inv_cloud_effective_size(jcol,jlev)482 ! enddo483 ! enddo484 473 call solver_spartacus_sw(nlev,istartcol,iendcol, & 485 474 & config, single_level, thermodynamics, cloud, & -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_mcica_lw.F90
r4773 r4853 19 19 ! 2017-10-23 R. Hogan Renamed single-character variables 20 20 21 #include "ecrad_config.h" 22 21 23 module radiation_mcica_lw 22 24 … … 124 126 ! Identify clear-sky layers 125 127 logical :: is_clear_sky_layer(nlev) 128 129 ! Temporary storage for more efficient summation 130 #ifdef DWD_REDUCTION_OPTIMIZATIONS 131 real(jprb), dimension(nlev+1,2) :: sum_aux 132 #else 133 real(jprb) :: sum_up, sum_dn 134 #endif 126 135 127 136 ! Index of the highest cloudy layer … … 179 188 180 189 ! Sum over g-points to compute broadband fluxes 181 flux%lw_up_clear(jcol,:) = sum(flux_up_clear,1) 182 flux%lw_dn_clear(jcol,:) = sum(flux_dn_clear,1) 190 #ifdef DWD_REDUCTION_OPTIMIZATIONS 191 sum_aux(:,:) = 0.0_jprb 192 do jg = 1,ng 193 do jlev = 1,nlev+1 194 sum_aux(jlev,1) = sum_aux(jlev,1) + flux_up_clear(jg,jlev) 195 sum_aux(jlev,2) = sum_aux(jlev,2) + flux_dn_clear(jg,jlev) 196 end do 197 end do 198 flux%lw_up_clear(jcol,:) = sum_aux(:,1) 199 flux%lw_dn_clear(jcol,:) = sum_aux(:,2) 200 #else 201 do jlev = 1,nlev+1 202 sum_up = 0.0_jprb 203 sum_dn = 0.0_jprb 204 !$omp simd reduction(+:sum_up, sum_dn) 205 do jg = 1,ng 206 sum_up = sum_up + flux_up_clear(jg,jlev) 207 sum_dn = sum_dn + flux_dn_clear(jg,jlev) 208 end do 209 flux%lw_up_clear(jcol,jlev) = sum_up 210 flux%lw_dn_clear(jcol,jlev) = sum_dn 211 end do 212 #endif 213 183 214 ! Store surface spectral downwelling fluxes 184 215 flux%lw_dn_surf_clear_g(:,jcol) = flux_dn_clear(:,nlev+1) … … 279 310 else 280 311 ! Clear-sky layer: copy over clear-sky values 281 reflectance(:,jlev) = ref_clear(:,jlev) 282 transmittance(:,jlev) = trans_clear(:,jlev) 283 source_up(:,jlev) = source_up_clear(:,jlev) 284 source_dn(:,jlev) = source_dn_clear(:,jlev) 312 do jg = 1,ng 313 reflectance(jg,jlev) = ref_clear(jg,jlev) 314 transmittance(jg,jlev) = trans_clear(jg,jlev) 315 source_up(jg,jlev) = source_up_clear(jg,jlev) 316 source_dn(jg,jlev) = source_dn_clear(jg,jlev) 317 end do 285 318 end if 286 319 end do … … 307 340 308 341 ! Store overcast broadband fluxes 309 flux%lw_up(jcol,:) = sum(flux_up,1) 310 flux%lw_dn(jcol,:) = sum(flux_dn,1) 342 #ifdef DWD_REDUCTION_OPTIMIZATIONS 343 sum_aux(:,:) = 0._jprb 344 do jg = 1, ng 345 do jlev = 1, nlev+1 346 sum_aux(jlev,1) = sum_aux(jlev,1) + flux_up(jg,jlev) 347 sum_aux(jlev,2) = sum_aux(jlev,2) + flux_dn(jg,jlev) 348 end do 349 end do 350 flux%lw_up(jcol,:) = sum_aux(:,1) 351 flux%lw_dn(jcol,:) = sum_aux(:,2) 352 #else 353 do jlev = 1,nlev+1 354 sum_up = 0.0_jprb 355 sum_dn = 0.0_jprb 356 !$omp simd reduction(+:sum_up, sum_dn) 357 do jg = 1,ng 358 sum_up = sum_up + flux_up(jg,jlev) 359 sum_dn = sum_dn + flux_dn(jg,jlev) 360 end do 361 flux%lw_up(jcol,jlev) = sum_up 362 flux%lw_dn(jcol,jlev) = sum_dn 363 end do 364 #endif 311 365 312 366 ! Cloudy flux profiles currently assume completely overcast 313 367 ! skies; perform weighted average with clear-sky profile 314 flux%lw_up(jcol,:) = total_cloud_cover *flux%lw_up(jcol,:) & 315 & + (1.0_jprb - total_cloud_cover)*flux%lw_up_clear(jcol,:) 316 flux%lw_dn(jcol,:) = total_cloud_cover *flux%lw_dn(jcol,:) & 317 & + (1.0_jprb - total_cloud_cover)*flux%lw_dn_clear(jcol,:) 368 do jlev = 1,nlev+1 369 flux%lw_up(jcol,jlev) = total_cloud_cover *flux%lw_up(jcol,jlev) & 370 & + (1.0_jprb - total_cloud_cover)*flux%lw_up_clear(jcol,jlev) 371 flux%lw_dn(jcol,jlev) = total_cloud_cover *flux%lw_dn(jcol,jlev) & 372 & + (1.0_jprb - total_cloud_cover)*flux%lw_dn_clear(jcol,jlev) 373 end do 318 374 ! Store surface spectral downwelling fluxes 319 375 flux%lw_dn_surf_g(:,jcol) = total_cloud_cover*flux_dn(:,nlev+1) & … … 335 391 ! No cloud in profile and clear-sky fluxes already 336 392 ! calculated: copy them over 337 flux%lw_up(jcol,:) = flux%lw_up_clear(jcol,:) 338 flux%lw_dn(jcol,:) = flux%lw_dn_clear(jcol,:) 393 do jlev = 1,nlev+1 394 flux%lw_up(jcol,jlev) = flux%lw_up_clear(jcol,jlev) 395 flux%lw_dn(jcol,jlev) = flux%lw_dn_clear(jcol,jlev) 396 end do 339 397 flux%lw_dn_surf_g(:,jcol) = flux%lw_dn_surf_clear_g(:,jcol) 340 398 if (config%do_lw_derivatives) then -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_mcica_sw.F90
r4773 r4853 18 18 ! 2017-10-23 R. Hogan Renamed single-character variables 19 19 20 #include "ecrad_config.h" 21 20 22 module radiation_mcica_sw 21 23 … … 119 121 ! Total cloud cover output from the cloud generator 120 122 real(jprb) :: total_cloud_cover 123 124 ! Temporary storage for more efficient summation 125 #ifdef DWD_REDUCTION_OPTIMIZATIONS 126 real(jprb), dimension(nlev+1,3) :: sum_aux 127 #else 128 real(jprb) :: sum_up, sum_dn_diff, sum_dn_dir 129 #endif 121 130 122 131 ! Number of g points … … 175 184 176 185 ! Sum over g-points to compute and save clear-sky broadband 177 ! fluxes 178 flux%sw_up_clear(jcol,:) = sum(flux_up,1) 186 ! fluxes. Note that the built-in "sum" function is very slow, 187 ! and before being replaced by the alternatives below 188 ! accounted for around 40% of the total cost of this routine. 189 #ifdef DWD_REDUCTION_OPTIMIZATIONS 190 ! Optimized summation for the NEC architecture 191 sum_aux(:,:) = 0.0_jprb 192 do jg = 1,ng 193 do jlev = 1,nlev+1 194 sum_aux(jlev,1) = sum_aux(jlev,1) + flux_up(jg,jlev) 195 sum_aux(jlev,2) = sum_aux(jlev,2) + flux_dn_direct(jg,jlev) 196 sum_aux(jlev,3) = sum_aux(jlev,3) + flux_dn_diffuse(jg,jlev) 197 end do 198 end do 199 flux%sw_up_clear(jcol,:) = sum_aux(:,1) 200 flux%sw_dn_clear(jcol,:) = sum_aux(:,2) + sum_aux(:,3) 179 201 if (allocated(flux%sw_dn_direct_clear)) then 180 flux%sw_dn_direct_clear(jcol,:) & 181 & = sum(flux_dn_direct,1) 182 flux%sw_dn_clear(jcol,:) = sum(flux_dn_diffuse,1) & 183 & + flux%sw_dn_direct_clear(jcol,:) 184 else 185 flux%sw_dn_clear(jcol,:) = sum(flux_dn_diffuse,1) & 186 & + sum(flux_dn_direct,1) 202 flux%sw_dn_direct_clear(jcol,:) = sum_aux(:,2) 187 203 end if 204 #else 205 ! Optimized summation for the x86-64 architecture 206 do jlev = 1,nlev+1 207 sum_up = 0.0_jprb 208 sum_dn_diff = 0.0_jprb 209 sum_dn_dir = 0.0_jprb 210 !$omp simd reduction(+:sum_up, sum_dn_diff, sum_dn_dir) 211 do jg = 1,ng 212 sum_up = sum_up + flux_up(jg,jlev) 213 sum_dn_diff = sum_dn_diff + flux_dn_diffuse(jg,jlev) 214 sum_dn_dir = sum_dn_dir + flux_dn_direct(jg,jlev) 215 end do 216 flux%sw_up_clear(jcol,jlev) = sum_up 217 flux%sw_dn_clear(jcol,jlev) = sum_dn_diff + sum_dn_dir 218 if (allocated(flux%sw_dn_direct_clear)) then 219 flux%sw_dn_direct_clear(jcol,jlev) = sum_dn_dir 220 end if 221 end do 222 #endif 223 188 224 ! Store spectral downwelling fluxes at surface 189 flux%sw_dn_diffuse_surf_clear_g(:,jcol) = flux_dn_diffuse(:,nlev+1) 190 flux%sw_dn_direct_surf_clear_g(:,jcol) = flux_dn_direct(:,nlev+1) 225 do jg = 1,ng 226 flux%sw_dn_diffuse_surf_clear_g(jg,jcol) = flux_dn_diffuse(jg,nlev+1) 227 flux%sw_dn_direct_surf_clear_g(jg,jcol) = flux_dn_direct(jg,nlev+1) 228 end do 191 229 192 230 ! Do cloudy-sky calculation … … 249 287 else 250 288 ! Clear-sky layer: copy over clear-sky values 251 reflectance(:,jlev) = ref_clear(:,jlev) 252 transmittance(:,jlev) = trans_clear(:,jlev) 253 ref_dir(:,jlev) = ref_dir_clear(:,jlev) 254 trans_dir_diff(:,jlev) = trans_dir_diff_clear(:,jlev) 255 trans_dir_dir(:,jlev) = trans_dir_dir_clear(:,jlev) 289 do jg = 1,ng 290 reflectance(jg,jlev) = ref_clear(jg,jlev) 291 transmittance(jg,jlev) = trans_clear(jg,jlev) 292 ref_dir(jg,jlev) = ref_dir_clear(jg,jlev) 293 trans_dir_diff(jg,jlev) = trans_dir_diff_clear(jg,jlev) 294 trans_dir_dir(jg,jlev) = trans_dir_dir_clear(jg,jlev) 295 end do 256 296 end if 257 297 end do … … 264 304 265 305 ! Store overcast broadband fluxes 266 flux%sw_up(jcol,:) = sum(flux_up,1) 306 #ifdef DWD_REDUCTION_OPTIMIZATIONS 307 sum_aux(:,:) = 0.0_jprb 308 do jg = 1,ng 309 do jlev = 1,nlev+1 310 sum_aux(jlev,1) = sum_aux(jlev,1) + flux_up(jg,jlev) 311 sum_aux(jlev,2) = sum_aux(jlev,2) + flux_dn_direct(jg,jlev) 312 sum_aux(jlev,3) = sum_aux(jlev,3) + flux_dn_diffuse(jg,jlev) 313 end do 314 end do 315 flux%sw_up(jcol,:) = sum_aux(:,1) 316 flux%sw_dn(jcol,:) = sum_aux(:,2) + sum_aux(:,3) 267 317 if (allocated(flux%sw_dn_direct)) then 268 flux%sw_dn_direct(jcol,:) = sum(flux_dn_direct,1) 269 flux%sw_dn(jcol,:) = sum(flux_dn_diffuse,1) & 270 & + flux%sw_dn_direct(jcol,:) 271 else 272 flux%sw_dn(jcol,:) = sum(flux_dn_diffuse,1) & 273 & + sum(flux_dn_direct,1) 318 flux%sw_dn_direct(jcol,:) = sum_aux(:,2) 274 319 end if 275 320 #else 321 do jlev = 1,nlev+1 322 sum_up = 0.0_jprb 323 sum_dn_diff = 0.0_jprb 324 sum_dn_dir = 0.0_jprb 325 !$omp simd reduction(+:sum_up, sum_dn_diff, sum_dn_dir) 326 do jg = 1,ng 327 sum_up = sum_up + flux_up(jg,jlev) 328 sum_dn_diff = sum_dn_diff + flux_dn_diffuse(jg,jlev) 329 sum_dn_dir = sum_dn_dir + flux_dn_direct(jg,jlev) 330 end do 331 flux%sw_up(jcol,jlev) = sum_up 332 flux%sw_dn(jcol,jlev) = sum_dn_diff + sum_dn_dir 333 if (allocated(flux%sw_dn_direct)) then 334 flux%sw_dn_direct(jcol,jlev) = sum_dn_dir 335 end if 336 end do 337 #endif 338 276 339 ! Cloudy flux profiles currently assume completely overcast 277 340 ! skies; perform weighted average with clear-sky profile 278 flux%sw_up(jcol,:) = total_cloud_cover *flux%sw_up(jcol,:) & 279 & + (1.0_jprb - total_cloud_cover)*flux%sw_up_clear(jcol,:) 280 flux%sw_dn(jcol,:) = total_cloud_cover *flux%sw_dn(jcol,:) & 281 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_clear(jcol,:) 282 if (allocated(flux%sw_dn_direct)) then 283 flux%sw_dn_direct(jcol,:) = total_cloud_cover *flux%sw_dn_direct(jcol,:) & 284 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_direct_clear(jcol,:) 285 end if 341 do jlev = 1, nlev+1 342 flux%sw_up(jcol,jlev) = total_cloud_cover *flux%sw_up(jcol,jlev) & 343 & + (1.0_jprb - total_cloud_cover)*flux%sw_up_clear(jcol,jlev) 344 flux%sw_dn(jcol,jlev) = total_cloud_cover *flux%sw_dn(jcol,jlev) & 345 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_clear(jcol,jlev) 346 if (allocated(flux%sw_dn_direct)) then 347 flux%sw_dn_direct(jcol,jlev) = total_cloud_cover *flux%sw_dn_direct(jcol,jlev) & 348 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_direct_clear(jcol,jlev) 349 end if 350 end do 286 351 ! Likewise for surface spectral fluxes 287 flux%sw_dn_diffuse_surf_g(:,jcol) = flux_dn_diffuse(:,nlev+1) 288 flux%sw_dn_direct_surf_g(:,jcol) = flux_dn_direct(:,nlev+1) 289 flux%sw_dn_diffuse_surf_g(:,jcol) = total_cloud_cover *flux%sw_dn_diffuse_surf_g(:,jcol) & 290 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_diffuse_surf_clear_g(:,jcol) 291 flux%sw_dn_direct_surf_g(:,jcol) = total_cloud_cover *flux%sw_dn_direct_surf_g(:,jcol) & 292 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_direct_surf_clear_g(:,jcol) 293 352 do jg = 1,ng 353 flux%sw_dn_diffuse_surf_g(jg,jcol) = flux_dn_diffuse(jg,nlev+1) 354 flux%sw_dn_direct_surf_g(jg,jcol) = flux_dn_direct(jg,nlev+1) 355 flux%sw_dn_diffuse_surf_g(jg,jcol) = total_cloud_cover *flux%sw_dn_diffuse_surf_g(jg,jcol) & 356 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_diffuse_surf_clear_g(jg,jcol) 357 flux%sw_dn_direct_surf_g(jg,jcol) = total_cloud_cover *flux%sw_dn_direct_surf_g(jg,jcol) & 358 & + (1.0_jprb - total_cloud_cover)*flux%sw_dn_direct_surf_clear_g(jg,jcol) 359 end do 360 294 361 else 295 362 ! No cloud in profile and clear-sky fluxes already 296 363 ! calculated: copy them over 297 flux%sw_up(jcol,:) = flux%sw_up_clear(jcol,:) 298 flux%sw_dn(jcol,:) = flux%sw_dn_clear(jcol,:) 299 if (allocated(flux%sw_dn_direct)) then 300 flux%sw_dn_direct(jcol,:) = flux%sw_dn_direct_clear(jcol,:) 301 end if 302 flux%sw_dn_diffuse_surf_g(:,jcol) = flux%sw_dn_diffuse_surf_clear_g(:,jcol) 303 flux%sw_dn_direct_surf_g(:,jcol) = flux%sw_dn_direct_surf_clear_g(:,jcol) 364 do jlev = 1, nlev+1 365 flux%sw_up(jcol,jlev) = flux%sw_up_clear(jcol,jlev) 366 flux%sw_dn(jcol,jlev) = flux%sw_dn_clear(jcol,jlev) 367 if (allocated(flux%sw_dn_direct)) then 368 flux%sw_dn_direct(jcol,jlev) = flux%sw_dn_direct_clear(jcol,jlev) 369 end if 370 end do 371 do jg = 1,ng 372 flux%sw_dn_diffuse_surf_g(jg,jcol) = flux%sw_dn_diffuse_surf_clear_g(jg,jcol) 373 flux%sw_dn_direct_surf_g(jg,jcol) = flux%sw_dn_direct_surf_clear_g(jg,jcol) 374 end do 304 375 305 376 end if ! Cloud is present in profile … … 307 378 else 308 379 ! Set fluxes to zero if sun is below the horizon 309 flux%sw_up(jcol,:) = 0.0_jprb 310 flux%sw_dn(jcol,:) = 0.0_jprb 311 if (allocated(flux%sw_dn_direct)) then 312 flux%sw_dn_direct(jcol,:) = 0.0_jprb 313 end if 314 flux%sw_up_clear(jcol,:) = 0.0_jprb 315 flux%sw_dn_clear(jcol,:) = 0.0_jprb 316 if (allocated(flux%sw_dn_direct_clear)) then 317 flux%sw_dn_direct_clear(jcol,:) = 0.0_jprb 318 end if 319 flux%sw_dn_diffuse_surf_g(:,jcol) = 0.0_jprb 320 flux%sw_dn_direct_surf_g(:,jcol) = 0.0_jprb 321 flux%sw_dn_diffuse_surf_clear_g(:,jcol) = 0.0_jprb 322 flux%sw_dn_direct_surf_clear_g(:,jcol) = 0.0_jprb 380 do jlev = 1, nlev+1 381 flux%sw_up(jcol,jlev) = 0.0_jprb 382 flux%sw_dn(jcol,jlev) = 0.0_jprb 383 if (allocated(flux%sw_dn_direct)) then 384 flux%sw_dn_direct(jcol,jlev) = 0.0_jprb 385 end if 386 flux%sw_up_clear(jcol,jlev) = 0.0_jprb 387 flux%sw_dn_clear(jcol,jlev) = 0.0_jprb 388 if (allocated(flux%sw_dn_direct_clear)) then 389 flux%sw_dn_direct_clear(jcol,jlev) = 0.0_jprb 390 end if 391 end do 392 do jg = 1,ng 393 flux%sw_dn_diffuse_surf_g(jg,jcol) = 0.0_jprb 394 flux%sw_dn_direct_surf_g(jg,jcol) = 0.0_jprb 395 flux%sw_dn_diffuse_surf_clear_g(jg,jcol) = 0.0_jprb 396 flux%sw_dn_direct_surf_clear_g(jg,jcol) = 0.0_jprb 397 end do 323 398 end if ! Sun above horizon 324 399 -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_save.F90
r4773 r4853 86 86 end if 87 87 88 if (config%i_gas_model == IGasModelMonochromatic &88 if (config%i_gas_model_lw == IGasModelMonochromatic & 89 89 .and. config%mono_lw_wavelength > 0.0_jprb) then 90 90 lw_units_str = 'W m-3' … … 515 515 end if 516 516 517 if (config%i_gas_model == IGasModelMonochromatic &517 if (config%i_gas_model_lw == IGasModelMonochromatic & 518 518 .and. config%mono_lw_wavelength > 0.0_jprb) then 519 519 lw_units_str = 'W m-3' -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_spartacus_sw.F90
r4773 r4853 87 87 use radiation_constants, only : Pi, GasConstantDryAir, & 88 88 & AccelDueToGravity 89 USE mod_phys_lmdz_para90 89 91 90 implicit none … … 327 326 write(nulout,'(a)',advance='no') ' Processing columns' 328 327 end if 329 330 print*,'Dans radiation_spartacus, mpi_rank, omp_rank, &331 size, chape inv_cloud = ',&332 mpi_rank, omp_rank, &333 shape(cloud%inv_cloud_effective_size), &334 size(cloud%inv_cloud_effective_size)335 328 336 329 ! Main loop over columns … … 504 497 & .not. (nreg == 2 .and. cloud%fraction(jcol,jlev) & 505 498 & > 1.0-config%cloud_fraction_threshold)) then 506 ! print*,' Dans radiation_spartacus mpi_rank, omp_rank, jcol, jlev, &507 ! & cloud%inv_cloud_effective_size =', mpi_rank, &508 ! & omp_rank, jcol, jlev, &509 ! & cloud%inv_cloud_effective_size(jcol,jlev)510 499 if (cloud%inv_cloud_effective_size(jcol,jlev) > 0.0_jprb) then 511 500 ! 3D effects are only simulated if -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_spectral_definition.F90
r4773 r4853 15 15 ! 16 16 17 #include "ecrad_config.h" 18 17 19 module radiation_spectral_definition 18 20 … … 23 25 public 24 26 25 real(jprb), parameter :: SolarReferenceTemperature = 5777.0_jprb ! K27 real(jprb), parameter :: SolarReferenceTemperature = 5777.0_jprb ! K 26 28 real(jprb), parameter :: TerrestrialReferenceTemperature = 273.15_jprb ! K 27 29 … … 85 87 subroutine read_spectral_definition(this, file) 86 88 87 use easy_netcdf, only : netcdf_file 89 #ifdef EASY_NETCDF_READ_MPI 90 use easy_netcdf_read_mpi, only : netcdf_file 91 #else 92 use easy_netcdf, only : netcdf_file 93 #endif 88 94 use yomhook, only : lhook, dr_hook, jphook 89 95 … … 132 138 133 139 !--------------------------------------------------------------------- 134 ! Store a simple band description by copying over the lower and135 ! upper wavenumbers of each band136 subroutine allocate_bands_only(this, wavenumber1, wavenumber2)140 ! Store a simple band description by copying over the reference 141 ! temperature and the lower and upper wavenumbers of each band 142 subroutine allocate_bands_only(this, reference_temperature, wavenumber1, wavenumber2) 137 143 138 144 use yomhook, only : lhook, dr_hook, jphook 139 145 140 146 class(spectral_definition_type), intent(inout) :: this 141 real(jprb), dimension(:), intent(in) :: wavenumber1, wavenumber2 147 real(jprb), intent(in) :: reference_temperature ! K 148 real(jprb), dimension(:), intent(in) :: wavenumber1, wavenumber2 ! cm-1 142 149 143 150 real(jphook) :: hook_handle … … 152 159 this%wavenumber1_band = wavenumber1 153 160 this%wavenumber2_band = wavenumber2 154 161 this%reference_temperature = reference_temperature 162 155 163 if (lhook) call dr_hook('radiation_spectral_definition:allocate_bands_only',1,hook_handle) 156 164 … … 167 175 this%ng = 0 168 176 this%nband = 0 177 this%reference_temperature = -1.0_jprb 169 178 170 179 if (allocated(this%wavenumber1)) deallocate(this%wavenumber1) -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_tripleclouds_lw.F90
r4773 r4853 170 170 logical :: is_clear_sky_layer(0:nlev+1) 171 171 172 ! Temporaries to speed up summations 173 real(jprb) :: sum_dn, sum_up 174 172 175 ! Index of the highest cloudy layer 173 176 integer :: i_cloud_top … … 261 264 if (config%do_clear) then 262 265 ! Sum over g-points to compute broadband fluxes 263 flux%lw_up_clear(jcol,:) = sum(flux_up_clear,1) 264 flux%lw_dn_clear(jcol,:) = sum(flux_dn_clear,1) 266 do jlev = 1,nlev+1 267 sum_up = 0.0_jprb 268 sum_dn = 0.0_jprb 269 !$omp simd reduction(+:sum_up, sum_dn) 270 do jg = 1,ng 271 sum_up = sum_up + flux_up_clear(jg,jlev) 272 sum_dn = sum_dn + flux_dn_clear(jg,jlev) 273 end do 274 flux%lw_up_clear(jcol,jlev) = sum_up 275 flux%lw_dn_clear(jcol,jlev) = sum_dn 276 end do 277 265 278 ! Store surface spectral downwelling fluxes / TOA upwelling 266 flux%lw_dn_surf_clear_g(:,jcol) = flux_dn_clear(:,nlev+1) 267 flux%lw_up_toa_clear_g (:,jcol) = flux_up_clear(:,1) 279 do jg = 1,ng 280 flux%lw_dn_surf_clear_g(jg,jcol) = flux_dn_clear(jg,nlev+1) 281 flux%lw_up_toa_clear_g (jg,jcol) = flux_up_clear(jg,1) 282 end do 268 283 ! Save the spectral fluxes if required 269 284 if (config%do_save_spectral_flux) then … … 453 468 end if 454 469 else 455 flux%lw_dn(jcol,:) = sum(flux_dn_clear(:,jlev)) 470 sum_dn = 0.0_jprb 471 !$omp simd reduction(+:sum_dn) 472 do jg = 1,ng 473 sum_dn = sum_dn + flux_dn_clear(jg,jlev) 474 end do 475 flux%lw_dn(jcol,jlev) = sum_dn 456 476 if (config%do_save_spectral_flux) then 457 477 call indexed_sum(flux_dn_clear(:,jlev), & … … 470 490 & + total_albedo(:,1,i_cloud_top)*flux_dn_clear(:,i_cloud_top) 471 491 flux_up(:,2:) = 0.0_jprb 472 flux%lw_up(jcol,i_cloud_top) = sum(flux_up(:,1)) 492 493 sum_up = 0.0_jprb 494 !$omp simd reduction(+:sum_up) 495 do jg = 1,ng 496 sum_up = sum_up + flux_up(jg,1) 497 end do 498 flux%lw_up(jcol,i_cloud_top) = sum_up 499 473 500 if (config%do_save_spectral_flux) then 474 501 call indexed_sum(flux_up(:,1), & … … 478 505 do jlev = i_cloud_top-1,1,-1 479 506 flux_up(:,1) = trans_clear(:,jlev)*flux_up(:,1) + source_up_clear(:,jlev) 480 flux%lw_up(jcol,jlev) = sum(flux_up(:,1)) 507 sum_up = 0.0_jprb 508 !$omp simd reduction(+:sum_up) 509 do jg = 1,ng 510 sum_up = sum_up + flux_up(jg,1) 511 end do 512 flux%lw_up(jcol,jlev) = sum_up 481 513 if (config%do_save_spectral_flux) then 482 514 call indexed_sum(flux_up(:,1), & … … 528 560 529 561 ! Store the broadband fluxes 530 flux%lw_up(jcol,jlev+1) = sum(sum(flux_up,1)) 531 flux%lw_dn(jcol,jlev+1) = sum(sum(flux_dn,1)) 562 sum_up = 0.0_jprb 563 sum_dn = 0.0_jprb 564 do jreg = 1,nregions 565 !$omp simd reduction(+:sum_up, sum_dn) 566 do jg = 1,ng 567 sum_up = sum_up + flux_up(jg,jreg) 568 sum_dn = sum_dn + flux_dn(jg,jreg) 569 end do 570 end do 571 flux%lw_up(jcol,jlev+1) = sum_up 572 flux%lw_dn(jcol,jlev+1) = sum_dn 532 573 533 574 ! Save the spectral fluxes if required -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_tripleclouds_sw.F90
r4773 r4853 74 74 ! Gas and aerosol optical depth, single-scattering albedo and 75 75 ! asymmetry factor at each shortwave g-point 76 ! real(jprb), intent(in), dimension(istartcol:iendcol,nlev,config%n_g_sw) :: & 77 real(jprb), intent(in), dimension(config%n_g_sw,nlev,istartcol:iendcol) :: & 78 & od, ssa, g 76 real(jprb), intent(in), dimension(config%n_g_sw,nlev,istartcol:iendcol) & 77 & :: od, ssa, g 79 78 80 79 ! Cloud and precipitation optical depth, single-scattering albedo and 81 80 ! asymmetry factor in each shortwave band 82 real(jprb), intent(in), dimension(config%n_bands_sw,nlev,istartcol:iendcol) ::&83 & od_cloud, ssa_cloud, g_cloud81 real(jprb), intent(in), dimension(config%n_bands_sw,nlev,istartcol:iendcol) & 82 & :: od_cloud, ssa_cloud, g_cloud 84 83 85 84 ! Optical depth, single scattering albedo and asymmetry factor in … … 92 91 ! flux into a plane perpendicular to the incoming radiation at 93 92 ! top-of-atmosphere in each of the shortwave g points 94 real(jprb), intent(in), dimension(config%n_g_sw,istartcol:iendcol) ::&95 & albedo_direct, albedo_diffuse, incoming_sw93 real(jprb), intent(in), dimension(config%n_g_sw,istartcol:iendcol) & 94 & :: albedo_direct, albedo_diffuse, incoming_sw 96 95 97 96 ! Output … … 166 165 real(jprb) :: scat_od, scat_od_cloud 167 166 167 ! Temporaries to speed up summations 168 real(jprb) :: sum_dn_diff, sum_dn_dir, sum_up 169 170 ! Local cosine of solar zenith angle 168 171 real(jprb) :: mu0 169 172 … … 444 447 end if 445 448 446 ! Store the TOA broadband fluxes 447 flux%sw_up(jcol,1) = sum(sum(flux_up,1)) 448 flux%sw_dn(jcol,1) = mu0 * sum(sum(direct_dn,1)) 449 ! Store the TOA broadband fluxes, noting that there is no 450 ! diffuse downwelling at TOA. The intrinsic "sum" command has 451 ! been found to be very slow; better performance is found on 452 ! x86-64 architecture with explicit loops and the "omp simd 453 ! reduction" directive. 454 sum_up = 0.0_jprb 455 sum_dn_dir = 0.0_jprb 456 do jreg = 1,nregions 457 !$omp simd reduction(+:sum_up, sum_dn_dir) 458 do jg = 1,ng 459 sum_up = sum_up + flux_up(jg,jreg) 460 sum_dn_dir = sum_dn_dir + direct_dn(jg,jreg) 461 end do 462 end do 463 flux%sw_up(jcol,1) = sum_up 464 flux%sw_dn(jcol,1) = mu0 * sum_dn_dir 449 465 if (allocated(flux%sw_dn_direct)) then 450 466 flux%sw_dn_direct(jcol,1) = flux%sw_dn(jcol,1) 451 467 end if 452 468 if (config%do_clear) then 453 flux%sw_up_clear(jcol,1) = sum(flux_up_clear) 454 flux%sw_dn_clear(jcol,1) = mu0 * sum(direct_dn_clear) 469 sum_up = 0.0_jprb 470 sum_dn_dir = 0.0_jprb 471 !$omp simd reduction(+:sum_up, sum_dn_dir) 472 do jg = 1,ng 473 sum_up = sum_up + flux_up_clear(jg) 474 sum_dn_dir = sum_dn_dir + direct_dn_clear(jg) 475 end do 476 flux%sw_up_clear(jcol,1) = sum_up 477 flux%sw_dn_clear(jcol,1) = mu0 * sum_dn_dir 455 478 if (allocated(flux%sw_dn_direct_clear)) then 456 479 flux%sw_dn_direct_clear(jcol,1) = flux%sw_dn_clear(jcol,1) … … 467 490 & config%i_spec_from_reordered_g_sw, & 468 491 & flux%sw_dn_band(:,jcol,1)) 469 flux%sw_dn_band(:,jcol,1) = & 470 & mu0 * flux%sw_dn_band(:,jcol,1) 492 flux%sw_dn_band(:,jcol,1) = mu0 * flux%sw_dn_band(:,jcol,1) 471 493 if (allocated(flux%sw_dn_direct_band)) then 472 494 flux%sw_dn_direct_band(:,jcol,1) = flux%sw_dn_band(:,jcol,1) … … 549 571 ! nothing to do 550 572 551 ! Store the broadband fluxes 552 flux%sw_up(jcol,jlev+1) = sum(sum(flux_up,1)) 573 ! Store the broadband fluxes. The intrinsic "sum" command has 574 ! been found to be very slow; better performance is found on 575 ! x86-64 architecture with explicit loops and the "omp simd 576 ! reduction" directive. 577 sum_up = 0.0_jprb 578 sum_dn_dir = 0.0_jprb 579 sum_dn_diff = 0.0_jprb 580 do jreg = 1,nregions 581 !$omp simd reduction(+:sum_up, sum_dn_diff, sum_dn_dir) 582 do jg = 1,ng 583 sum_up = sum_up + flux_up(jg,jreg) 584 sum_dn_diff = sum_dn_diff + flux_dn(jg,jreg) 585 sum_dn_dir = sum_dn_dir + direct_dn(jg,jreg) 586 end do 587 end do 588 flux%sw_up(jcol,jlev+1) = sum_up 589 flux%sw_dn(jcol,jlev+1) = mu0 * sum_dn_dir + sum_dn_diff 553 590 if (allocated(flux%sw_dn_direct)) then 554 flux%sw_dn_direct(jcol,jlev+1) = mu0 * sum(sum(direct_dn,1)) 555 flux%sw_dn(jcol,jlev+1) & 556 & = flux%sw_dn_direct(jcol,jlev+1) + sum(sum(flux_dn,1)) 557 else 558 flux%sw_dn(jcol,jlev+1) = mu0 * sum(sum(direct_dn,1)) + sum(sum(flux_dn,1)) 591 flux%sw_dn_direct(jcol,jlev+1) = mu0 * sum_dn_dir 559 592 end if 560 593 if (config%do_clear) then 561 flux%sw_up_clear(jcol,jlev+1) = sum(flux_up_clear) 594 sum_up = 0.0_jprb 595 sum_dn_dir = 0.0_jprb 596 sum_dn_diff = 0.0_jprb 597 !$omp simd reduction(+:sum_up, sum_dn_diff, sum_dn_dir) 598 do jg = 1,ng 599 sum_up = sum_up + flux_up_clear(jg) 600 sum_dn_diff = sum_dn_diff + flux_dn_clear(jg) 601 sum_dn_dir = sum_dn_dir + direct_dn_clear(jg) 602 end do 603 flux%sw_up_clear(jcol,jlev+1) = sum_up 604 flux%sw_dn_clear(jcol,jlev+1) = mu0 * sum_dn_dir + sum_dn_diff 562 605 if (allocated(flux%sw_dn_direct_clear)) then 563 flux%sw_dn_direct_clear(jcol,jlev+1) = mu0 * sum(direct_dn_clear) 564 flux%sw_dn_clear(jcol,jlev+1) & 565 & = flux%sw_dn_direct_clear(jcol,jlev+1) + sum(flux_dn_clear) 566 else 567 flux%sw_dn_clear(jcol,jlev+1) = mu0 * sum(direct_dn_clear) & 568 & + sum(flux_dn_clear) 606 flux%sw_dn_direct_clear(jcol,jlev+1) = mu0 * sum_dn_dir 569 607 end if 570 608 end if … … 605 643 end if 606 644 end if 607 608 645 end do ! Final loop over levels 609 646 -
LMDZ6/trunk/libf/phylmd/ecrad/radiation/radiation_two_stream.F90
r4773 r4853 22 22 ! 2023-09-28 R Hogan Increased security for single-precision SW "k" 23 23 24 #include "ecrad_config.h" 25 24 26 module radiation_two_stream 25 27 … … 43 45 44 46 contains 45 46 #ifdef FAST_EXPONENTIAL47 !---------------------------------------------------------------------48 ! Fast exponential for negative arguments: a Pade approximant that49 ! doesn't go negative for negative arguments, applied to arg/8, and50 ! the result is then squared three times51 elemental function exp_fast(arg) result(ex)52 real(jprd) :: arg, ex53 ex = 1.0_jprd / (1.0_jprd + arg*(-0.125_jprd &54 + arg*(0.0078125_jprd - 0.000325520833333333_jprd * arg)))55 ex = ex*ex56 ex = ex*ex57 ex = ex*ex58 end function exp_fast59 #else60 #define exp_fast exp61 #endif62 47 63 48 !--------------------------------------------------------------------- … … 214 199 k_exponent = sqrt(max((gamma1(jg) - gamma2(jg)) * (gamma1(jg) + gamma2(jg)), & 215 200 1.0e-12_jprd)) ! Eq 18 of Meador & Weaver (1980) 216 exponential = exp _fast(-k_exponent*od(jg))201 exponential = exp(-k_exponent*od(jg)) 217 202 exponential2 = exponential*exponential 218 203 reftrans_factor = 1.0 / (k_exponent + gamma1(jg) + (k_exponent - gamma1(jg))*exponential2) … … 306 291 #endif 307 292 308 ! Added for DWD (2020)309 !NEC$ shortloop310 293 do jg = 1, ng 311 294 factor = (LwDiffusivityWP * 0.5_jprb) * ssa(jg) … … 315 298 1.0e-12_jprb)) ! Eq 18 of Meador & Weaver (1980) 316 299 if (od(jg) > 1.0e-3_jprb) then 317 exponential = exp _fast(-k_exponent*od(jg))300 exponential = exp(-k_exponent*od(jg)) 318 301 exponential2 = exponential*exponential 319 302 reftrans_factor = 1.0_jprb / (k_exponent + gamma1 + (k_exponent - gamma1)*exponential2) … … 392 375 #endif 393 376 394 transmittance = exp_fast(-LwDiffusivityWP*od) 395 396 ! Added for DWD (2020) 397 !NEC$ shortloop 377 #ifndef DWD_TWO_STREAM_OPTIMIZATIONS 378 transmittance = exp(-LwDiffusivityWP*od) 379 #endif 380 398 381 do jg = 1, ng 399 382 ! Compute upward and downward emission assuming the Planck … … 401 384 ! (e.g. Wiscombe , JQSRT 1976). 402 385 coeff = LwDiffusivityWP*od(jg) 386 #ifdef DWD_TWO_STREAM_OPTIMIZATIONS 387 transmittance(jg) = exp(-coeff) 388 #endif 403 389 if (od(jg) > 1.0e-3_jprb) then 404 390 ! Simplified from calc_reflectance_transmittance_lw above … … 516 502 k_gamma4 = k_exponent*gamma4 517 503 ! Check for mu0 <= 0! 518 exponential0 = exp _fast(-od_over_mu0)504 exponential0 = exp(-od_over_mu0) 519 505 trans_dir_dir(jg) = exponential0 520 exponential = exp _fast(-k_exponent*od(jg))506 exponential = exp(-k_exponent*od(jg)) 521 507 522 508 exponential2 = exponential*exponential … … 609 595 ! The three transfer coefficients from the two-stream 610 596 ! differentiatial equations 597 #ifndef DWD_TWO_STREAM_OPTIMIZATIONS 611 598 real(jprb), dimension(ng) :: gamma1, gamma2, gamma3, gamma4 612 599 real(jprb), dimension(ng) :: alpha1, alpha2, k_exponent 613 600 real(jprb), dimension(ng) :: exponential ! = exp(-k_exponent*od) 601 #else 602 real(jprb) :: gamma1, gamma2, gamma3, gamma4 603 real(jprb) :: alpha1, alpha2, k_exponent 604 real(jprb) :: exponential ! = exp(-k_exponent*od) 605 #endif 614 606 615 607 real(jprb) :: reftrans_factor, factor … … 625 617 #endif 626 618 619 #ifndef DWD_TWO_STREAM_OPTIMIZATIONS 627 620 ! GCC 9.3 strange error: intermediate values of ~ -8000 cause a 628 621 ! FPE when vectorizing exp(), but not in non-vectorized loop, nor 629 622 ! with larger negative values! 630 623 trans_dir_dir = max(-max(od * (1.0_jprb/mu0), 0.0_jprb),-1000.0_jprb) 631 trans_dir_dir = exp_fast(trans_dir_dir) 632 633 ! Added for DWD (2020) 634 !NEC$ shortloop 624 trans_dir_dir = exp(trans_dir_dir) 625 635 626 do jg = 1, ng 636 627 … … 659 650 end do 660 651 661 exponential = exp_fast(-k_exponent*od) 662 663 !NEC$ shortloop 652 exponential = exp(-k_exponent*od) 653 664 654 do jg = 1, ng 665 655 k_mu0 = k_exponent(jg)*mu0 … … 705 695 trans_dir_diff(jg) = max(0.0_jprb, min(trans_dir_diff(jg), mu0*(1.0_jprb-trans_dir_dir(jg))-ref_dir(jg))) 706 696 end do 707 697 698 #else 699 ! GPU-capable and vector-optimized version for ICON 700 do jg = 1, ng 701 702 trans_dir_dir(jg) = max(-max(od(jg) * (1.0_jprb/mu0),0.0_jprb),-1000.0_jprb) 703 trans_dir_dir(jg) = exp(trans_dir_dir(jg)) 704 705 ! Zdunkowski "PIFM" (Zdunkowski et al., 1980; Contributions to 706 ! Atmospheric Physics 53, 147-66) 707 factor = 0.75_jprb*asymmetry(jg) 708 709 gamma1 = 2.0_jprb - ssa(jg) * (1.25_jprb + factor) 710 gamma2 = ssa(jg) * (0.75_jprb - factor) 711 gamma3 = 0.5_jprb - mu0*factor 712 gamma4 = 1.0_jprb - gamma3 713 714 alpha1 = gamma1*gamma4 + gamma2*gamma3 ! Eq. 16 715 alpha2 = gamma1*gamma3 + gamma2*gamma4 ! Eq. 17 716 #ifdef PARKIND1_SINGLE 717 k_exponent = sqrt(max((gamma1 - gamma2) * (gamma1 + gamma2), 1.0e-6_jprb)) ! Eq 18 718 #else 719 k_exponent = sqrt(max((gamma1 - gamma2) * (gamma1 + gamma2), 1.0e-12_jprb)) ! Eq 18 720 #endif 721 722 exponential = exp(-k_exponent*od(jg)) 723 724 k_mu0 = k_exponent*mu0 725 one_minus_kmu0_sqr = 1.0_jprb - k_mu0*k_mu0 726 k_gamma3 = k_exponent*gamma3 727 k_gamma4 = k_exponent*gamma4 728 exponential2 = exponential*exponential 729 k_2_exponential = 2.0_jprb * k_exponent * exponential 730 reftrans_factor = 1.0_jprb / (k_exponent + gamma1 + (k_exponent - gamma1)*exponential2) 731 732 ! Meador & Weaver (1980) Eq. 25 733 ref_diff(jg) = gamma2 * (1.0_jprb - exponential2) * reftrans_factor 734 735 ! Meador & Weaver (1980) Eq. 26 736 trans_diff(jg) = k_2_exponential * reftrans_factor 737 738 ! Here we need mu0 even though it wasn't in Meador and Weaver 739 ! because we are assuming the incoming direct flux is defined to 740 ! be the flux into a plane perpendicular to the direction of the 741 ! sun, not into a horizontal plane 742 reftrans_factor = mu0 * ssa(jg) * reftrans_factor & 743 & / merge(one_minus_kmu0_sqr, epsilon(1.0_jprb), abs(one_minus_kmu0_sqr) > epsilon(1.0_jprb)) 744 745 ! Meador & Weaver (1980) Eq. 14, multiplying top & bottom by 746 ! exp(-k_exponent*od) in case of very high optical depths 747 ref_dir(jg) = reftrans_factor & 748 & * ( (1.0_jprb - k_mu0) * (alpha2 + k_gamma3) & 749 & -(1.0_jprb + k_mu0) * (alpha2 - k_gamma3)*exponential2 & 750 & -k_2_exponential*(gamma3 - alpha2*mu0)*trans_dir_dir(jg) ) 751 752 ! Meador & Weaver (1980) Eq. 15, multiplying top & bottom by 753 ! exp(-k_exponent*od), minus the 1*exp(-od/mu0) term 754 ! representing direct unscattered transmittance. 755 trans_dir_diff(jg) = reftrans_factor * ( k_2_exponential*(gamma4 + alpha1*mu0) & 756 & - trans_dir_dir(jg) & 757 & * ( (1.0_jprb + k_mu0) * (alpha1 + k_gamma4) & 758 & -(1.0_jprb - k_mu0) * (alpha1 - k_gamma4) * exponential2) ) 759 760 ! Final check that ref_dir + trans_dir_diff <= 1 761 ref_dir(jg) = max(0.0_jprb, min(ref_dir(jg), mu0*(1.0_jprb-trans_dir_dir(jg)))) 762 trans_dir_diff(jg) = max(0.0_jprb, min(trans_dir_diff(jg), mu0*(1.0_jprb-trans_dir_dir(jg))-ref_dir(jg))) 763 764 end do 765 #endif 766 708 767 #ifdef DO_DR_HOOK_TWO_STREAM 709 768 if (lhook) call dr_hook('radiation_two_stream:calc_ref_trans_sw',1,hook_handle) … … 757 816 k_exponent = sqrt(max((gamma1(jg) - gamma2(jg)) * (gamma1(jg) + gamma2(jg)), & 758 817 & 1.0e-12_jprd)) ! Eq 18 759 exponential = exp _fast(-k_exponent*od(jg))818 exponential = exp(-k_exponent*od(jg)) 760 819 exponential2 = exponential*exponential 761 820 k_2_exponential = 2.0_jprd * k_exponent * exponential … … 766 825 ! Until 1.1.8, used LwDiffusivity instead of 2.0, although the 767 826 ! effect is very small 768 ! frac_scat_diffuse(jg) = 1.0_jprb - min(1.0_jprb,exp _fast(-LwDiffusivity*od(jg)) &827 ! frac_scat_diffuse(jg) = 1.0_jprb - min(1.0_jprb,exp(-LwDiffusivity*od(jg)) & 769 828 ! & / max(1.0e-8_jprb, k_2_exponential * reftrans_factor)) 770 829 frac_scat_diffuse(jg) = 1.0_jprb & 771 & - min(1.0_jprb,exp _fast(-2.0_jprb*od(jg)) &830 & - min(1.0_jprb,exp(-2.0_jprb*od(jg)) & 772 831 & / max(1.0e-8_jprb, k_2_exponential * reftrans_factor)) 773 832 end do -
LMDZ6/trunk/libf/phylmd/ecrad/test/ifs/Makefile
r4773 r4853 15 15 CONFIG = configCY49R1.nam 16 16 CONFIG_ECCKD = configCY49R1_ecckd.nam 17 CONFIG_MIXED = configCY49R1_mixed.nam 17 18 18 19 # Typing "make" will run radiation scheme on IFS profiles … … 111 112 test_ecckd_tc: 112 113 $(DRIVER) $(CONFIG_ECCKD) $(INPUT).nc $(INPUT)_ecckd_tc_out.nc 114 115 test_mixed_gas: 116 $(DRIVER) $(CONFIG_MIXED) $(INPUT).nc $(INPUT)_sw_ecckd_lw_ecckd_out.nc 117 $(CHANGENAM) $(CONFIG_MIXED) config_mix.nam lw_gas_model_name='"RRTMG-IFS"' do_cloud_aerosol_per_lw_g_point=false 118 $(DRIVER) config_mix.nam $(INPUT).nc $(INPUT)_sw_ecckd_lw_rrtmg_out.nc 119 $(CHANGENAM) $(CONFIG_MIXED) config_mix.nam sw_gas_model_name='"RRTMG-IFS"' do_cloud_aerosol_per_sw_g_point=false 120 $(DRIVER) config_mix.nam $(INPUT).nc $(INPUT)_sw_rrtmg_lw_ecckd_out.nc 121 $(CHANGENAM) $(CONFIG_MIXED) config_mix.nam sw_gas_model_name='"RRTMG-IFS"' lw_gas_model_name='"RRTMG-IFS"' do_cloud_aerosol_per_lw_g_point=false do_cloud_aerosol_per_sw_g_point=false 122 $(DRIVER) config_mix.nam $(INPUT).nc $(INPUT)_sw_rrtmg_lw_rrtmg_out.nc 113 123 114 124 # ecCKD with no aerosols
Note: See TracChangeset
for help on using the changeset viewer.