Changeset 4444 for LMDZ6/branches
- Timestamp:
- Feb 21, 2023, 3:26:41 PM (22 months ago)
- Location:
- LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad
- Files:
-
- 24 added
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/easy_netcdf.F90
r3908 r4444 35 35 ! a NetCDF file 36 36 type netcdf_file 37 integer :: ncid 37 integer :: ncid = -1! NetCDF file ID 38 38 integer :: iverbose ! Verbosity: 0 = report only fatal errors, 39 39 ! 1 = ...and warnings, … … 55 55 procedure :: create => create_netcdf_file 56 56 procedure :: close => close_netcdf_file 57 procedure :: is_open 57 58 procedure :: get_real_scalar 59 procedure :: get_int_scalar 58 60 procedure :: get_real_vector 59 procedure :: get_int eger_vector61 procedure :: get_int_vector 60 62 procedure :: get_real_matrix 61 63 procedure :: get_real_array3 … … 65 67 procedure :: get_real_array3_indexed 66 68 procedure :: get_real_array4 67 generic :: get => get_real_scalar, get_real_vector, & 69 procedure :: get_char_vector 70 procedure :: get_char_matrix 71 generic :: get => get_real_scalar, get_int_scalar, & 72 & get_real_vector, get_int_vector, & 68 73 & get_real_matrix, get_real_array3, & 69 & get_real_array4, get_integer_vector,&74 & get_real_array4, & 70 75 & get_real_scalar_indexed, get_real_vector_indexed, & 71 & get_real_matrix_indexed, get_real_array3_indexed 76 & get_real_matrix_indexed, get_real_array3_indexed, & 77 & get_char_vector, get_char_matrix 72 78 procedure :: get_real_scalar_attribute 73 79 procedure :: get_string_attribute … … 83 89 procedure :: put_real_scalar 84 90 procedure :: put_real_vector 91 procedure :: put_int_vector 85 92 procedure :: put_real_matrix 86 93 procedure :: put_real_array3 … … 91 98 & put_real_matrix, put_real_array3, & 92 99 & put_real_scalar_indexed, put_real_vector_indexed, & 93 & put_real_matrix_indexed 100 & put_real_matrix_indexed, put_int_vector 94 101 procedure :: set_verbose 95 102 procedure :: transpose_matrices … … 101 108 procedure :: attribute_exists 102 109 procedure :: global_attribute_exists 110 #ifdef NC_NETCDF4 111 procedure :: copy_dimensions 112 #endif 113 procedure :: copy_variable_definition 114 procedure :: copy_variable 103 115 procedure, private :: get_array_dimensions 104 116 procedure, private :: get_variable_id … … 257 269 end if 258 270 271 this%ncid = -1 272 259 273 end subroutine close_netcdf_file 260 274 … … 367 381 368 382 integer :: j, istatus 369 integer :: dimids(NF90_MAX_VAR_DIMS)383 integer :: idimids(NF90_MAX_VAR_DIMS) 370 384 371 385 istatus = nf90_inquire_variable(this%ncid, ivarid, & 372 & ndims=ndims, dimids= dimids)386 & ndims=ndims, dimids=idimids) 373 387 if (istatus /= NF90_NOERR) then 374 388 write(nulerr,'(a,i0,a,a)') '*** Error inquiring about NetCDF variable with id ', & … … 379 393 ndimlens(:) = 0 380 394 do j = 1,ndims 381 istatus = nf90_inquire_dimension(this%ncid, dimids(j), len=ndimlens(j))395 istatus = nf90_inquire_dimension(this%ncid, idimids(j), len=ndimlens(j)) 382 396 if (istatus /= NF90_NOERR) then 383 397 write(nulerr,'(a,i0,a,i0,a,a)') '*** Error reading length of dimension ', & … … 420 434 421 435 !--------------------------------------------------------------------- 436 ! Return true if file is open, false otherwise 437 function is_open(this) 438 class(netcdf_file) :: this 439 logical :: is_open 440 is_open = (this%ncid >= 0) 441 end function is_open 442 443 !--------------------------------------------------------------------- 422 444 ! Return the number of dimensions of variable with name var_name, or 423 445 ! -1 if the variable is not found … … 619 641 620 642 !--------------------------------------------------------------------- 643 ! Read an integer scalar 644 subroutine get_int_scalar(this, var_name, scalar) 645 class(netcdf_file) :: this 646 character(len=*), intent(in) :: var_name 647 integer, intent(out):: scalar 648 649 integer :: istatus 650 integer :: ivarid, ndims 651 integer :: ndimlens(NF90_MAX_VAR_DIMS) 652 integer :: j, ntotal 653 654 ! Inquire the ID, shape & size of the variable 655 call this%get_variable_id(var_name, ivarid) 656 call this%get_array_dimensions(ivarid, ndims, ndimlens) 657 658 ! Compute number of elements of the variable in the file 659 ntotal = 1 660 do j = 1, ndims 661 ntotal = ntotal * ndimlens(j) 662 end do 663 664 if (this%iverbose >= 3) then 665 write(nulout,'(a,a)',advance='no') ' Reading ', var_name 666 call this%print_variable_attributes(ivarid,nulout) 667 end if 668 669 ! Abort if the number of elements is anything other than 1 670 if (ntotal /= 1) then 671 write(nulerr,'(a,a,a,i0,a)') '*** Error reading NetCDF variable ', & 672 & var_name, ' with total length ', ntotal, ' as a scalar' 673 call my_abort('Error reading NetCDF file') 674 end if 675 676 ! Read variable 677 istatus = nf90_get_var(this%ncid, ivarid, scalar) 678 if (istatus /= NF90_NOERR) then 679 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 680 & var_name, ' as a scalar: ', trim(nf90_strerror(istatus)) 681 call my_abort('Error reading NetCDF file') 682 end if 683 684 end subroutine get_int_scalar 685 686 687 !--------------------------------------------------------------------- 621 688 ! Read a scalar from a larger array, where "index" indexes the most 622 689 ! slowly varying dimension 623 subroutine get_real_scalar_indexed(this, var_name, index, scalar)690 subroutine get_real_scalar_indexed(this, var_name, scalar, index) 624 691 class(netcdf_file) :: this 625 692 character(len=*), intent(in) :: var_name … … 676 743 677 744 !--------------------------------------------------------------------- 678 ! Read a 1D array into "vector", which must be allocatable and will679 ! be reallocated if necessary745 ! Read a 1D real array into "vector", which must be allocatable and 746 ! will be reallocated if necessary 680 747 subroutine get_real_vector(this, var_name, vector) 681 748 class(netcdf_file) :: this … … 734 801 735 802 !--------------------------------------------------------------------- 736 ! Read a 1D integer array into "vector", which must be allocatable803 ! Read a 1D character array into "vector", which must be allocatable 737 804 ! and will be reallocated if necessary 738 subroutine get_ integer_vector(this, var_name, vector)805 subroutine get_char_vector(this, var_name, vector) 739 806 class(netcdf_file) :: this 740 807 character(len=*), intent(in) :: var_name 741 integer, allocatable, intent(out) :: vector(:)808 character(len=1), allocatable, intent(out) :: vector(:) 742 809 743 810 integer :: n ! Length of vector … … 784 851 if (istatus /= NF90_NOERR) then 785 852 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 853 & var_name, ' as a vector of chars: ', trim(nf90_strerror(istatus)) 854 call my_abort('Error reading NetCDF file') 855 end if 856 857 end subroutine get_char_vector 858 859 860 !--------------------------------------------------------------------- 861 ! Read a 1D integer array into "vector", which must be allocatable 862 ! and will be reallocated if necessary 863 subroutine get_int_vector(this, var_name, vector) 864 865 class(netcdf_file) :: this 866 character(len=*), intent(in) :: var_name 867 integer, allocatable, intent(out) :: vector(:) 868 869 integer :: n ! Length of vector 870 integer :: istatus 871 integer :: ivarid, ndims 872 integer :: ndimlens(NF90_MAX_VAR_DIMS) 873 integer :: j 874 875 call this%get_variable_id(var_name, ivarid) 876 call this%get_array_dimensions(ivarid, ndims, ndimlens) 877 878 ! Ensure variable has only one dimension in the file 879 n = 1 880 do j = 1, ndims 881 n = n * ndimlens(j) 882 if (j > 1 .and. ndimlens(j) > 1) then 883 write(nulerr,'(a,a,a)') '*** Error reading NetCDF variable ', & 884 & var_name, & 885 & ' as a vector: all dimensions above the first must be singletons' 886 call my_abort('Error reading NetCDF file') 887 end if 888 end do 889 890 ! Reallocate if necessary 891 if (allocated(vector)) then 892 if (size(vector) /= n) then 893 if (this%iverbose >= 1) then 894 write(nulout,'(a,a)') ' Warning: resizing vector to read ', var_name 895 end if 896 deallocate(vector) 897 allocate(vector(n)) 898 end if 899 else 900 allocate(vector(n)) 901 end if 902 903 if (this%iverbose >= 3) then 904 write(nulout,'(a,a,a,i0,a)',advance='no') ' Reading ', var_name, '(', n, ')' 905 call this%print_variable_attributes(ivarid,nulout) 906 end if 907 908 ! Read variable 909 istatus = nf90_get_var(this%ncid, ivarid, vector) 910 if (istatus /= NF90_NOERR) then 911 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 786 912 & var_name, ' as an integer vector: ', trim(nf90_strerror(istatus)) 787 913 call my_abort('Error reading NetCDF file') 788 914 end if 789 915 790 end subroutine get_integer_vector 791 916 end subroutine get_int_vector 792 917 793 918 !--------------------------------------------------------------------- 794 919 ! Read a vector of data from a larger array; the vector must be 795 920 ! allocatable and will be reallocated if necessary 796 subroutine get_real_vector_indexed(this, var_name, index, vector)921 subroutine get_real_vector_indexed(this, var_name, vector, index) 797 922 class(netcdf_file) :: this 798 923 character(len=*), intent(in) :: var_name … … 975 1100 976 1101 !--------------------------------------------------------------------- 1102 ! Read 2D array of characters into "matrix", which must be 1103 ! allocatable and will be reallocated if necessary. Whether to 1104 ! transpose is specifed by the final optional argument, but can also 1105 ! be specified by the do_transpose_2d class data member. 1106 subroutine get_char_matrix(this, var_name, matrix, do_transp) 1107 class(netcdf_file) :: this 1108 character(len=*), intent(in) :: var_name 1109 character(len=1), allocatable, intent(inout) :: matrix(:,:) 1110 logical, optional, intent(in):: do_transp ! Transpose data? 1111 1112 character(len=1), allocatable:: tmp_matrix(:,:) 1113 integer :: ndimlen1, ndimlen2 1114 integer :: istatus 1115 integer :: ivarid, ndims 1116 integer :: ndimlens(NF90_MAX_VAR_DIMS) 1117 integer :: vstart(NF90_MAX_VAR_DIMS) 1118 integer :: vcount(NF90_MAX_VAR_DIMS) 1119 integer :: j, ntotal 1120 logical :: do_transpose 1121 1122 ! Decide whether to transpose the array 1123 if (present(do_transp)) then 1124 do_transpose = do_transp 1125 else 1126 do_transpose = this%do_transpose_2d 1127 end if 1128 1129 call this%get_variable_id(var_name, ivarid) 1130 call this%get_array_dimensions(ivarid, ndims, ndimlens) 1131 1132 ! Ensure the variable has no more than two non-singleton 1133 ! dimensions 1134 ntotal = 1 1135 do j = 1, ndims 1136 ntotal = ntotal * ndimlens(j) 1137 if (j > 2 .and. ndimlens(j) > 1) then 1138 write(nulerr,'(a,a,a)') '*** Error reading NetCDF variable ', & 1139 & var_name, & 1140 & ' as a matrix: all dimensions above the second must be singletons' 1141 call my_abort('Error reading NetCDF file') 1142 end if 1143 end do 1144 1145 ! Work out dimension lengths 1146 if (ndims >= 2) then 1147 ndimlen1 = ndimlens(1) 1148 ndimlen2 = ntotal/ndimlen1 1149 else 1150 ndimlen1 = ntotal 1151 ndimlen2 = 1 1152 end if 1153 1154 if (do_transpose) then 1155 ! Read and transpose 1156 allocate(tmp_matrix(ndimlen1, ndimlen2)) 1157 1158 ! Reallocate if necessary 1159 if (allocated(matrix)) then 1160 if (size(matrix,1) /= ndimlen2 .or. size(matrix,2) /= ndimlen1) then 1161 if (this%iverbose >= 1) then 1162 write(nulout,'(a,a)') ' Warning: resizing matrix to read ', var_name 1163 end if 1164 deallocate(matrix) 1165 allocate(matrix(ndimlen2, ndimlen1)) 1166 end if 1167 else 1168 allocate(matrix(ndimlen2, ndimlen1)) 1169 end if 1170 1171 if (this%iverbose >= 3) then 1172 write(nulout,'(a,a,a,i0,a,i0,a)',advance='no') ' Reading ', var_name, '(', & 1173 & ndimlen2, ',', ndimlen1, ')' 1174 call this%print_variable_attributes(ivarid,nulout) 1175 end if 1176 1177 istatus = nf90_get_var(this%ncid, ivarid, tmp_matrix) 1178 matrix = transpose(tmp_matrix) 1179 deallocate(tmp_matrix) 1180 else 1181 ! Read data without transposition 1182 1183 ! Reallocate if necessary 1184 if (allocated(matrix)) then 1185 if (size(matrix,1) /= ndimlen1 .or. size(matrix,2) /= ndimlen2) then 1186 if (this%iverbose >= 1) then 1187 write(nulout,'(a,a)') ' Warning: resizing matrix to read ', var_name 1188 end if 1189 allocate(matrix(ndimlen1, ndimlen2)) 1190 end if 1191 else 1192 allocate(matrix(ndimlen1, ndimlen2)) 1193 end if 1194 1195 if (this%iverbose >= 3) then 1196 write(nulout,'(a,a,a,i0,a,i0,a)',advance='no') ' Reading ', var_name, '(', & 1197 & ndimlen1, ',', ndimlen2, ')' 1198 call this%print_variable_attributes(ivarid,nulout) 1199 end if 1200 1201 vstart = 1 1202 vcount(1:2) = [ndimlen1,1] 1203 1204 do j = 1,ndimlen2 1205 vstart(2) = j 1206 istatus = nf90_get_var(this%ncid, ivarid, matrix(:,j), start=vstart, count=vcount) 1207 end do 1208 end if 1209 1210 if (istatus /= NF90_NOERR) then 1211 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 1212 & var_name, ' as a matrix of characters: ', trim(nf90_strerror(istatus)) 1213 call my_abort('Error reading NetCDF file') 1214 end if 1215 1216 end subroutine get_char_matrix 1217 1218 1219 !--------------------------------------------------------------------- 977 1220 ! Read matrix of data from a larger array, which must be allocatable 978 1221 ! and will be reallocated if necessary. Whether to transpose is 979 1222 ! specifed by the final optional argument, but can also be specified 980 1223 ! by the do_transpose_2d class data member. 981 subroutine get_real_matrix_indexed(this, var_name, index, matrix, do_transp)1224 subroutine get_real_matrix_indexed(this, var_name, matrix, index, do_transp) 982 1225 class(netcdf_file) :: this 983 1226 character(len=*), intent(in) :: var_name … … 1187 1430 if (this%iverbose >= 3) then 1188 1431 write(nulout,'(a,a,a,i0,i0,i0,a)',advance='no') ' Reading ', var_name, & 1189 & ' (permut eddimensions ', i_permute_3d, ')'1432 & ' (permuting dimensions ', i_permute_3d, ')' 1190 1433 call this%print_variable_attributes(ivarid,nulout) 1191 1434 end if … … 1235 1478 ! be allocatable and will be reallocated if necessary. Whether to 1236 1479 ! pemute is specifed by the final optional argument 1237 subroutine get_real_array3_indexed(this, var_name, index, var, ipermute)1480 subroutine get_real_array3_indexed(this, var_name, var, index, ipermute) 1238 1481 class(netcdf_file) :: this 1239 1482 character(len=*), intent(in) :: var_name … … 1331 1574 write(nulout,'(a,i0,a,a,a,i0,i0,i0,a)') ' Reading slice ', index, & 1332 1575 & ' of ', var_name, & 1333 & ' (permut eddimensions ', i_permute_3d, ')'1576 & ' (permuting dimensions ', i_permute_3d, ')' 1334 1577 end if 1335 1578 … … 1471 1714 if (this%iverbose >= 3) then 1472 1715 write(nulout,'(a,a,a,i0,i0,i0,a)',advance='no') ' Reading ', var_name, & 1473 & ' (permut eddimensions ', i_permute_4d, ')'1716 & ' (permuting dimensions ', i_permute_4d, ')' 1474 1717 call this%print_variable_attributes(ivarid,nulout) 1475 1718 end if … … 1549 1792 ! allocate(character(len=i_attr_len) :: attr_str) 1550 1793 if (len(attr_str) < i_attr_len) then 1551 write(nulerr,'(a,a)') '*** Error: not enough space to read attribute ', attr_name1794 write(nulerr,'(a,a)') '*** Not enough space to read attribute ', attr_name 1552 1795 call my_abort('Error reading NetCDF file') 1553 1796 end if … … 1577 1820 real(jprb), intent(out) :: attr 1578 1821 1579 integer :: i _attr_len, ivarid1822 integer :: ivarid 1580 1823 integer :: istatus 1581 integer :: j1582 1824 1583 1825 istatus = nf90_inq_varid(this%ncid, var_name, ivarid) … … 1624 1866 ! allocate(character(len=i_attr_len) :: attr_str) 1625 1867 if (len(attr_str) < i_attr_len) then 1626 write(nulerr,'(a,a)') '*** Error: not enough space to read global attribute ', attr_name1868 write(nulerr,'(a,a)') '*** Not enough space to read global attribute ', attr_name 1627 1869 call my_abort('Error reading NetCDF file') 1628 1870 end if … … 1652 1894 1653 1895 character(len=4000) :: attr_str 1654 integer :: i_attr_len1655 1896 integer :: istatus 1656 integer :: j1657 1897 1658 1898 if (this%iverbose >= 4) then 1659 1899 istatus = nf90_get_att(this%ncid, ivarid, 'long_name', attr_str) 1660 1900 if (istatus == NF90_NOERR) then 1661 write(iunit, '(a)') ':' 1662 write(iunit, '(a,a)', advance='no') ' ', trim(attr_str) 1901 write(iunit, '(a,a,a)', advance='no') ': "', trim(attr_str), '"' 1663 1902 istatus = nf90_get_att(this%ncid, ivarid, 'units', attr_str) 1664 1903 if (istatus == NF90_NOERR) then … … 1721 1960 ! names. 1722 1961 subroutine define_variable(this, var_name, dim1_name, dim2_name, dim3_name, & 1723 & long_name, units_str, comment_str, standard_name, is_double, & 1724 & data_type_name, fill_value, deflate_level, shuffle, chunksizes) 1962 & dim4_name, long_name, units_str, comment_str, & 1963 & standard_name, is_double, data_type_name, fill_value, & 1964 & deflate_level, shuffle, chunksizes, ndims) 1725 1965 class(netcdf_file) :: this 1726 1966 character(len=*), intent(in) :: var_name 1727 1967 character(len=*), intent(in), optional :: long_name, units_str, comment_str, standard_name 1728 character(len=*), intent(in), optional :: dim1_name, dim2_name, dim3_name 1968 character(len=*), intent(in), optional :: dim1_name, dim2_name, dim3_name, dim4_name 1729 1969 logical, intent(in), optional :: is_double 1730 1970 character(len=*), intent(in), optional :: data_type_name … … 1733 1973 logical, intent(in), optional :: shuffle ! Shuffle bytes before compression 1734 1974 integer, dimension(:), intent(in), optional :: chunksizes 1735 1736 integer :: istatus, ndims, ivarid 1975 integer, intent(in), optional :: ndims 1976 1977 integer :: istatus, ndims_local, ndims_input, ivarid 1737 1978 integer, dimension(NF90_MAX_VAR_DIMS) :: idimids 1738 1979 integer :: data_type 1739 1980 1740 if (present(dim1_name)) then 1981 ! Sometimes a program may not know at compile time the exact 1982 ! dimensions of a variable - if ndims is present then only up to 1983 ! that many dimensions will be defined 1984 ndims_input = 4 1985 if (present(ndims)) then 1986 ndims_input = ndims 1987 end if 1988 1989 if (present(dim1_name) .and. ndims_input >= 1) then 1741 1990 ! Variable is at least one dimensional 1742 ndims = 11991 ndims_local = 1 1743 1992 istatus = nf90_inq_dimid(this%ncid, dim1_name, idimids(1)) 1744 1993 if (istatus /= NF90_NOERR) then … … 1747 1996 call my_abort('Error writing NetCDF file') 1748 1997 end if 1749 if (present(dim2_name) ) then1998 if (present(dim2_name) .and. ndims_input >= 2) then 1750 1999 ! Variable is at least two dimensional 1751 ndims = 22000 ndims_local = 2 1752 2001 istatus = nf90_inq_dimid(this%ncid, dim2_name, idimids(2)) 1753 2002 if (istatus /= NF90_NOERR) then … … 1756 2005 call my_abort('Error writing NetCDF file') 1757 2006 end if 1758 if (present(dim3_name) ) then2007 if (present(dim3_name) .and. ndims_input >= 3) then 1759 2008 ! Variable is at least three dimensional 1760 ndims = 32009 ndims_local = 3 1761 2010 istatus = nf90_inq_dimid(this%ncid, dim3_name, idimids(3)) 1762 2011 if (istatus /= NF90_NOERR) then … … 1765 2014 call my_abort('Error writing NetCDF file') 1766 2015 end if 2016 if (present(dim4_name) .and. ndims_input >= 4) then 2017 ! Variable is at least three dimensional 2018 ndims_local = 4 2019 istatus = nf90_inq_dimid(this%ncid, dim4_name, idimids(4)) 2020 if (istatus /= NF90_NOERR) then 2021 write(nulerr,'(a,a,a,a)') '*** Error inquiring ID of dimension ', & 2022 & dim4_name, ': ', trim(nf90_strerror(istatus)) 2023 call my_abort('Error writing NetCDF file') 2024 end if 2025 end if 1767 2026 end if 1768 2027 end if 1769 2028 else 1770 2029 ! Variable is a scalar 1771 ndims = 02030 ndims_local = 0 1772 2031 end if 1773 2032 1774 2033 ! Read output precision from optional argument "is_double" if 1775 2034 ! present, otherwise from default output precision for this file 1776 data_type = NF90_FLOAT ! Default1777 2035 if (present(data_type_name)) then 1778 2036 if (data_type_name == 'double') then … … 1787 2045 data_type = NF90_FLOAT 1788 2046 else 1789 write(nulerr,'(a,a,a)') '*** Error: netCDF data type "', data_type_name, '" not supported'2047 write(nulerr,'(a,a,a)') '*** NetCDF data type "', data_type_name, '" not supported' 1790 2048 call my_abort('Error writing NetCDF file') 1791 2049 end if 1792 2050 else if (present(is_double)) then 2051 if (is_double) then 2052 data_type = NF90_DOUBLE 2053 else 2054 data_type = NF90_FLOAT 2055 end if 2056 else if (this%is_double_precision) then 1793 2057 data_type = NF90_DOUBLE 2058 else 2059 data_type = NF90_FLOAT 1794 2060 end if 1795 2061 1796 2062 ! Define variable 1797 2063 #ifdef NC_NETCDF4 1798 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims ), &2064 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims_local), & 1799 2065 & ivarid, deflate_level=deflate_level, shuffle=shuffle, chunksizes=chunksizes) 1800 2066 #else 1801 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims ), ivarid)2067 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims_local), ivarid) 1802 2068 #endif 1803 2069 if (istatus /= NF90_NOERR) then … … 1811 2077 istatus = nf90_put_att(this%ncid, ivarid, "long_name", long_name) 1812 2078 if (this%iverbose >= 4) then 1813 write(nulout,'(a,a,a,a)') ' Defining ',trim(var_name),': ',long_name 2079 write(nulout,'(a,a,a,a,a)', advance='no') ' Defining ',trim(var_name), & 2080 & ': "', long_name, '"' 1814 2081 end if 1815 2082 else 1816 2083 if (this%iverbose >= 4) then 1817 write(nulout,'(a,a)') ' Defining ',trim(var_name) 1818 end if 1819 end if 2084 write(nulout,'(a,a)', advance='no') ' Defining ',trim(var_name) 2085 end if 2086 end if 2087 1820 2088 if (present(units_str)) then 1821 2089 istatus = nf90_put_att(this%ncid, ivarid, "units", units_str) 1822 end if 2090 if (this%iverbose >= 4) then 2091 if (trim(units_str) == '1') then 2092 write(nulout, '(a)') ' (dimensionless)' 2093 else 2094 write(nulout, '(a,a,a)') ' (', trim(units_str), ')' 2095 end if 2096 end if 2097 else 2098 if (this%iverbose >= 4) then 2099 write(nulout, '(1x)') 2100 end if 2101 end if 2102 1823 2103 if (present(standard_name)) then 1824 2104 istatus = nf90_put_att(this%ncid, ivarid, "standard_name", standard_name) … … 1863 2143 subroutine put_global_attributes(this, title_str, inst_str, source_str, & 1864 2144 & comment_str, references_str, creator_name, creator_email_str, & 1865 & contributor_name, project_str, conventions_str )2145 & contributor_name, project_str, conventions_str, prior_history_str) 1866 2146 class(netcdf_file) :: this 1867 2147 … … 1872 2152 character(len=*), intent(in), optional :: contributor_name, project_str 1873 2153 character(len=*), intent(in), optional :: comment_str, conventions_str 1874 character(len=*), intent(in), optional :: references_str 2154 character(len=*), intent(in), optional :: references_str, prior_history_str 1875 2155 1876 2156 character(len=32) :: date_time_str … … 1887 2167 & time_vals(1), time_vals(2), time_vals(3), time_vals(5), time_vals(6), time_vals(7) 1888 2168 1889 history_str = trim(date_time_str) // ': ' // trim(command_line_str) 2169 if (present(prior_history_str)) then 2170 history_str = trim(prior_history_str) // new_line('a') & 2171 & // trim(date_time_str) // ': ' // trim(command_line_str) 2172 else 2173 history_str = trim(date_time_str) // ': ' // trim(command_line_str) 2174 end if 1890 2175 1891 2176 if (present(title_str)) i=nf90_put_att(this%ncid, NF90_GLOBAL, "title", title_str) … … 2057 2342 2058 2343 !--------------------------------------------------------------------- 2344 ! Save an integer vector with name var_name in the file 2345 subroutine put_int_vector(this, var_name, var) 2346 class(netcdf_file) :: this 2347 character(len=*), intent(in) :: var_name 2348 integer, intent(in) :: var(:) 2349 2350 integer :: ivarid, ndims, istatus 2351 integer(kind=jpib) :: ntotal 2352 integer :: ndimlens(NF90_MAX_VAR_DIMS) 2353 2354 call this%end_define_mode() 2355 2356 ! Check the vector is of the right length 2357 call this%get_variable_id(var_name, ivarid) 2358 call this%get_array_dimensions(ivarid, ndims, ndimlens, ntotal) 2359 if (ntotal /= size(var,kind=jpib)) then 2360 write(nulerr,'(a,i0,a,a,a,i0)') '*** Error: attempt to write vector of length ', & 2361 & size(var), ' to ', var_name, ' which has total length ', ntotal 2362 call my_abort('Error writing NetCDF file') 2363 end if 2364 2365 ! Save the vector 2366 istatus = nf90_put_var(this%ncid, ivarid, var) 2367 if (istatus /= NF90_NOERR) then 2368 write(nulerr,'(a,a,a,a)') '*** Error writing vector ', var_name, ': ', & 2369 & trim(nf90_strerror(istatus)) 2370 call my_abort('Error writing NetCDF file') 2371 end if 2372 2373 end subroutine put_int_vector 2374 2375 2376 !--------------------------------------------------------------------- 2059 2377 ! Save a vector slice with name var_name in the file 2060 subroutine put_real_vector_indexed(this, var_name, index, var)2378 subroutine put_real_vector_indexed(this, var_name, var, index2, index3) 2061 2379 class(netcdf_file) :: this 2062 2380 character(len=*), intent(in) :: var_name 2063 2381 real(jprb), intent(in) :: var(:) 2064 integer, intent(in) :: index 2382 integer, intent(in) :: index2 2383 integer, intent(in), optional :: index3 2065 2384 2066 2385 integer :: ivarid, ndims, istatus … … 2070 2389 integer :: vcount(NF90_MAX_VAR_DIMS) 2071 2390 2391 character(len=512) :: var_slice_name 2392 integer :: index_last 2393 2072 2394 call this%end_define_mode() 2073 2395 … … 2076 2398 call this%get_array_dimensions(ivarid, ndims, ndimlens, ntotal) 2077 2399 ntotal = ntotal / ndimlens(ndims) 2400 if (present(index3)) then 2401 ntotal = ntotal / ndimlens(ndims-1) 2402 index_last = index3 2403 write(var_slice_name,'(a,a,i0,a,i0,a)') var_name, '(:,', index2, ',', index3, ')' 2404 else 2405 index_last = index2 2406 write(var_slice_name,'(a,a,i0,a)') var_name, '(:,', index2, ')' 2407 end if 2408 2078 2409 if (ntotal /= size(var,kind=jpib)) then 2079 write(nulerr,'(a,i0,a,a, a,i0)') '*** Error: attempt to write vector of length ', &2080 & size(var), ' to slice of ', var_name, ' which has length ', ntotal2410 write(nulerr,'(a,i0,a,a,i0)') '*** Error: attempt to write vector of length ', & 2411 & size(var), ' to ', trim(var_slice_name), ' which has length ', ntotal 2081 2412 call my_abort('Error writing NetCDF file') 2082 2413 end if 2083 if (index < 1 .or. index> ndimlens(ndims)) then2084 write(nulerr,'(a, i0,a,a,a,i0)') '*** Error: attempt to write vector to slice', &2085 & index, ' of ', var_name, ' which has outer dimension ', ndimlens(ndims)2414 if (index_last < 1 .or. index_last > ndimlens(ndims)) then 2415 write(nulerr,'(a,a,a,i0)') '*** Error: attempt to write vector to ', & 2416 & trim(var_slice_name), ' which has outer dimension ', ndimlens(ndims) 2086 2417 call my_abort('Error writing NetCDF file') 2087 2418 end if … … 2089 2420 ! Save the vector 2090 2421 vstart(1:ndims-1) = 1 2091 vstart(ndims) = index2092 2422 vcount(1:ndims-1) = ndimlens(1:ndims-1) 2093 2423 vcount(ndims) = 1 2424 if (present(index3)) then 2425 vstart(ndims) = index3 2426 vstart(ndims-1) = index2 2427 vcount(ndims-1) = 1 2428 else 2429 vstart(ndims) = index2 2430 end if 2431 2094 2432 istatus = nf90_put_var(this%ncid, ivarid, var, start=vstart, count=vcount) 2095 2433 if (istatus /= NF90_NOERR) then 2096 write(nulerr,'(a,a,a,a)') '*** Error writing vector to ', var_name, ': ', &2097 & 2434 write(nulerr,'(a,a,a,a)') '*** Error writing vector to ', trim(var_slice_name), & 2435 & ': ', trim(nf90_strerror(istatus)) 2098 2436 call my_abort('Error writing NetCDF file') 2099 2437 end if … … 2171 2509 ! dimensions if either optional argument transp is .true., or the 2172 2510 ! transpose_matrices method has already been called. 2173 subroutine put_real_matrix_indexed(this, var_name, index, var, do_transp)2511 subroutine put_real_matrix_indexed(this, var_name, var, index3, index4, do_transp) 2174 2512 class(netcdf_file) :: this 2175 2513 character(len=*), intent(in) :: var_name 2176 2514 real(jprb), intent(in) :: var(:,:) 2177 integer, intent(in) :: index 2515 integer, intent(in) :: index3 2516 integer, intent(in), optional :: index4 2178 2517 2179 2518 real(jprb), allocatable :: var_transpose(:,:) 2180 logical, optional, intent(in) :: do_transp2519 logical, optional, intent(in) :: do_transp 2181 2520 2182 2521 integer :: ivarid, ndims, nvarlen, istatus … … 2186 2525 integer :: vcount(NF90_MAX_VAR_DIMS) 2187 2526 2527 character(len=512) :: var_slice_name 2528 2188 2529 logical :: do_transpose 2189 2530 … … 2204 2545 ! ntotal is zero then there must be an unlimited dimension) 2205 2546 ntotal = ntotal / ndimlens(ndims) 2547 if (present(index4)) then 2548 ntotal = ntotal / ndimlens(ndims-1) 2549 write(var_slice_name,'(a,a,i0,a,i0,a)') var_name, '(:,:,', index3, ',', index4, ')' 2550 else 2551 write(var_slice_name,'(a,a,i0,a)') var_name, '(:,:,', index3, ')' 2552 end if 2206 2553 if (ntotal /= size(var,kind=jpib) .and. ntotal /= 0) then 2207 2554 write(nulerr,'(a,i0,a,a,a,i0)') '*** Error: attempt to write matrix of total size ', & 2208 & nvarlen, ' to ', var_name, ' which has total size ', ntotal2555 & nvarlen, ' to ', trim(var_slice_name), ' which has total size ', ntotal 2209 2556 call my_abort('Error writing NetCDF file') 2210 2557 end if 2211 2558 2212 2559 vstart(1:ndims-1) = 1 2213 vstart(ndims) = index2214 2560 vcount(1:ndims-1) = ndimlens(1:ndims-1) 2215 2561 vcount(ndims) = 1 2562 if (present(index4)) then 2563 vstart(ndims) = index4 2564 vstart(ndims-1) = index3 2565 vcount(ndims-1) = 1 2566 else 2567 vstart(ndims) = index3 2568 end if 2216 2569 2217 2570 if (do_transpose) then 2218 2571 ! Save the matrix with transposition 2219 2572 if (this%iverbose >= 3) then 2220 write(nulout,'(a, i0,a,a,a)') ' Writing slice ', index, ' of ', var_name, &2573 write(nulout,'(a,a,a)') ' Writing ', trim(var_slice_name), & 2221 2574 & ' (transposing dimensions)' 2222 2575 end if … … 2228 2581 ! Save the matrix without transposition 2229 2582 if (this%iverbose >= 3) then 2230 write(nulout,'(a, i0,a,a)') ' Writing slice ', index, ' of ', var_name2583 write(nulout,'(a,a)') ' Writing ', trim(var_slice_name) 2231 2584 end if 2232 2585 istatus = nf90_put_var(this%ncid, ivarid, var, start=vstart, count=vcount) … … 2234 2587 2235 2588 if (istatus /= NF90_NOERR) then 2236 write(nulerr,'(a,a,a ,a)') '*** Error writing matrix ', var_name, &2589 write(nulerr,'(a,a,a)') '*** Error writing ', trim(var_slice_name), & 2237 2590 & ': ', trim(nf90_strerror(istatus)) 2238 2591 call my_abort('Error writing NetCDF file') … … 2291 2644 if (this%iverbose >= 3) then 2292 2645 write(nulout,'(a,a,a,i0,i0,i0,a)') ' Writing ', var_name, & 2293 & ' (permut eddimensions: ', i_permute_3d, ')'2646 & ' (permuting dimensions: ', i_permute_3d, ')' 2294 2647 end if 2295 2648 n_dimlens_permuted = (/ size(var,i_permute_3d(1)), & 2296 2649 & size(var,i_permute_3d(2)), & 2297 2650 & size(var,i_permute_3d(3)) /) 2298 if (this%iverbose >= 4) then 2299 write(nulout,'(a,i0,a,i0,a,i0,a,i0,a,i0,a,i0,a)') ' (', & 2300 & n_dimlens_permuted(1), ',', n_dimlens_permuted(2), & 2301 & ',', n_dimlens_permuted(3), ') -> (', ndimlens(1), & 2302 & ',', ndimlens(2), ',', ndimlens(3), ')' 2303 end if 2651 !! FIX: This makes it look like the dimensions have stayed the same 2652 ! if (this%iverbose >= 4) then 2653 ! write(nulout,'(a,i0,a,i0,a,i0,a,i0,a,i0,a,i0,a)') ' (', & 2654 ! & n_dimlens_permuted(1), ',', n_dimlens_permuted(2), & 2655 ! & ',', n_dimlens_permuted(3), ') -> (', ndimlens(1), & 2656 ! & ',', ndimlens(2), ',', ndimlens(3), ')' 2657 ! end if 2304 2658 allocate(var_permute(n_dimlens_permuted(1), & 2305 2659 & n_dimlens_permuted(2), n_dimlens_permuted(3))) … … 2326 2680 end subroutine put_real_array3 2327 2681 2682 2683 #ifdef NC_NETCDF4 2684 !--------------------------------------------------------------------- 2685 ! Copy dimensions from "infile" to "this" 2686 subroutine copy_dimensions(this, infile) 2687 class(netcdf_file) :: this 2688 type(netcdf_file), intent(in) :: infile 2689 2690 integer :: jdim 2691 integer :: ndims 2692 integer :: idimids(1024) 2693 integer :: dimlen 2694 character(len=512) :: dimname 2695 integer :: istatus 2696 integer :: include_parents 2697 2698 include_parents = 0 2699 2700 istatus = nf90_inq_dimids(infile%ncid, ndims, idimids, include_parents) 2701 if (istatus /= NF90_NOERR) then 2702 write(nulerr,'(a,a)') '*** Error reading dimensions of NetCDF file: ', & 2703 trim(nf90_strerror(istatus)) 2704 call my_abort('Error reading NetCDF file') 2705 end if 2706 2707 do jdim = 1,ndims 2708 istatus = nf90_inquire_dimension(infile%ncid, idimids(jdim), & 2709 & name=dimname, len=dimlen) 2710 if (istatus /= NF90_NOERR) then 2711 write(nulerr,'(a,a)') '*** Error reading NetCDF dimension properties: ', & 2712 trim(nf90_strerror(istatus)) 2713 call my_abort('Error reading NetCDF file') 2714 end if 2715 call this%define_dimension(trim(dimname), dimlen) 2716 end do 2717 2718 end subroutine copy_dimensions 2719 #endif 2720 2721 !--------------------------------------------------------------------- 2722 ! Copy variable definition and attributes from "infile" to "this" 2723 subroutine copy_variable_definition(this, infile, var_name) 2724 class(netcdf_file) :: this 2725 type(netcdf_file), intent(in) :: infile 2726 character(len=*), intent(in) :: var_name 2727 2728 #ifdef NC_NETCDF4 2729 integer :: deflate_level ! Compression: 0 (none) to 9 (most) 2730 logical :: shuffle ! Shuffle bytes before compression 2731 integer :: chunksizes(NF90_MAX_VAR_DIMS) 2732 #endif 2733 integer :: data_type 2734 integer :: ndims 2735 integer :: idimids_in(NF90_MAX_VAR_DIMS) 2736 integer :: idimids_out(NF90_MAX_VAR_DIMS) 2737 integer :: nattr 2738 character(len=512) :: attr_name 2739 character(len=512) :: dim_name 2740 2741 integer :: istatus 2742 integer :: ivarid_in, ivarid_out 2743 integer :: jattr, jdim 2744 2745 if (this%iverbose >= 4) then 2746 write(nulout,'(a,a)') ' Copying definition of ', trim(var_name) 2747 end if 2748 2749 ! Get variable ID from name 2750 istatus = nf90_inq_varid(infile%ncid, var_name, ivarid_in) 2751 if (istatus /= NF90_NOERR) then 2752 write(nulerr,'(a,i0,a)') '*** Error inquiring about NetCDF variable "', & 2753 & var_name, '": ', trim(nf90_strerror(istatus)) 2754 call my_abort('Error reading NetCDF file') 2755 end if 2756 2757 ! Get variable properties 2758 #ifdef NC_NETCDF4 2759 istatus = nf90_inquire_variable(infile%ncid, ivarid_in, xtype=data_type, ndims=ndims, & 2760 & dimids=idimids_in, chunksizes=chunksizes, deflate_level=deflate_level, & 2761 & shuffle=shuffle, natts=nattr) 2762 #else 2763 istatus = nf90_inquire_variable(infile%ncid, ivarid_in, xtype=data_type, ndims=ndims, & 2764 & dimids=idimids_in, natts=nattr) 2765 #endif 2766 if (istatus /= NF90_NOERR) then 2767 write(nulerr,'(a,a)') '*** Error reading NetCDF variable properties: ', & 2768 trim(nf90_strerror(istatus)) 2769 call my_abort('Error reading NetCDF file') 2770 end if 2771 2772 ! Map dimension IDs 2773 do jdim = 1,ndims 2774 istatus = nf90_inquire_dimension(infile%ncid, idimids_in(jdim), name=dim_name) 2775 if (istatus /= NF90_NOERR) then 2776 write(nulerr,'(a,a)') '*** Error reading NetCDF dimension name: ', & 2777 trim(nf90_strerror(istatus)) 2778 call my_abort('Error reading NetCDF file') 2779 end if 2780 2781 istatus = nf90_inq_dimid(this%ncid, trim(dim_name), idimids_out(jdim)) 2782 if (istatus /= NF90_NOERR) then 2783 write(nulerr,'(a,a)') '*** Error reading NetCDF dimension ID: ', & 2784 trim(nf90_strerror(istatus)) 2785 call my_abort('Error reading NetCDF file') 2786 end if 2787 end do 2788 2789 ! Create variable 2790 #ifdef NC_NETCDF4 2791 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids_out(1:ndims), & 2792 & ivarid_out, deflate_level=deflate_level, shuffle=shuffle, chunksizes=chunksizes(1:ndims)) 2793 #else 2794 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids_out(1:ndims), ivarid_out) 2795 #endif 2796 if (istatus /= NF90_NOERR) then 2797 write(nulerr,'(a,a,a,a)') '*** Error defining variable "', var_name, & 2798 & '": ', trim(nf90_strerror(istatus)) 2799 call my_abort('Error writing NetCDF file') 2800 end if 2801 2802 ! Copy attributes 2803 do jattr = 1,nattr 2804 istatus = nf90_inq_attname(infile%ncid, ivarid_in, jattr, attr_name) 2805 if (istatus /= NF90_NOERR) then 2806 write(nulerr,'(a,a)') '*** Error reading attribute: ', & 2807 & trim(nf90_strerror(istatus)) 2808 call my_abort('Error reading NetCDF file') 2809 end if 2810 istatus = nf90_copy_att(infile%ncid, ivarid_in, trim(attr_name), & 2811 & this%ncid, ivarid_out) 2812 2813 end do 2814 2815 end subroutine copy_variable_definition 2816 2817 2818 !--------------------------------------------------------------------- 2819 ! Copy variable from "infile" to "this" 2820 subroutine copy_variable(this, infile, var_name) 2821 class(netcdf_file) :: this 2822 class(netcdf_file), intent(in) :: infile 2823 character(len=*), intent(in) :: var_name 2824 2825 integer :: ivarid_in, ivarid_out 2826 integer :: ndims 2827 integer :: ndimlens(NF90_MAX_VAR_DIMS) 2828 integer(kind=jpib) :: ntotal 2829 integer :: data_type 2830 integer :: istatus 2831 2832 ! We use the Fortran-77 functions because they don't check that 2833 ! the rank of the arguments is correct 2834 integer, external :: nf_get_var_double, nf_put_var_double 2835 integer, external :: nf_get_var_int, nf_put_var_int 2836 2837 real(kind=jprd), allocatable :: data_real(:) 2838 integer, allocatable :: data_int(:) 2839 2840 ! If we are in define mode, exit define mode 2841 call this%end_define_mode() 2842 2843 if (this%iverbose >= 4) then 2844 write(nulout,'(a,a)') ' Copying ', trim(var_name) 2845 end if 2846 2847 call infile%get_variable_id(var_name, ivarid_in) 2848 call infile%get_array_dimensions(ivarid_in, ndims, ndimlens, ntotal) 2849 istatus = nf90_inquire_variable(infile%ncid, ivarid_in, xtype=data_type) 2850 if (istatus /= NF90_NOERR) then 2851 write(nulerr,'(a,a,a,a)') '*** Error reading variable "', var_name, '": ', & 2852 & trim(nf90_strerror(istatus)) 2853 call my_abort('Error reading NetCDF file') 2854 end if 2855 2856 call infile%get_variable_id(var_name, ivarid_out) 2857 if (data_type == NF90_DOUBLE .or. data_type == NF90_FLOAT) then 2858 allocate(data_real(ntotal)) 2859 !istatus = nf90_get_var(infile%ncid, ivarid_in, data_real(1)) 2860 istatus = nf_get_var_double(infile%ncid, ivarid_in, data_real) 2861 if (istatus /= NF90_NOERR) then 2862 deallocate(data_real) 2863 write(nulerr,'(a,a,a,a)') '*** Error reading variable "', var_name, '": ', & 2864 & trim(nf90_strerror(istatus)) 2865 call my_abort('Error reading NetCDF file') 2866 end if 2867 2868 !istatus = nf90_put_var(this%ncid, ivarid_out, data_real) 2869 istatus = nf_put_var_double(this%ncid, ivarid_out, data_real) 2870 deallocate(data_real) 2871 if (istatus /= NF90_NOERR) then 2872 write(nulerr,'(a,a,a,a)') '*** Error writing variable "', var_name, '": ', & 2873 & trim(nf90_strerror(istatus)) 2874 call my_abort('Error writing NetCDF file') 2875 end if 2876 2877 else 2878 allocate(data_int(ntotal)) 2879 !istatus = nf90_get_var(infile%ncid, ivarid_in, data_int) 2880 istatus = nf_get_var_int(infile%ncid, ivarid_in, data_int) 2881 if (istatus /= NF90_NOERR) then 2882 deallocate(data_int) 2883 2884 write(nulerr,'(a,a,a,a)') '*** Error reading variable "', var_name, '": ', & 2885 & trim(nf90_strerror(istatus)) 2886 call my_abort('Error reading NetCDF file') 2887 end if 2888 2889 !istatus = nf90_put_var(this%ncid, ivarid_out, data_int) 2890 istatus = nf_put_var_int(this%ncid, ivarid_out, data_int) 2891 deallocate(data_int) 2892 if (istatus /= NF90_NOERR) then 2893 write(nulerr,'(a,a,a,a)') '*** Error writing variable "', var_name, '": ', & 2894 & trim(nf90_strerror(istatus)) 2895 call my_abort('Error writing NetCDF file') 2896 end if 2897 end if 2898 2899 end subroutine copy_variable 2900 2328 2901 end module easy_netcdf -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_adding_ica_lw.F90
r3908 r4444 296 296 297 297 ! Loop index for model level 298 integer :: jlev 298 integer :: jlev, jcol 299 299 300 300 real(jprb) :: hook_handle … … 307 307 ! Work down through the atmosphere computing the downward fluxes 308 308 ! at each half-level 309 ! Added for DWD (2020) 310 !NEC$ outerloop_unroll(8) 309 311 do jlev = 1,nlev 310 flux_dn(:,jlev+1) = transmittance(:,jlev)*flux_dn(:,jlev) + source_dn(:,jlev) 312 do jcol = 1,ncol 313 flux_dn(jcol,jlev+1) = transmittance(jcol,jlev)*flux_dn(jcol,jlev) + source_dn(jcol,jlev) 314 end do 311 315 end do 312 316 … … 316 320 ! Work back up through the atmosphere computing the upward fluxes 317 321 ! at each half-level 322 ! Added for DWD (2020) 323 !NEC$ outerloop_unroll(8) 318 324 do jlev = nlev,1,-1 319 flux_up(:,jlev) = transmittance(:,jlev)*flux_up(:,jlev+1) + source_up(:,jlev) 325 do jcol = 1,ncol 326 flux_up(jcol,jlev) = transmittance(jcol,jlev)*flux_up(jcol,jlev+1) + source_up(jcol,jlev) 327 end do 320 328 end do 321 329 -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_adding_ica_sw.F90
r3908 r4444 98 98 ! also the "source", which is the upwelling flux due to direct 99 99 ! radiation that is scattered below that level 100 ! Added for DWD (2020) 101 !NEC$ outerloop_unroll(8) 100 102 do jlev = nlev,1,-1 101 103 ! Next loop over columns. We could do this by indexing the … … 128 130 ! Work back down through the atmosphere computing the fluxes at 129 131 ! each half-level 132 ! Added for DWD (2020) 133 !NEC$ outerloop_unroll(8) 130 134 do jlev = 1,nlev 131 135 do jcol = 1,ncol -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_aerosol.F90
r3908 r4444 115 115 allocate(this%g_lw (config%n_bands_lw,istartlev:iendlev,ncol)) 116 116 ! If longwave scattering by aerosol is not to be represented, 117 ! then the user may wish to just provide absorption optical deth118 ! in od_lw, in which case we must set the following two117 ! then the user may wish to just provide absorption optical 118 ! depth in od_lw, in which case we must set the following two 119 119 ! variables to zero 120 120 this%ssa_lw = 0.0_jprb … … 128 128 129 129 !--------------------------------------------------------------------- 130 ! Deallocate array 130 ! Deallocate arrays 131 131 subroutine deallocate_aerosol_arrays(this) 132 132 … … 158 158 159 159 use yomhook, only : lhook, dr_hook 160 use radiation_c onfig,only : out_of_bounds_3d160 use radiation_check, only : out_of_bounds_3d 161 161 162 162 class(aerosol_type), intent(inout) :: this -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_aerosol_optics.F90
r4188 r4444 14 14 ! 15 15 ! Modifications 16 ! 2018-04-15 R Hogan Add "direct" option 16 ! 2018-04-15 R. Hogan Add "direct" option 17 ! 2020-11-14 R. Hogan Add setup_general_aerosol_optics for ecCKD compatibility 18 ! 2022-03-27 R. Hogan Add setup_general_aerosol_optics_legacy to use RRTM aerosol files with ecCKD 17 19 18 20 module radiation_aerosol_optics … … 36 38 use radiation_aerosol_optics_data, only : aerosol_optics_type 37 39 use radiation_io, only : nulerr, radiation_abort 38 use setup_aerosol_optics_lmdz_m, only: setup_aerosol_optics_lmdz40 use setup_aerosol_optics_lmdz_m, only: setup_aerosol_optics_lmdz 39 41 40 42 type(config_type), intent(inout) :: config … … 47 49 ! Load data from file and prepare to map config%n_aerosol_types 48 50 ! aerosol types 49 call setup_aerosol_optics_lmdz(config%aerosol_optics, & 50 trim(config%aerosol_optics_file_name)) 51 if (config%use_general_aerosol_optics) then 52 ! Read file containing high spectral resolution optical 53 ! properties and average to the spectral intervals of the 54 ! current gas-optics scheme 55 ! call setup_general_aerosol_optics(config) 56 call setup_general_aerosol_optics_lmdz(config,trim(config%aerosol_optics_file_name)) 57 else 58 ! Read file containing optical properties already in the bands 59 ! of the gas-optics scheme 60 ! call config%aerosol_optics%setup(trim(config%aerosol_optics_file_name), & 61 ! & iverbose=config%iverbosesetup) 62 call setup_aerosol_optics_lmdz(config%aerosol_optics, & 63 trim(config%aerosol_optics_file_name)) 64 end if 65 66 call config%aerosol_optics%initialize_types(config%n_aerosol_types) 51 67 52 68 ! Check agreement in number of bands 53 69 if (config%n_bands_lw /= config%aerosol_optics%n_bands_lw) then 54 write(nulerr,'(a)') '*** Error: number of longwave bands does not match aerosol optics look-up table' 70 write(nulerr,'(a,i0,a,i0,a)') '*** Error: number of longwave bands (', & 71 & config%n_bands_lw, ') does not match aerosol optics look-up table (', & 72 & config%aerosol_optics%n_bands_lw, ')' 55 73 call radiation_abort() 56 74 end if … … 64 82 end if 65 83 66 call config%aerosol_optics%print_description(config%i_aerosol_type_map(1:config%n_aerosol_types)) 84 if (config%iverbosesetup >= 1) then 85 call config%aerosol_optics%print_description(config%i_aerosol_type_map(1:config%n_aerosol_types)) 86 end if 67 87 68 88 if (lhook) call dr_hook('radiation_aerosol_optics:setup_aerosol_optics',1,hook_handle) 69 89 70 90 end subroutine setup_aerosol_optics 91 92 93 !--------------------------------------------------------------------- 94 ! Read file containing high spectral resolution optical properties 95 ! and average to the spectral intervals of the current gas-optics 96 ! scheme 97 subroutine setup_general_aerosol_optics(config) 98 99 use parkind1, only : jprb 100 use yomhook, only : lhook, dr_hook 101 use easy_netcdf, only : netcdf_file 102 use radiation_config, only : config_type 103 use radiation_aerosol_optics_data, only : aerosol_optics_type 104 use radiation_spectral_definition, only : SolarReferenceTemperature, & 105 & TerrestrialReferenceTemperature 106 use radiation_io, only : nulout 107 108 type(config_type), intent(inout), target :: config 109 110 ! The NetCDF file containing the aerosol optics data 111 type(netcdf_file) :: file 112 113 ! Wavenumber points in NetCDF file 114 real(jprb), allocatable :: wavenumber(:) ! cm-1 115 116 ! Hydrophilic aerosol properties 117 real(jprb), allocatable :: mass_ext_philic(:,:,:) ! Mass-ext coefficient (m2 kg-1) 118 real(jprb), allocatable :: ssa_philic(:,:,:) ! Single-scattering albedo 119 real(jprb), allocatable :: g_philic(:,:,:) ! Asymmetry factor 120 real(jprb), allocatable :: lidar_ratio_philic(:,:,:) ! Lidar ratio (sr) 121 122 ! Hydrophobic aerosol properties 123 real(jprb), allocatable :: mass_ext_phobic(:,:) ! Mass-ext coefficient (m2 kg-1) 124 real(jprb), allocatable :: ssa_phobic(:,:) ! Single-scattering albedo 125 real(jprb), allocatable :: g_phobic(:,:) ! Asymmetry factor 126 real(jprb), allocatable :: lidar_ratio_phobic(:,:) ! Lidar ratio (sr) 127 128 ! Mapping matrix between optical properties at the wavenumbers in 129 ! the file, and spectral intervals used by the gas-optics scheme 130 real(jprb), allocatable :: mapping(:,:) 131 132 ! Pointer to the aerosol optics coefficients for brevity of access 133 type(aerosol_optics_type), pointer :: ao 134 135 ! Target monochromatic wavenumber for interpolation (cm-1) 136 real(jprb) :: wavenumber_target 137 138 ! Number of spectral points describing aerosol properties in the 139 ! shortwave and longwave 140 integer :: nspecsw, nspeclw 141 142 ! Number of monochromatic wavelengths required 143 integer :: nmono 144 145 integer :: n_type_philic, n_type_phobic, nrh, nwn 146 integer :: jtype, jwl, iwn 147 148 ! Weight of first point in interpolation 149 real(jprb) :: weight1 150 151 real(jprb) :: hook_handle 152 153 if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics',0,hook_handle) 154 155 ao => config%aerosol_optics 156 157 call file%open(trim(config%aerosol_optics_file_name), iverbose=config%iverbosesetup) 158 159 if (.not. file%exists('wavenumber')) then 160 ! Assume we have an old-style aerosol optics file with optical 161 ! properties provided per pre-defined band 162 call file%close() 163 if (config%iverbosesetup >= 2) then 164 write(nulout,'(a)') 'Legacy aerosol optics file: mapping between bands' 165 end if 166 call setup_general_aerosol_optics_legacy(config, trim(config%aerosol_optics_file_name)) 167 return 168 end if 169 170 if (file%exists('mass_ext_hydrophilic')) then 171 ao%use_hydrophilic = .true. 172 else 173 ao%use_hydrophilic = .false. 174 end if 175 176 call file%get('wavenumber', wavenumber) 177 nwn = size(wavenumber) 178 179 ! Read the raw scattering data 180 call file%get('mass_ext_hydrophobic', mass_ext_phobic) 181 call file%get('ssa_hydrophobic', ssa_phobic) 182 call file%get('asymmetry_hydrophobic', g_phobic) 183 call file%get('lidar_ratio_hydrophobic', lidar_ratio_phobic) 184 185 call file%get_global_attribute('description_hydrophobic', & 186 & ao%description_phobic_str) 187 188 if (ao%use_hydrophilic) then 189 call file%get('mass_ext_hydrophilic', mass_ext_philic) 190 call file%get('ssa_hydrophilic', ssa_philic) 191 call file%get('asymmetry_hydrophilic', g_philic) 192 call file%get('lidar_ratio_hydrophilic', lidar_ratio_philic) 193 194 call file%get('relative_humidity1', ao%rh_lower) 195 196 call file%get_global_attribute('description_hydrophilic', & 197 & ao%description_philic_str) 198 end if 199 200 ! Close aerosol scattering file 201 call file%close() 202 203 n_type_phobic = size(mass_ext_phobic, 2) 204 if (ao%use_hydrophilic) then 205 n_type_philic = size(mass_ext_philic, 3) 206 nrh = size(ao%rh_lower) 207 else 208 n_type_philic = 0 209 nrh = 0 210 end if 211 212 if (config%do_cloud_aerosol_per_sw_g_point) then 213 nspecsw = config%gas_optics_sw%spectral_def%ng 214 else 215 nspecsw = config%gas_optics_sw%spectral_def%nband 216 end if 217 218 if (config%do_cloud_aerosol_per_lw_g_point) then 219 nspeclw = config%gas_optics_lw%spectral_def%ng 220 else 221 nspeclw = config%gas_optics_lw%spectral_def%nband 222 end if 223 224 if (allocated(ao%wavelength_mono)) then 225 ! Monochromatic wavelengths also required 226 nmono = size(ao%wavelength_mono) 227 else 228 nmono = 0 229 end if 230 231 call ao%allocate(n_type_phobic, n_type_philic, nrh, nspeclw, nspecsw, nmono) 232 233 if (config%do_sw) then 234 call config%gas_optics_sw%spectral_def%calc_mapping(SolarReferenceTemperature, & 235 & wavenumber, mapping, use_bands=(.not. config%do_cloud_aerosol_per_sw_g_point)) 236 237 ao%mass_ext_sw_phobic = matmul(mapping, mass_ext_phobic) 238 ao%ssa_sw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic) & 239 & / ao%mass_ext_sw_phobic 240 ao%g_sw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic*g_phobic) & 241 & / (ao%mass_ext_sw_phobic*ao%ssa_sw_phobic) 242 243 if (ao%use_hydrophilic) then 244 do jtype = 1,n_type_philic 245 ao%mass_ext_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype)) 246 ao%ssa_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 247 & *ssa_philic(:,:,jtype)) & 248 & / ao%mass_ext_sw_philic(:,:,jtype) 249 ao%g_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 250 & *ssa_philic(:,:,jtype)*g_philic(:,:,jtype)) & 251 & / (ao%mass_ext_sw_philic(:,:,jtype)*ao%ssa_sw_philic(:,:,jtype)) 252 end do 253 end if 254 end if 255 256 if (config%do_lw) then 257 call config%gas_optics_lw%spectral_def%calc_mapping(TerrestrialReferenceTemperature, & 258 & wavenumber, mapping, use_bands=(.not. config%do_cloud_aerosol_per_lw_g_point)) 259 260 ao%mass_ext_lw_phobic = matmul(mapping, mass_ext_phobic) 261 ao%ssa_lw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic) & 262 & / ao%mass_ext_lw_phobic 263 ao%g_lw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic*g_phobic) & 264 & / (ao%mass_ext_lw_phobic*ao%ssa_lw_phobic) 265 266 if (ao%use_hydrophilic) then 267 do jtype = 1,n_type_philic 268 ao%mass_ext_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype)) 269 ao%ssa_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 270 & *ssa_philic(:,:,jtype)) & 271 & / ao%mass_ext_lw_philic(:,:,jtype) 272 ao%g_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 273 & *ssa_philic(:,:,jtype)*g_philic(:,:,jtype)) & 274 & / (ao%mass_ext_lw_philic(:,:,jtype)*ao%ssa_lw_philic(:,:,jtype)) 275 end do 276 end if 277 end if 278 279 if (allocated(ao%wavelength_mono)) then 280 ! Monochromatic wavelengths also required 281 do jwl = 1,nmono 282 ! Wavelength (m) to wavenumber (cm-1) 283 wavenumber_target = 0.01_jprb / ao%wavelength_mono(jwl) 284 ! Find index to first interpolation point, and its weight 285 if (wavenumber_target <= wavenumber(1)) then 286 weight1 = 1.0_jprb 287 iwn = 1 288 else if (wavenumber_target >= wavenumber(nwn)) then 289 iwn = nwn-1 290 weight1 = 0.0_jprb 291 else 292 iwn = 1 293 do while (wavenumber(iwn+1) < wavenumber_target .and. iwn < nwn-1) 294 iwn = iwn + 1 295 end do 296 weight1 = (wavenumber(iwn+1)-wavenumber_target) & 297 & / (wavenumber(iwn+1)-wavenumber(iwn)) 298 end if 299 ! Linear interpolation 300 ao%mass_ext_mono_phobic(jwl,:) = weight1 * mass_ext_phobic(iwn,:) & 301 & + (1.0_jprb - weight1)* mass_ext_phobic(iwn+1,:) 302 ao%ssa_mono_phobic(jwl,:) = weight1 * ssa_phobic(iwn,:) & 303 & + (1.0_jprb - weight1)* ssa_phobic(iwn+1,:) 304 ao%g_mono_phobic(jwl,:) = weight1 * g_phobic(iwn,:) & 305 & + (1.0_jprb - weight1)* g_phobic(iwn+1,:) 306 ao%lidar_ratio_mono_phobic(jwl,:) = weight1 * lidar_ratio_phobic(iwn,:) & 307 & + (1.0_jprb - weight1)* lidar_ratio_phobic(iwn+1,:) 308 if (ao%use_hydrophilic) then 309 ao%mass_ext_mono_philic(jwl,:,:) = weight1 * mass_ext_philic(iwn,:,:) & 310 & + (1.0_jprb - weight1)* mass_ext_philic(iwn+1,:,:) 311 ao%ssa_mono_philic(jwl,:,:) = weight1 * ssa_philic(iwn,:,:) & 312 & + (1.0_jprb - weight1)* ssa_philic(iwn+1,:,:) 313 ao%g_mono_philic(jwl,:,:) = weight1 * g_philic(iwn,:,:) & 314 & + (1.0_jprb - weight1)* g_philic(iwn+1,:,:) 315 ao%lidar_ratio_mono_philic(jwl,:,:) = weight1 * lidar_ratio_philic(iwn,:,:) & 316 & + (1.0_jprb - weight1)* lidar_ratio_philic(iwn+1,:,:) 317 end if 318 end do 319 end if 320 321 ! Deallocate memory local to this routine 322 deallocate(mass_ext_phobic) 323 deallocate(ssa_phobic) 324 deallocate(g_phobic) 325 deallocate(lidar_ratio_phobic) 326 if (ao%use_hydrophilic) then 327 deallocate(mass_ext_philic) 328 deallocate(ssa_philic) 329 deallocate(g_philic) 330 deallocate(lidar_ratio_philic) 331 end if 332 333 if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics',1,hook_handle) 334 335 end subroutine setup_general_aerosol_optics 336 337 !--------------------------------------------------------------------- 338 ! Read LMDZ file containing high spectral resolution optical properties 339 ! and average to the spectral intervals of the current gas-optics 340 ! scheme 341 subroutine setup_general_aerosol_optics_lmdz(config,file_name) 342 343 use parkind1, only : jprb 344 use yomhook, only : lhook, dr_hook 345 ! use easy_netcdf, only : netcdf_file 346 use radiation_config, only : config_type 347 use radiation_aerosol_optics_data, only : aerosol_optics_type 348 use radiation_spectral_definition, only : SolarReferenceTemperature, & 349 & TerrestrialReferenceTemperature 350 use radiation_io, only : nulout 351 use netcdf95, only: nf95_open, nf95_inq_grp_full_ncid, nf95_close, & 352 nf95_inq_dimid, nf95_inq_varid, nf95_inquire_dimension, & 353 nf95_get_var, nf95_gw_var 354 use netcdf, only: nf90_nowrite 355 356 357 type(config_type), intent(inout), target :: config 358 359 ! ! The NetCDF file containing the aerosol optics data 360 ! type(netcdf_file) :: file 361 362 character(len=*), intent(in):: file_name 363 ! NetCDF file containing the aerosol optics data 364 365 ! Wavenumber points in NetCDF file 366 real(jprb), allocatable :: wavenumber(:) ! cm-1 367 368 ! Hydrophilic aerosol properties 369 real(jprb), allocatable :: mass_ext_philic(:,:,:) ! Mass-ext coefficient (m2 kg-1) 370 real(jprb), allocatable :: ssa_philic(:,:,:) ! Single-scattering albedo 371 real(jprb), allocatable :: g_philic(:,:,:) ! Asymmetry factor 372 real(jprb), allocatable :: lidar_ratio_philic(:,:,:) ! Lidar ratio (sr) 373 374 ! Hydrophobic aerosol properties 375 real(jprb), allocatable :: mass_ext_phobic(:,:) ! Mass-ext coefficient (m2 kg-1) 376 real(jprb), allocatable :: ssa_phobic(:,:) ! Single-scattering albedo 377 real(jprb), allocatable :: g_phobic(:,:) ! Asymmetry factor 378 real(jprb), allocatable :: lidar_ratio_phobic(:,:) ! Lidar ratio (sr) 379 380 ! Mapping matrix between optical properties at the wavenumbers in 381 ! the file, and spectral intervals used by the gas-optics scheme 382 real(jprb), allocatable :: mapping(:,:) 383 384 ! Pointer to the aerosol optics coefficients for brevity of access 385 type(aerosol_optics_type), pointer :: ao 386 387 ! Target monochromatic wavenumber for interpolation (cm-1) 388 real(jprb) :: wavenumber_target 389 390 ! Number of spectral points describing aerosol properties in the 391 ! shortwave and longwave 392 integer :: nspecsw, nspeclw 393 394 ! Number of monochromatic wavelengths required 395 integer :: nmono 396 397 integer :: n_type_philic, n_type_phobic, nrh, nwn 398 integer :: jtype, jwl, iwn 399 400 ! Weight of first point in interpolation 401 real(jprb) :: weight1 402 403 real(jprb) :: hook_handle 404 405 ! Local: 406 integer ncid, grpid, dimid, varid 407 408 if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics',0,hook_handle) 409 410 ao => config%aerosol_optics 411 412 ao%use_hydrophilic = .true. 413 ao%use_monochromatic = .true. 414 print*,'file_name= ',file_name 415 call nf95_open(file_name, nf90_nowrite, ncid) 416 call nf95_inq_grp_full_ncid(ncid, "Hydrophilic", grpid) 417 call nf95_inq_dimid(grpid, "hur", dimid) 418 call nf95_inquire_dimension(grpid, dimid, nclen = ao%nrh) 419 ! allocate(ao%rh_lower(ao%nrh)) 420 call nf95_inq_varid(grpid, "hur_bounds", varid) 421 call nf95_get_var(grpid, varid, ao%rh_lower, count_nc = [1, ao%nrh]) 422 423 ! Hydrophilic/LW_bands: 424 call nf95_inq_grp_full_ncid(ncid, "Hydrophilic/LW_bands", grpid) 425 call nf95_inq_varid(grpid, "asymmetry", varid) 426 call nf95_gw_var(grpid, varid, ao%g_lw_philic) 427 call nf95_inq_varid(grpid, "single_scat_alb", varid) 428 call nf95_gw_var(grpid, varid, ao%ssa_lw_philic) 429 call nf95_inq_varid(grpid, "mass_ext", varid) 430 call nf95_gw_var(grpid, varid, ao%mass_ext_lw_philic) 431 432 ! Hydrophilic/SW_bands: 433 call nf95_inq_grp_full_ncid(ncid, "Hydrophilic/SW_bands", grpid) 434 call nf95_inq_varid(grpid, "asymmetry", varid) 435 call nf95_gw_var(grpid, varid, ao%g_sw_philic) 436 ao%g_sw_philic = cshift(ao%g_sw_philic, 1) 437 call nf95_inq_varid(grpid, "single_scat_alb", varid) 438 call nf95_gw_var(grpid, varid, ao%ssa_sw_philic) 439 ao%g_sw_philic = cshift(ao%ssa_sw_philic, 1) 440 call nf95_inq_varid(grpid, "mass_ext", varid) 441 call nf95_gw_var(grpid, varid, ao%mass_ext_sw_philic) 442 ao%g_sw_philic = cshift(ao%mass_ext_sw_philic, 1) 443 444 ! Hydrophilic/Monochromatic: 445 call nf95_inq_grp_full_ncid(ncid, "Hydrophilic/Monochromatic", grpid) 446 call nf95_inq_varid(grpid, "mass_ext", varid) 447 call nf95_gw_var(grpid, varid, ao%mass_ext_mono_philic) 448 449 ! Hydrophobic/LW_bands: 450 call nf95_inq_grp_full_ncid(ncid, "Hydrophobic/LW_bands", grpid) 451 call nf95_inq_varid(grpid, "asymmetry", varid) 452 call nf95_gw_var(grpid, varid, ao%g_lw_phobic) 453 call nf95_inq_varid(grpid, "single_scat_alb", varid) 454 call nf95_gw_var(grpid, varid, ao%ssa_lw_phobic) 455 call nf95_inq_varid(grpid, "mass_ext", varid) 456 call nf95_gw_var(grpid, varid, ao%mass_ext_lw_phobic) 457 458 ! Hydrophobic/SW_bands: 459 call nf95_inq_grp_full_ncid(ncid, "Hydrophobic/SW_bands", grpid) 460 call nf95_inq_varid(grpid, "asymmetry", varid) 461 call nf95_gw_var(grpid, varid, ao%g_sw_phobic) 462 ao%g_sw_phobic = cshift(ao%g_sw_phobic, 1) 463 call nf95_inq_varid(grpid, "single_scat_alb", varid) 464 call nf95_gw_var(grpid, varid, ao%ssa_sw_phobic) 465 ao%g_sw_phobic = cshift(ao%ssa_sw_phobic, 1) 466 call nf95_inq_varid(grpid, "mass_ext", varid) 467 call nf95_gw_var(grpid, varid, ao%mass_ext_sw_phobic) 468 ao%g_sw_phobic = cshift(ao%mass_ext_sw_phobic, 1) 469 ! AI ATTENTION 470 call nf95_inq_varid(grpid, "wavenumber", varid) 471 call nf95_gw_var(grpid, varid, wavenumber) 472 473 ! Hydrophobic/Monochromatic: 474 call nf95_inq_grp_full_ncid(ncid, "Hydrophobic/Monochromatic", grpid) 475 call nf95_inq_varid(grpid, "mass_ext", varid) 476 call nf95_gw_var(grpid, varid, ao%mass_ext_mono_phobic) 477 478 ! call file%get('wavenumber', wavenumber) 479 ! nwn = size(wavenumber) 480 481 ! call file%get_global_attribute('description_hydrophobic', & 482 ! & ao%description_phobic_str) 483 484 485 ! call file%get('relative_humidity1', ao%rh_lower) 486 487 ! call file%get_global_attribute('description_hydrophilic', & 488 ! & ao%description_philic_str) 489 490 ! Close aerosol scattering file 491 ! call file%close() 492 493 call nf95_close(ncid) 494 495 ! Get array sizes 496 ! ao%n_bands_lw = size(ao%mass_ext_lw_phobic, 1) 497 ! ao%n_bands_sw = size(ao%mass_ext_sw_phobic, 1) 498 ! ao%n_mono_wl = size(ao%mass_ext_mono_phobic, 1) 499 ! ao%n_type_phobic = size(ao%mass_ext_lw_phobic, 2) 500 ! ao%n_type_philic = size(ao%mass_ext_lw_philic, 3) 501 502 ! Allocate memory for mapping arrays 503 ! ao%ntype = ao%n_type_phobic + ao%n_type_philic 504 ! allocate(ao%iclass(ao%ntype)) 505 ! allocate(ao%itype(ao%ntype)) 506 507 ! ao%iclass = IAerosolClassUndefined 508 ! ao%itype = 0 509 510 n_type_phobic = size(mass_ext_phobic, 2) 511 if (ao%use_hydrophilic) then 512 n_type_philic = size(mass_ext_philic, 3) 513 nrh = size(ao%rh_lower) 514 else 515 n_type_philic = 0 516 nrh = 0 517 end if 518 519 if (config%do_cloud_aerosol_per_sw_g_point) then 520 nspecsw = config%gas_optics_sw%spectral_def%ng 521 else 522 nspecsw = config%gas_optics_sw%spectral_def%nband 523 end if 524 525 if (config%do_cloud_aerosol_per_lw_g_point) then 526 nspeclw = config%gas_optics_lw%spectral_def%ng 527 else 528 nspeclw = config%gas_optics_lw%spectral_def%nband 529 end if 530 531 if (allocated(ao%wavelength_mono)) then 532 ! Monochromatic wavelengths also required 533 nmono = size(ao%wavelength_mono) 534 else 535 nmono = 0 536 end if 537 538 call ao%allocate(n_type_phobic, n_type_philic, nrh, nspeclw, nspecsw, nmono) 539 540 if (config%do_sw) then 541 call config%gas_optics_sw%spectral_def%calc_mapping(SolarReferenceTemperature, & 542 & wavenumber, mapping, use_bands=(.not. config%do_cloud_aerosol_per_sw_g_point)) 543 544 ao%mass_ext_sw_phobic = matmul(mapping, mass_ext_phobic) 545 ao%ssa_sw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic) & 546 & / ao%mass_ext_sw_phobic 547 ao%g_sw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic*g_phobic) & 548 & / (ao%mass_ext_sw_phobic*ao%ssa_sw_phobic) 549 550 if (ao%use_hydrophilic) then 551 do jtype = 1,n_type_philic 552 ao%mass_ext_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype)) 553 ao%ssa_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 554 & *ssa_philic(:,:,jtype)) & 555 & / ao%mass_ext_sw_philic(:,:,jtype) 556 ao%g_sw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 557 & *ssa_philic(:,:,jtype)*g_philic(:,:,jtype)) & 558 & / (ao%mass_ext_sw_philic(:,:,jtype)*ao%ssa_sw_philic(:,:,jtype)) 559 end do 560 end if 561 end if 562 if (config%do_lw) then 563 call config%gas_optics_lw%spectral_def%calc_mapping(TerrestrialReferenceTemperature, & 564 & wavenumber, mapping, use_bands=(.not. config%do_cloud_aerosol_per_lw_g_point)) 565 566 ao%mass_ext_lw_phobic = matmul(mapping, mass_ext_phobic) 567 ao%ssa_lw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic) & 568 & / ao%mass_ext_lw_phobic 569 ao%g_lw_phobic = matmul(mapping, mass_ext_phobic*ssa_phobic*g_phobic) & 570 & / (ao%mass_ext_lw_phobic*ao%ssa_lw_phobic) 571 572 if (ao%use_hydrophilic) then 573 do jtype = 1,n_type_philic 574 ao%mass_ext_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype)) 575 ao%ssa_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 576 & *ssa_philic(:,:,jtype)) & 577 & / ao%mass_ext_lw_philic(:,:,jtype) 578 ao%g_lw_philic(:,:,jtype) = matmul(mapping, mass_ext_philic(:,:,jtype) & 579 & *ssa_philic(:,:,jtype)*g_philic(:,:,jtype)) & 580 & / (ao%mass_ext_lw_philic(:,:,jtype)*ao%ssa_lw_philic(:,:,jtype)) 581 end do 582 end if 583 end if 584 585 if (allocated(ao%wavelength_mono)) then 586 ! Monochromatic wavelengths also required 587 do jwl = 1,nmono 588 ! Wavelength (m) to wavenumber (cm-1) 589 wavenumber_target = 0.01_jprb / ao%wavelength_mono(jwl) 590 ! Find index to first interpolation point, and its weight 591 if (wavenumber_target <= wavenumber(1)) then 592 weight1 = 1.0_jprb 593 iwn = 1 594 else if (wavenumber_target >= wavenumber(nwn)) then 595 iwn = nwn-1 596 weight1 = 0.0_jprb 597 else 598 iwn = 1 599 do while (wavenumber(iwn+1) < wavenumber_target .and. iwn < nwn-1) 600 iwn = iwn + 1 601 end do 602 weight1 = (wavenumber(iwn+1)-wavenumber_target) & 603 & / (wavenumber(iwn+1)-wavenumber(iwn)) 604 end if 605 ! Linear interpolation 606 ao%mass_ext_mono_phobic(jwl,:) = weight1 * mass_ext_phobic(iwn,:) & 607 & + (1.0_jprb - weight1)* mass_ext_phobic(iwn+1,:) 608 ao%ssa_mono_phobic(jwl,:) = weight1 * ssa_phobic(iwn,:) & 609 & + (1.0_jprb - weight1)* ssa_phobic(iwn+1,:) 610 ao%g_mono_phobic(jwl,:) = weight1 * g_phobic(iwn,:) & 611 & + (1.0_jprb - weight1)* g_phobic(iwn+1,:) 612 ao%lidar_ratio_mono_phobic(jwl,:) = weight1 * lidar_ratio_phobic(iwn,:) & 613 & + (1.0_jprb - weight1)* lidar_ratio_phobic(iwn+1,:) 614 if (ao%use_hydrophilic) then 615 ao%mass_ext_mono_philic(jwl,:,:) = weight1 * mass_ext_philic(iwn,:,:) & 616 & + (1.0_jprb - weight1)* mass_ext_philic(iwn+1,:,:) 617 ao%ssa_mono_philic(jwl,:,:) = weight1 * ssa_philic(iwn,:,:) & 618 & + (1.0_jprb - weight1)* ssa_philic(iwn+1,:,:) 619 ao%g_mono_philic(jwl,:,:) = weight1 * g_philic(iwn,:,:) & 620 & + (1.0_jprb - weight1)* g_philic(iwn+1,:,:) 621 ao%lidar_ratio_mono_philic(jwl,:,:) = weight1 * lidar_ratio_philic(iwn,:,:) & 622 & + (1.0_jprb - weight1)* lidar_ratio_philic(iwn+1,:,:) 623 end if 624 end do 625 end if 626 627 ! Deallocate memory local to this routine 628 deallocate(mass_ext_phobic) 629 deallocate(ssa_phobic) 630 deallocate(g_phobic) 631 deallocate(lidar_ratio_phobic) 632 if (ao%use_hydrophilic) then 633 deallocate(mass_ext_philic) 634 deallocate(ssa_philic) 635 deallocate(g_philic) 636 deallocate(lidar_ratio_philic) 637 end if 638 639 if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics',1,hook_handle) 640 641 end subroutine setup_general_aerosol_optics_lmdz 642 643 644 !--------------------------------------------------------------------- 645 ! Read file containing legacy-style band-wise aerosol optical 646 ! properties and average to the spectral intervals of the current 647 ! gas-optics scheme 648 subroutine setup_general_aerosol_optics_legacy(config, file_name) 649 650 use parkind1, only : jprb 651 use yomhook, only : lhook, dr_hook 652 use easy_netcdf, only : netcdf_file 653 use radiation_config, only : config_type 654 use radiation_aerosol_optics_data, only : aerosol_optics_type 655 use radiation_spectral_definition, only : SolarReferenceTemperature, & 656 & TerrestrialReferenceTemperature 657 658 type(config_type), intent(inout), target :: config 659 660 ! The NetCDF file containing the aerosol optics data 661 character(len=*), intent(in) :: file_name 662 663 ! Mapping matrix between optical properties at the wavenumbers in 664 ! the file, and spectral intervals used by the gas-optics scheme 665 real(jprb), allocatable :: mapping(:,:), mapping_transp(:,:) 666 667 ! Pointer to the aerosol optics coefficients for brevity of access 668 type(aerosol_optics_type), pointer :: ao 669 670 ! Local copy of aerosol optical properties in the spectral 671 ! intervals of the file, which is deallocated when it goes out of 672 ! scope 673 type(aerosol_optics_type) :: ao_legacy 674 675 integer :: jtype 676 677 real(jprb) :: hook_handle 678 679 if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics_legacy',0,hook_handle) 680 ao => config%aerosol_optics 681 682 ! Load file into a local structure 683 call ao_legacy%setup(file_name, iverbose=config%iverbosesetup) 684 685 ! Copy over scalars and coordinate variables 686 call ao%allocate(ao_legacy%n_type_phobic, ao_legacy%n_type_philic, ao_legacy%nrh, & 687 & config%n_bands_lw, config%n_bands_sw, ao_legacy%n_mono_wl) 688 ao%description_phobic_str = ao_legacy%description_phobic_str 689 ao%description_philic_str = ao_legacy%description_philic_str 690 ao%rh_lower = ao_legacy%rh_lower 691 692 ! use_hydrophilic = ao_legacy%use_hydrophilic 693 ! ao%iclass = ao_legacy%iclass 694 ! ao%itype = ao_legacy%itype 695 ! ao%ntype = ao_legacy%ntype 696 ! ao%n_type_phobic = ao_legacy%n_type_phobic 697 ! ao%n_type_philic = ao_legacy%n_type_philic 698 ! ao%n_mono_wl = ao_legacy%n_mono_wl 699 ! ao%use_monochromatic = ao_legacy%use_monochromatic 700 701 if (config%do_sw) then 702 call config%gas_optics_sw%spectral_def%calc_mapping_from_wavenumber_bands(SolarReferenceTemperature, & 703 & ao_legacy%wavenumber1_sw, ao_legacy%wavenumber2_sw, mapping_transp, & 704 & use_bands=(.not. config%do_cloud_aerosol_per_sw_g_point)) 705 if (allocated(mapping)) then 706 deallocate(mapping) 707 end if 708 allocate(mapping(config%n_bands_sw,ao_legacy%n_bands_sw)) 709 mapping = transpose(mapping_transp) 710 ao%mass_ext_sw_phobic = matmul(mapping, ao_legacy%mass_ext_sw_phobic) 711 ao%ssa_sw_phobic = matmul(mapping, ao_legacy%mass_ext_sw_phobic*ao_legacy%ssa_sw_phobic) & 712 & / ao%mass_ext_sw_phobic 713 ao%g_sw_phobic = matmul(mapping, ao_legacy%mass_ext_sw_phobic*ao_legacy%ssa_sw_phobic & 714 & *ao_legacy%g_sw_phobic) & 715 & / (ao%mass_ext_sw_phobic*ao%ssa_sw_phobic) 716 717 if (ao%use_hydrophilic) then 718 do jtype = 1,ao%n_type_philic 719 ao%mass_ext_sw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_sw_philic(:,:,jtype)) 720 ao%ssa_sw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_sw_philic(:,:,jtype) & 721 & *ao_legacy%ssa_sw_philic(:,:,jtype)) & 722 & / ao%mass_ext_sw_philic(:,:,jtype) 723 ao%g_sw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_sw_philic(:,:,jtype) & 724 & *ao_legacy%ssa_sw_philic(:,:,jtype)*ao_legacy%g_sw_philic(:,:,jtype)) & 725 & / (ao%mass_ext_sw_philic(:,:,jtype)*ao%ssa_sw_philic(:,:,jtype)) 726 end do 727 end if 728 end if 729 730 if (config%do_lw) then 731 if (allocated(mapping_transp)) then 732 deallocate(mapping_transp) 733 end if 734 call config%gas_optics_lw%spectral_def%calc_mapping_from_wavenumber_bands(TerrestrialReferenceTemperature, & 735 & ao_legacy%wavenumber1_lw, ao_legacy%wavenumber2_lw, mapping_transp, & 736 & use_bands=(.not. config%do_cloud_aerosol_per_lw_g_point)) 737 if (allocated(mapping)) then 738 deallocate(mapping) 739 end if 740 allocate(mapping(config%n_bands_lw,ao_legacy%n_bands_lw)) 741 mapping = transpose(mapping_transp) 742 ao%mass_ext_lw_phobic = matmul(mapping, ao_legacy%mass_ext_lw_phobic) 743 ao%ssa_lw_phobic = matmul(mapping, ao_legacy%mass_ext_lw_phobic*ao_legacy%ssa_lw_phobic) & 744 & / ao%mass_ext_lw_phobic 745 ao%g_lw_phobic = matmul(mapping, ao_legacy%mass_ext_lw_phobic*ao_legacy%ssa_lw_phobic & 746 & *ao_legacy%g_lw_phobic) & 747 & / (ao%mass_ext_lw_phobic*ao%ssa_lw_phobic) 748 749 if (ao%use_hydrophilic) then 750 do jtype = 1,ao%n_type_philic 751 ao%mass_ext_lw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_lw_philic(:,:,jtype)) 752 ao%ssa_lw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_lw_philic(:,:,jtype) & 753 & *ao_legacy%ssa_lw_philic(:,:,jtype)) & 754 & / ao%mass_ext_lw_philic(:,:,jtype) 755 ao%g_lw_philic(:,:,jtype) = matmul(mapping, ao_legacy%mass_ext_lw_philic(:,:,jtype) & 756 & *ao_legacy%ssa_lw_philic(:,:,jtype)*ao_legacy%g_lw_philic(:,:,jtype)) & 757 & / (ao%mass_ext_lw_philic(:,:,jtype)*ao%ssa_lw_philic(:,:,jtype)) 758 end do 759 end if 760 end if 761 762 if (allocated(ao_legacy%wavelength_mono)) then 763 ao%wavelength_mono = ao_legacy%wavelength_mono 764 ao%mass_ext_mono_phobic = ao_legacy%mass_ext_mono_phobic 765 ao%ssa_mono_phobic = ao_legacy%ssa_mono_phobic 766 ao%g_mono_phobic = ao_legacy%g_mono_phobic 767 ao%lidar_ratio_mono_phobic = ao_legacy%lidar_ratio_mono_phobic 768 if (ao%use_hydrophilic) then 769 ao%mass_ext_mono_philic = ao_legacy%mass_ext_mono_philic 770 ao%ssa_mono_philic = ao_legacy%ssa_mono_philic 771 ao%g_mono_philic = ao_legacy%g_mono_philic 772 ao%lidar_ratio_mono_philic = ao_legacy%lidar_ratio_mono_philic 773 end if 774 end if 775 776 if (lhook) call dr_hook('radiation_aerosol_optics:setup_general_aerosol_optics_legacy',1,hook_handle) 777 778 end subroutine setup_general_aerosol_optics_legacy 71 779 72 780 … … 89 797 & IAerosolClassUndefined, IAerosolClassIgnored, & 90 798 & IAerosolClassHydrophobic, IAerosolClassHydrophilic 91 USE phys_local_var_mod, ONLY: rhcl92 799 93 800 integer, intent(in) :: nlev ! number of model levels … … 134 841 135 842 ! Loop indices for column, level, g point, band and aerosol type 136 integer :: jcol, jlev, jg, jtype 843 integer :: jcol, jlev, jg, jtype, jband 137 844 138 845 ! Range of levels over which aerosols are present … … 141 848 ! Indices to spectral band and relative humidity look-up table 142 849 integer :: iband, irh 850 851 ! Short cut for ao%itype(jtype) 852 integer :: itype 143 853 144 854 ! Pointer to the aerosol optics coefficients for brevity of access … … 182 892 183 893 ! Set variables to zero that may not have been previously 184 g_sw = 0.0_jprb894 g_sw(:,:,istartcol:iendcol) = 0.0_jprb 185 895 if (config%do_lw_aerosol_scattering) then 186 ssa_lw = 0.0_jprb 187 g_lw = 0.0_jprb 188 end if 189 190 !AI juin 2022 191 !call gas%get(IH2O, IMassMixingRatio, h2o_mmr, istartcol=istartcol) 896 ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb 897 g_lw(:,:,istartcol:iendcol) = 0.0_jprb 898 end if 899 900 call gas%get(IH2O, IMassMixingRatio, h2o_mmr, istartcol=istartcol) 192 901 193 902 ! Loop over position … … 197 906 ! saturation and the index to the relative-humidity index of 198 907 ! hydrophilic-aerosol data 199 ! AI juin 2022 200 ! rh = h2o_mmr(jcol,jlev) / thermodynamics%h2o_sat_liq(jcol,jlev) 201 ! irh = ao%calc_rh_index(rh) 202 irh = ao%calc_rh_index(rhcl(jcol,jlev)) 203 ! print*,'irh=',irh 908 rh = h2o_mmr(jcol,jlev) / thermodynamics%h2o_sat_liq(jcol,jlev) 909 irh = ao%calc_rh_index(rh) 204 910 205 911 factor = ( thermodynamics%pressure_hl(jcol,jlev+1) & … … 216 922 217 923 do jtype = 1,config%n_aerosol_types 924 925 itype = ao%itype(jtype) 926 218 927 ! Add the optical depth, scattering optical depth and 219 928 ! scattering optical depth-weighted asymmetry factor for … … 222 931 ! dimension being spectral band. 223 932 if (ao%iclass(jtype) == IAerosolClassHydrophobic) then 224 local_od_sw = factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 225 & * ao%mass_ext_sw_phobic(:,ao%itype(jtype)) 226 od_sw_aerosol = od_sw_aerosol + local_od_sw 227 scat_sw_aerosol = scat_sw_aerosol & 228 & + local_od_sw * ao%ssa_sw_phobic(:,ao%itype(jtype)) 229 scat_g_sw_aerosol = scat_g_sw_aerosol & 230 & + local_od_sw * ao%ssa_sw_phobic(:,ao%itype(jtype)) & 231 & * ao%g_sw_phobic(:,ao%itype(jtype)) 933 do jband = 1,config%n_bands_sw 934 local_od_sw(jband) = factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 935 & * ao%mass_ext_sw_phobic(jband,itype) 936 od_sw_aerosol(jband) = od_sw_aerosol(jband) + local_od_sw(jband) 937 scat_sw_aerosol(jband) = scat_sw_aerosol(jband) & 938 & + local_od_sw(jband) * ao%ssa_sw_phobic(jband,itype) 939 scat_g_sw_aerosol(jband) = scat_g_sw_aerosol(jband) & 940 & + local_od_sw(jband) * ao%ssa_sw_phobic(jband,itype) & 941 & * ao%g_sw_phobic(jband,itype) 942 end do 232 943 if (config%do_lw_aerosol_scattering) then 233 944 local_od_lw = factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 234 & * ao%mass_ext_lw_phobic(:, ao%itype(jtype))945 & * ao%mass_ext_lw_phobic(:,itype) 235 946 od_lw_aerosol = od_lw_aerosol + local_od_lw 236 947 scat_lw_aerosol = scat_lw_aerosol & 237 & + local_od_lw * ao%ssa_lw_phobic(:, ao%itype(jtype))948 & + local_od_lw * ao%ssa_lw_phobic(:,itype) 238 949 scat_g_lw_aerosol = scat_g_lw_aerosol & 239 & + local_od_lw * ao%ssa_lw_phobic(:, ao%itype(jtype)) &240 & * ao%g_lw_phobic(:, ao%itype(jtype))950 & + local_od_lw * ao%ssa_lw_phobic(:,itype) & 951 & * ao%g_lw_phobic(:,itype) 241 952 else 242 953 ! If aerosol longwave scattering is not included then we … … 245 956 od_lw_aerosol = od_lw_aerosol & 246 957 & + factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 247 & * ao%mass_ext_lw_phobic(:, ao%itype(jtype)) &248 & * (1.0_jprb - ao%ssa_lw_phobic(:, ao%itype(jtype)))958 & * ao%mass_ext_lw_phobic(:,itype) & 959 & * (1.0_jprb - ao%ssa_lw_phobic(:,itype)) 249 960 end if 250 961 else if (ao%iclass(jtype) == IAerosolClassHydrophilic) then 251 962 ! Hydrophilic aerosols require the look-up tables to 252 963 ! be indexed with irh 253 local_od_sw = factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 254 & * ao%mass_ext_sw_philic(:,irh,ao%itype(jtype)) 255 od_sw_aerosol = od_sw_aerosol + local_od_sw 256 scat_sw_aerosol = scat_sw_aerosol & 257 & + local_od_sw * ao%ssa_sw_philic(:,irh,ao%itype(jtype)) 258 scat_g_sw_aerosol = scat_g_sw_aerosol & 259 & + local_od_sw * ao%ssa_sw_philic(:,irh,ao%itype(jtype)) & 260 & * ao%g_sw_philic(:,irh,ao%itype(jtype)) 964 do jband = 1,config%n_bands_sw 965 local_od_sw(jband) = factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 966 & * ao%mass_ext_sw_philic(jband,irh,itype) 967 od_sw_aerosol(jband) = od_sw_aerosol(jband) + local_od_sw(jband) 968 scat_sw_aerosol(jband) = scat_sw_aerosol(jband) & 969 & + local_od_sw(jband) * ao%ssa_sw_philic(jband,irh,itype) 970 scat_g_sw_aerosol(jband) = scat_g_sw_aerosol(jband) & 971 & + local_od_sw(jband) * ao%ssa_sw_philic(jband,irh,itype) & 972 & * ao%g_sw_philic(jband,irh,itype) 973 end do 261 974 if (config%do_lw_aerosol_scattering) then 262 975 local_od_lw = factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 263 & * ao%mass_ext_lw_philic(:,irh, ao%itype(jtype))976 & * ao%mass_ext_lw_philic(:,irh,itype) 264 977 od_lw_aerosol = od_lw_aerosol + local_od_lw 265 978 scat_lw_aerosol = scat_lw_aerosol & 266 & + local_od_lw * ao%ssa_lw_philic(:,irh, ao%itype(jtype))979 & + local_od_lw * ao%ssa_lw_philic(:,irh,itype) 267 980 scat_g_lw_aerosol = scat_g_lw_aerosol & 268 & + local_od_lw * ao%ssa_lw_philic(:,irh, ao%itype(jtype)) &269 & * ao%g_lw_philic(:,irh, ao%itype(jtype))981 & + local_od_lw * ao%ssa_lw_philic(:,irh,itype) & 982 & * ao%g_lw_philic(:,irh,itype) 270 983 else 271 984 ! If aerosol longwave scattering is not included then we … … 274 987 od_lw_aerosol = od_lw_aerosol & 275 988 & + factor * aerosol%mixing_ratio(jcol,jlev,jtype) & 276 & * ao%mass_ext_lw_philic(:,irh, ao%itype(jtype)) &277 & * (1.0_jprb - ao%ssa_lw_philic(:,irh, ao%itype(jtype)))989 & * ao%mass_ext_lw_philic(:,irh,itype) & 990 & * (1.0_jprb - ao%ssa_lw_philic(:,irh,itype)) 278 991 end if 279 992 end if … … 295 1008 ! properties (noting that any gas scattering will have an 296 1009 ! asymmetry factor of zero) 297 if (od_sw_aerosol(1) > 0.0_jprb) then298 do jg = 1,config%n_g_sw299 iband = config%i_band_from_reordered_g_sw(jg)300 local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband)1010 do jg = 1,config%n_g_sw 1011 iband = config%i_band_from_reordered_g_sw(jg) 1012 local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband) 1013 if (local_od > 0.0_jprb .and. od_sw_aerosol(iband) > 0.0_jprb) then 301 1014 local_scat = ssa_sw(jg,jlev,jcol) * od_sw(jg,jlev,jcol) & 302 1015 & + scat_sw_aerosol(iband) … … 304 1017 ! simply weights the aerosol asymmetry by the scattering 305 1018 ! optical depth 306 g_sw(jg,jlev,jcol) = scat_g_sw_aerosol(iband) / local_scat 1019 if (local_scat > 0.0_jprb) then 1020 g_sw(jg,jlev,jcol) = scat_g_sw_aerosol(iband) / local_scat 1021 end if 307 1022 ssa_sw(jg,jlev,jcol) = local_scat / local_od 308 1023 od_sw (jg,jlev,jcol) = local_od 309 end do310 end if1024 end if 1025 end do 311 1026 312 1027 ! Combine aerosol longwave scattering properties with gas … … 320 1035 do jg = 1,config%n_g_lw 321 1036 iband = config%i_band_from_reordered_g_lw(jg) 322 if (od_lw_aerosol(iband) > 0.0_jprb) then 1037 local_od = od_lw(jg,jlev,jcol) + od_lw_aerosol(iband) 1038 if (local_od > 0.0_jprb .and. od_lw_aerosol(iband) > 0.0_jprb) then 323 1039 ! All scattering is due to aerosols, therefore the 324 1040 ! asymmetry factor is equal to the value for aerosols … … 326 1042 g_lw(jg,jlev,jcol) = scat_g_lw_aerosol(iband) & 327 1043 & / scat_lw_aerosol(iband) 328 else329 g_lw(jg,jlev,jcol) = 0.0_jprb330 1044 end if 331 local_od = od_lw(jg,jlev,jcol) + od_lw_aerosol(iband)332 1045 ssa_lw(jg,jlev,jcol) = scat_lw_aerosol(iband) / local_od 333 1046 od_lw (jg,jlev,jcol) = local_od … … 390 1103 ! a point in space for each spectral band of the shortwave and 391 1104 ! longwave spectrum 392 real(jprb), dimension(config%n_bands_sw ) &1105 real(jprb), dimension(config%n_bands_sw,nlev) & 393 1106 & :: od_sw_aerosol, scat_sw_aerosol, scat_g_sw_aerosol 394 real(jprb), dimension(config%n_bands_lw ) :: od_lw_aerosol395 real(jprb), dimension(config%n_bands_lw_if_scattering ) &1107 real(jprb), dimension(config%n_bands_lw,nlev) :: od_lw_aerosol 1108 real(jprb), dimension(config%n_bands_lw_if_scattering,nlev) & 396 1109 & :: scat_lw_aerosol, scat_g_lw_aerosol 397 1110 398 1111 ! Loop indices for column, level, g point and band 399 integer :: jcol, jlev, jg 1112 integer :: jcol, jlev, jg, jb 400 1113 401 1114 ! Range of levels over which aerosols are present … … 422 1135 423 1136 ! Set variables to zero that may not have been previously 424 g_sw = 0.0_jprb1137 g_sw(:,:,istartcol:iendcol) = 0.0_jprb 425 1138 426 1139 ! Loop over position 427 1140 do jcol = istartcol,iendcol 1141 ! Added for DWD (2020) 1142 !NEC$ forced_collapse 428 1143 do jlev = istartlev,iendlev 429 od_sw_aerosol = aerosol%od_sw(:,jlev,jcol) 430 scat_sw_aerosol = aerosol%ssa_sw(:,jlev,jcol) * od_sw_aerosol 431 scat_g_sw_aerosol = aerosol%g_sw(:,jlev,jcol) * scat_sw_aerosol 432 433 if (.not. config%do_sw_delta_scaling_with_gases) then 434 ! Delta-Eddington scaling on aerosol only. Note that if 435 ! do_sw_delta_scaling_with_gases==.true. then the delta 436 ! scaling is done to the cloud-aerosol-gas mixture inside 437 ! the solver 438 call delta_eddington_extensive(od_sw_aerosol, scat_sw_aerosol, & 439 & scat_g_sw_aerosol) 440 end if 441 442 ! Combine aerosol shortwave scattering properties with gas 443 ! properties (noting that any gas scattering will have an 444 ! asymmetry factor of zero) 445 if (od_sw_aerosol(1) > 0.0_jprb) then 1144 do jb = 1,config%n_bands_sw 1145 od_sw_aerosol(jb,jlev) = aerosol%od_sw(jb,jlev,jcol) 1146 scat_sw_aerosol(jb,jlev) = aerosol%ssa_sw(jb,jlev,jcol) * od_sw_aerosol(jb,jlev) 1147 scat_g_sw_aerosol(jb,jlev) = aerosol%g_sw(jb,jlev,jcol) * scat_sw_aerosol(jb,jlev) 1148 1149 if (.not. config%do_sw_delta_scaling_with_gases) then 1150 ! Delta-Eddington scaling on aerosol only. Note that if 1151 ! do_sw_delta_scaling_with_gases==.true. then the delta 1152 ! scaling is done to the cloud-aerosol-gas mixture 1153 ! inside the solver 1154 call delta_eddington_extensive(od_sw_aerosol(jb,jlev), scat_sw_aerosol(jb,jlev), & 1155 & scat_g_sw_aerosol(jb,jlev)) 1156 end if 1157 end do 1158 end do 1159 ! Combine aerosol shortwave scattering properties with gas 1160 ! properties (noting that any gas scattering will have an 1161 ! asymmetry factor of zero) 1162 do jlev = istartlev,iendlev 1163 if (od_sw_aerosol(1,jlev) > 0.0_jprb) then 446 1164 do jg = 1,config%n_g_sw 447 1165 iband = config%i_band_from_reordered_g_sw(jg) 448 local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband )1166 local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband,jlev) 449 1167 local_scat = ssa_sw(jg,jlev,jcol) * od_sw(jg,jlev,jcol) & 450 & + scat_sw_aerosol(iband )1168 & + scat_sw_aerosol(iband,jlev) 451 1169 ! Note that asymmetry_sw of gases is zero so the following 452 1170 ! simply weights the aerosol asymmetry by the scattering 453 1171 ! optical depth 454 g_sw(jg,jlev,jcol) = scat_g_sw_aerosol(iband) / local_scat 1172 g_sw(jg,jlev,jcol) = scat_g_sw_aerosol(iband,jlev) / local_scat 1173 local_od = od_sw(jg,jlev,jcol) + od_sw_aerosol(iband,jlev) 455 1174 ssa_sw(jg,jlev,jcol) = local_scat / local_od 456 1175 od_sw (jg,jlev,jcol) = local_od … … 475 1194 476 1195 if (config%do_lw_aerosol_scattering) then 477 ssa_lw = 0.0_jprb478 g_lw = 0.0_jprb1196 ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb 1197 g_lw(:,:,istartcol:iendcol) = 0.0_jprb 479 1198 480 1199 ! Loop over position 481 1200 do jcol = istartcol,iendcol 1201 ! Added for DWD (2020) 1202 !NEC$ forced_collapse 482 1203 do jlev = istartlev,iendlev 483 od_lw_aerosol = aerosol%od_lw(:,jlev,jcol) 484 scat_lw_aerosol = aerosol%ssa_lw(:,jlev,jcol) * od_lw_aerosol 485 scat_g_lw_aerosol = aerosol%g_lw(:,jlev,jcol) * scat_lw_aerosol 1204 do jb = 1,config%n_bands_lw 1205 od_lw_aerosol(jb,jlev) = aerosol%od_lw(jb,jlev,jcol) 1206 scat_lw_aerosol(jb,jlev) = aerosol%ssa_lw(jb,jlev,jcol) * od_lw_aerosol(jb,jlev) 1207 scat_g_lw_aerosol(jb,jlev) = aerosol%g_lw(jb,jlev,jcol) * scat_lw_aerosol(jb,jlev) 486 1208 487 call delta_eddington_extensive(od_lw_aerosol, scat_lw_aerosol, & 488 & scat_g_lw_aerosol) 489 1209 call delta_eddington_extensive(od_lw_aerosol(jb,jlev), scat_lw_aerosol(jb,jlev), & 1210 & scat_g_lw_aerosol(jb,jlev)) 1211 end do 1212 end do 1213 do jlev = istartlev,iendlev 490 1214 do jg = 1,config%n_g_lw 491 1215 iband = config%i_band_from_reordered_g_lw(jg) 492 if (od_lw_aerosol(iband ) > 0.0_jprb) then1216 if (od_lw_aerosol(iband,jlev) > 0.0_jprb) then 493 1217 ! All scattering is due to aerosols, therefore the 494 1218 ! asymmetry factor is equal to the value for aerosols 495 if (scat_lw_aerosol(iband) > 0.0_jprb) then 496 g_lw(jg,jlev,jcol) = scat_g_lw_aerosol(iband) & 497 & / scat_lw_aerosol(iband) 498 else 499 g_lw(jg,jlev,jcol) = 0.0_jprb 1219 if (scat_lw_aerosol(iband,jlev) > 0.0_jprb) then 1220 g_lw(jg,jlev,jcol) = scat_g_lw_aerosol(iband,jlev) & 1221 & / scat_lw_aerosol(iband,jlev) 500 1222 end if 501 local_od = od_lw(jg,jlev,jcol) + od_lw_aerosol(iband )502 ssa_lw(jg,jlev,jcol) = scat_lw_aerosol(iband ) / local_od1223 local_od = od_lw(jg,jlev,jcol) + od_lw_aerosol(iband,jlev) 1224 ssa_lw(jg,jlev,jcol) = scat_lw_aerosol(iband,jlev) / local_od 503 1225 od_lw (jg,jlev,jcol) = local_od 504 1226 end if … … 511 1233 ! Loop over position 512 1234 do jcol = istartcol,iendcol 1235 ! Added for DWD (2020) 1236 !NEC$ forced_collapse 513 1237 do jlev = istartlev,iendlev 514 1238 ! If aerosol longwave scattering is not included then we 515 1239 ! weight the optical depth by the single scattering 516 1240 ! co-albedo 517 od_lw_aerosol = aerosol%od_lw(:,jlev,jcol) & 518 & * (1.0_jprb - aerosol%ssa_lw(:,jlev,jcol)) 1241 do jb = 1, config%n_bands_lw 1242 od_lw_aerosol(jb,jlev) = aerosol%od_lw(jb,jlev,jcol) & 1243 & * (1.0_jprb - aerosol%ssa_lw(jb,jlev,jcol)) 1244 end do 1245 end do 1246 do jlev = istartlev,iendlev 519 1247 do jg = 1,config%n_g_lw 520 1248 od_lw(jg,jlev,jcol) = od_lw(jg,jlev,jcol) & 521 & + od_lw_aerosol(config%i_band_from_reordered_g_lw(jg) )1249 & + od_lw_aerosol(config%i_band_from_reordered_g_lw(jg),jlev) 522 1250 end do 523 1251 end do … … 536 1264 ! Sometimes it is useful to specify aerosol in terms of its optical 537 1265 ! depth at a particular wavelength. This function returns the dry 538 ! shortwave mass-extinction coefficient, i.e. the extinction cross539 ! section per unit mass, for aerosol of type "itype" at shortwave540 ! band "iband". For hydrophilic types, the value at the first541 ! relativehumidity bin is taken.542 function dry_aerosol_ sw_mass_extinction(config, itype, iband)1266 ! mass-extinction coefficient, i.e. the extinction cross section per 1267 ! unit mass, for aerosol of type "itype" at the specified wavelength 1268 ! (m). For hydrophilic types, the value at the first relative 1269 ! humidity bin is taken. 1270 function dry_aerosol_mass_extinction(config, itype, wavelength) 543 1271 544 1272 use parkind1, only : jprb 1273 use radiation_io, only : nulerr, radiation_abort 545 1274 use radiation_config, only : config_type 546 1275 use radiation_aerosol_optics_data, only : aerosol_optics_type, & … … 550 1279 type(config_type), intent(in), target :: config 551 1280 552 ! Aerosol type and shortwave band as indices to the array 553 integer, intent(in) :: itype, iband 1281 ! Aerosol type 1282 integer, intent(in) :: itype 1283 1284 ! Wavelength (m) 1285 real(jprb), intent(in) :: wavelength 554 1286 555 real(jprb) dry_aerosol_sw_mass_extinction 1287 real(jprb) :: dry_aerosol_mass_extinction 1288 1289 ! Index to the monochromatic wavelength requested 1290 integer :: imono 556 1291 557 1292 ! Pointer to the aerosol optics coefficients for brevity of access … … 560 1295 ao => config%aerosol_optics 561 1296 1297 imono = minloc(abs(wavelength - ao%wavelength_mono), 1) 1298 1299 if (abs(wavelength - ao%wavelength_mono(imono))/wavelength > 0.01_jprb) then 1300 write(nulerr,'(a,e8.4,a)') '*** Error: requested wavelength ', & 1301 & wavelength, ' not within 1% of stored wavelengths' 1302 call radiation_abort() 1303 end if 1304 562 1305 if (ao%iclass(itype) == IAerosolClassHydrophobic) then 563 dry_aerosol_ sw_mass_extinction = ao%mass_ext_sw_phobic(iband,ao%itype(itype))1306 dry_aerosol_mass_extinction = ao%mass_ext_mono_phobic(imono,ao%itype(itype)) 564 1307 else if (ao%iclass(itype) == IAerosolClassHydrophilic) then 565 1308 ! Take the value at the first relative-humidity bin for the 566 1309 ! "dry" aerosol value 567 dry_aerosol_ sw_mass_extinction = ao%mass_ext_sw_philic(iband,1,ao%itype(itype))1310 dry_aerosol_mass_extinction = ao%mass_ext_mono_philic(imono,1,ao%itype(itype)) 568 1311 else 569 dry_aerosol_ sw_mass_extinction = 0.0_jprb570 end if 571 572 end function dry_aerosol_ sw_mass_extinction1312 dry_aerosol_mass_extinction = 0.0_jprb 1313 end if 1314 1315 end function dry_aerosol_mass_extinction 573 1316 574 1317 575 1318 !--------------------------------------------------------------------- 576 ! Compute aerosol extinction coefficient at a particular shortwave 577 ! band and a single height - this is useful for visibility 578 ! diagnostics 579 subroutine aerosol_sw_extinction(ncol,istartcol,iendcol, & 580 & config, iband, mixing_ratio, relative_humidity, extinction) 1319 ! Compute aerosol extinction coefficient at a particular wavelength 1320 ! and a single height - this is useful for visibility diagnostics 1321 subroutine aerosol_extinction(ncol,istartcol,iendcol, & 1322 & config, wavelength, mixing_ratio, relative_humidity, extinction) 581 1323 582 1324 use parkind1, only : jprb … … 591 1333 integer, intent(in) :: istartcol, iendcol ! range of columns to process 592 1334 type(config_type), intent(in), target :: config 593 integer, intent(in) :: iband ! Index of required spectral band1335 real(jprb), intent(in) :: wavelength ! Requested wavelength (m) 594 1336 real(jprb), intent(in) :: mixing_ratio(ncol,config%n_aerosol_types) 595 1337 real(jprb), intent(in) :: relative_humidity(ncol) … … 598 1340 ! Local aerosol extinction 599 1341 real(jprb) :: ext 1342 1343 ! Index to the monochromatic wavelength requested 1344 integer :: imono 600 1345 601 1346 ! Pointer to the aerosol optics coefficients for brevity of access … … 610 1355 real(jprb) :: hook_handle 611 1356 612 if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_ sw_extinction',0,hook_handle)1357 if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_extinction',0,hook_handle) 613 1358 614 1359 do jtype = 1,config%n_aerosol_types … … 620 1365 621 1366 ao => config%aerosol_optics 1367 1368 imono = minloc(abs(wavelength - ao%wavelength_mono), 1) 1369 1370 if (abs(wavelength - ao%wavelength_mono(imono))/wavelength > 0.01_jprb) then 1371 write(nulerr,'(a,e8.4,a)') '*** Error: requested wavelength ', & 1372 & wavelength, ' not within 1% of stored wavelengths' 1373 call radiation_abort() 1374 end if 622 1375 623 1376 ! Loop over position … … 630 1383 if (ao%iclass(jtype) == IAerosolClassHydrophobic) then 631 1384 ext = ext + mixing_ratio(jcol,jtype) & 632 & * ao%mass_ext_ sw_phobic(iband,ao%itype(jtype))1385 & * ao%mass_ext_mono_phobic(imono,ao%itype(jtype)) 633 1386 else if (ao%iclass(jtype) == IAerosolClassHydrophilic) then 634 1387 ext = ext + mixing_ratio(jcol,jtype) & 635 & * ao%mass_ext_ sw_philic(iband,irh,ao%itype(jtype))1388 & * ao%mass_ext_mono_philic(imono,irh,ao%itype(jtype)) 636 1389 end if 637 1390 end do … … 640 1393 end do 641 1394 642 if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_ sw_extinction',1,hook_handle)643 644 end subroutine aerosol_ sw_extinction1395 if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_extinction',1,hook_handle) 1396 1397 end subroutine aerosol_extinction 645 1398 646 1399 end module radiation_aerosol_optics -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_aerosol_optics_data.F90
r3908 r4444 57 57 integer, allocatable, dimension(:) :: itype 58 58 59 ! Wavenumber (cm-1) upper and lower bounds of each spectral 60 ! interval, which if used in the RRTMG gas optics scheme should 61 ! match its band bounds 62 real(jprb), allocatable, dimension(:) :: wavenumber1_sw, wavenumber2_sw 63 real(jprb), allocatable, dimension(:) :: wavenumber1_lw, wavenumber2_lw 64 59 65 ! Scattering properties are provided separately in the shortwave 60 66 ! and longwave for hydrophobic and hydrophilic aerosols. … … 64 70 & ssa_sw_phobic, & ! Single scattering albedo 65 71 & g_sw_phobic, & ! Asymmetry factor 72 ! & ssa_g_sw_phobic, & ! ssa*g 66 73 & mass_ext_lw_phobic, & ! Mass-extinction coefficient (m2 kg-1) 74 ! & mass_abs_lw_phobic, & ! Mass-absorption coefficient (m2 kg-1) 67 75 & ssa_lw_phobic, & ! Single scattering albedo 68 76 & g_lw_phobic ! Asymmetry factor 69 77 70 ! Hydrophilic aerosols are dimensioned (nband, nrh,n_type_philic):78 ! Hydrophilic aerosols are dimensioned (nband,nrh,n_type_philic): 71 79 real(jprb), allocatable, dimension(:,:,:) :: & 72 80 & mass_ext_sw_philic, & ! Mass-extinction coefficient (m2 kg-1) 73 81 & ssa_sw_philic, & ! Single scattering albedo 74 82 & g_sw_philic, & ! Asymmetry factor 83 ! & ssa_g_sw_philic, & ! ssa*g 75 84 & mass_ext_lw_philic, & ! Mass-extinction coefficient (m2 kg-1) 85 ! & mass_abs_lw_philic, & ! Mass-absorption coefficient (m2 kg-1) 76 86 & ssa_lw_philic, & ! Single scattering albedo 77 87 & g_lw_philic ! Asymmetry factor 78 88 79 ! Scattering properties at selected wavelengths 80 ! (n_mono_wl,n_type_phobic/philic) 89 ! Wavelengths at which monochromatic properties are stored, 90 ! dimensioned (n_mono_wl), units metres 91 real(jprb), allocatable :: wavelength_mono(:) 92 93 ! Scattering properties at selected monochromatic wavelengths 94 ! (n_mono_wl,n_type_phobic) 81 95 real(jprb), allocatable, dimension(:,:) :: & 82 96 & mass_ext_mono_phobic, & ! Mass-extinction coefficient (m2 kg-1) … … 84 98 & g_mono_phobic, & ! Asymmetry factor 85 99 & lidar_ratio_mono_phobic ! Lidar Ratio 100 ! ...hydrophilic aerosols dimensioned (n_mono_wl,nrh,n_type_philic): 86 101 real(jprb), allocatable, dimension(:,:,:) :: & 87 102 & mass_ext_mono_philic, & ! Mass-extinction coefficient (m2 kg-1) … … 104 119 ! The number of hydrophobic and hydrophilic types read from the 105 120 ! aerosol optics file 106 integer :: n_type_phobic, n_type_philic 121 integer :: n_type_phobic = 0 122 integer :: n_type_philic = 0 107 123 108 124 ! Number of relative humidity bins 109 integer :: nrh 125 integer :: nrh = 0 110 126 111 127 ! Number of longwave and shortwave bands of the data in the file, … … 121 137 contains 122 138 procedure :: setup => setup_aerosol_optics 139 procedure :: save => save_aerosol_optics 140 procedure :: allocate 141 procedure :: initialize_types 123 142 procedure :: set_hydrophobic_type 124 143 procedure :: set_hydrophilic_type … … 135 154 !--------------------------------------------------------------------- 136 155 ! Setup aerosol optics coefficients by reading them from a file 137 subroutine setup_aerosol_optics(this, file_name, ntype,iverbose)156 subroutine setup_aerosol_optics(this, file_name, iverbose) 138 157 139 158 use yomhook, only : lhook, dr_hook … … 143 162 class(aerosol_optics_type), intent(inout) :: this 144 163 character(len=*), intent(in) :: file_name 145 integer, intent(in) :: ntype146 164 integer, intent(in), optional :: iverbose 147 165 148 166 ! The NetCDF file containing the aerosol optics data 149 167 type(netcdf_file) :: file 168 169 real(jprb), allocatable :: wavelength_tmp(:) 150 170 integer :: iverb 171 151 172 real(jprb) :: hook_handle 152 173 … … 168 189 this%use_hydrophilic = .false. 169 190 end if 191 192 ! Read the wavenumber bounds 193 call file%get('wavenumber1_sw', this%wavenumber1_sw) 194 call file%get('wavenumber2_sw', this%wavenumber2_sw) 195 call file%get('wavenumber1_lw', this%wavenumber1_lw) 196 call file%get('wavenumber2_lw', this%wavenumber2_lw) 170 197 171 198 ! Read the raw scattering data … … 180 207 & this%description_phobic_str) 181 208 209 ! Precompute ssa*g for the shortwave and mass-absorption for the 210 ! longwave - TBD FIX 211 !allocate(this%ssa_g_sw_phobic(... 212 182 213 if (this%use_hydrophilic) then 183 214 call file%get('mass_ext_sw_hydrophilic', this%mass_ext_sw_philic) … … 194 225 end if 195 226 196 ! Read the raw scattering data at selected wavelengths if197 ! available in the input file227 ! Read the monochromatic scattering data at selected wavelengths 228 ! if available in the input file 198 229 if (file%exists('mass_ext_mono_hydrophobic')) then 199 230 this%use_monochromatic = .true. 231 232 if (allocated(this%wavelength_mono)) then 233 ! User has provided required monochromatic wavelengths, which 234 ! must match those in the file (in the more recent "general" 235 ! aerosol optics, interpolation provides optical properties at 236 ! the requested wavelengths) 237 call file%get('wavelength_mono', wavelength_tmp) 238 if (size(wavelength_tmp) /= size(this%wavelength_mono)) then 239 write(nulerr,'(a,i0,a,i0,a)') '*** Error: ', size(this%wavelength_mono), & 240 & ' monochromatic wavelengths requested but ', & 241 & size(wavelength_tmp), ' in file' 242 call radiation_abort('Radiation configuration error') 243 end if 244 if (any(abs(this%wavelength_mono-wavelength_tmp) & 245 & / this%wavelength_mono > 0.01_jprb)) then 246 write(nulerr,'(a,a)') '*** Error: requested monochromatic wavelengths', & 247 & 'must all be within 1% of values in file' 248 call radiation_abort('Radiation configuration error') 249 end if 250 else 251 ! User has not provided required wavelengths, so we save the 252 ! monochromatic wavelengths in the file 253 call file%get('wavelength_mono', this%wavelength_mono) 254 end if 255 200 256 call file%get('mass_ext_mono_hydrophobic', this%mass_ext_mono_phobic) 201 257 call file%get('ssa_mono_hydrophobic', this%ssa_mono_phobic) … … 233 289 write(nulerr,'(a,a)') '*** Error: mass extinction for hydrophilic and hydrophobic ', & 234 290 & 'aerosol have different numbers of longwave bands' 235 call radiation_abort( )291 call radiation_abort('Radiation configuration error') 236 292 end if 237 293 if (size(this%mass_ext_sw_philic,1) /= this%n_bands_sw) then 238 294 write(nulerr,'(a,a)') '*** Error: mass extinction for hydrophilic and hydrophobic ', & 239 295 & 'aerosol have different numbers of shortwave bands' 240 call radiation_abort( )296 call radiation_abort('Radiation configuration error') 241 297 end if 242 298 if (size(this%rh_lower) /= this%nrh) then 243 299 write(nulerr,'(a)') '*** Error: size(relative_humidity1) /= size(mass_ext_sw_hydrophilic,2)' 244 call radiation_abort( )300 call radiation_abort('Radiation configuration error') 245 301 end if 246 302 … … 250 306 end if 251 307 308 if (lhook) call dr_hook('radiation_aerosol_optics_data:setup',1,hook_handle) 309 310 end subroutine setup_aerosol_optics 311 312 313 !--------------------------------------------------------------------- 314 ! Initialize the arrays describing the user's aerosol types 315 subroutine initialize_types(this, ntype) 316 317 class(aerosol_optics_type), intent(inout) :: this 318 integer, intent(in) :: ntype 319 252 320 ! Allocate memory for mapping arrays 253 321 this%ntype = ntype … … 258 326 this%itype = 0 259 327 260 if (lhook) call dr_hook('radiation_aerosol_optics_data:setup',1,hook_handle) 261 262 end subroutine setup_aerosol_optics 328 end subroutine initialize_types 329 330 !--------------------------------------------------------------------- 331 ! Allocate arrays for aerosol optics data type 332 subroutine allocate(this, n_type_phobic, n_type_philic, nrh, & 333 & n_bands_lw, n_bands_sw, n_mono_wl) 334 335 use yomhook, only : lhook, dr_hook 336 337 class(aerosol_optics_type), intent(inout) :: this 338 integer, intent(in) :: n_type_phobic, n_type_philic, nrh 339 integer, intent(in) :: n_bands_lw, n_bands_sw, n_mono_wl 340 341 real(jprb) :: hook_handle 342 343 if (lhook) call dr_hook('radiation_aerosol_optics_data:allocate',0,hook_handle) 344 345 this%n_type_phobic = n_type_phobic 346 this%n_type_philic = n_type_philic 347 this%nrh = nrh 348 this%n_bands_lw = n_bands_lw 349 this%n_bands_sw = n_bands_sw 350 this%n_mono_wl = n_mono_wl 351 352 if (n_type_philic > 0) then 353 this%use_hydrophilic = .true. 354 else 355 this%use_hydrophilic = .false. 356 end if 357 358 if (n_bands_sw > 0) then 359 allocate(this%mass_ext_sw_phobic(n_bands_sw, n_type_phobic)) 360 allocate(this%ssa_sw_phobic(n_bands_sw, n_type_phobic)) 361 allocate(this%g_sw_phobic(n_bands_sw, n_type_phobic)) 362 end if 363 if (n_bands_lw > 0) then 364 allocate(this%mass_ext_lw_phobic(n_bands_lw, n_type_phobic)) 365 allocate(this%ssa_lw_phobic(n_bands_lw, n_type_phobic)) 366 allocate(this%g_lw_phobic(n_bands_lw, n_type_phobic)) 367 end if 368 if (n_mono_wl > 0) then 369 allocate(this%mass_ext_mono_phobic(n_mono_wl, n_type_phobic)) 370 allocate(this%ssa_mono_phobic(n_mono_wl, n_type_phobic)) 371 allocate(this%g_mono_phobic(n_mono_wl, n_type_phobic)) 372 allocate(this%lidar_ratio_mono_phobic(n_mono_wl, n_type_phobic)) 373 end if 374 375 if (n_type_philic > 0 .and. nrh > 0) then 376 if (n_bands_sw > 0) then 377 allocate(this%mass_ext_sw_philic(n_bands_sw, nrh, n_type_philic)) 378 allocate(this%ssa_sw_philic(n_bands_sw, nrh, n_type_philic)) 379 allocate(this%g_sw_philic(n_bands_sw, nrh, n_type_philic)) 380 end if 381 if (n_bands_lw > 0) then 382 allocate(this%mass_ext_lw_philic(n_bands_lw, nrh, n_type_philic)) 383 allocate(this%ssa_lw_philic(n_bands_lw, nrh, n_type_philic)) 384 allocate(this%g_lw_philic(n_bands_lw, nrh, n_type_philic)) 385 end if 386 if (n_mono_wl > 0) then 387 allocate(this%mass_ext_mono_philic(n_mono_wl, nrh, n_type_philic)) 388 allocate(this%ssa_mono_philic(n_mono_wl, nrh, n_type_philic)) 389 allocate(this%g_mono_philic(n_mono_wl, nrh, n_type_philic)) 390 allocate(this%lidar_ratio_mono_philic(n_mono_wl, nrh, n_type_philic)) 391 end if 392 end if 393 394 if (lhook) call dr_hook('radiation_aerosol_optics_data:allocate',1,hook_handle) 395 396 end subroutine allocate 397 398 399 !--------------------------------------------------------------------- 400 subroutine save_aerosol_optics(this, file_name, iverbose) 401 402 use yomhook, only : lhook, dr_hook 403 use easy_netcdf, only : netcdf_file 404 405 class(aerosol_optics_type), intent(inout) :: this 406 character(len=*), intent(in) :: file_name 407 integer, optional, intent(in) :: iverbose 408 409 ! Object for output NetCDF file 410 type(netcdf_file) :: out_file 411 412 real(jprb) :: hook_handle 413 414 if (lhook) call dr_hook('radiation_aerosol_optics_data:save',0,hook_handle) 415 416 ! Create the file 417 call out_file%create(trim(file_name), iverbose=iverbose) 418 419 ! Define dimensions 420 call out_file%define_dimension("band_lw", this%n_bands_lw) 421 call out_file%define_dimension("band_sw", this%n_bands_sw) 422 call out_file%define_dimension("hydrophilic", this%n_type_philic) 423 call out_file%define_dimension("hydrophobic", this%n_type_phobic) 424 call out_file%define_dimension("relative_humidity", this%nrh) 425 !if (this%use_monochromatic) then 426 ! call out_file%define_dimension("wavelength_mono", this%n_mono_wl) 427 !end if 428 429 ! Put global attributes 430 call out_file%put_global_attributes( & 431 & title_str="Aerosol optical properties in the spectral intervals of the gas-optics scheme for ecRad", & 432 & source_str="ecRad offline radiation model") 433 call out_file%put_global_attribute( & 434 & "description_hydrophobic", this%description_phobic_str) 435 call out_file%put_global_attribute( & 436 & "description_hydrophilic", this%description_philic_str) 437 438 ! Define variables 439 call out_file%define_variable("mass_ext_sw_hydrophobic", units_str="m2 kg-1", & 440 & long_name="Shortwave mass-extinction coefficient of hydrophobic aerosols", & 441 & dim2_name="hydrophobic", dim1_name="band_sw") 442 call out_file%define_variable("ssa_sw_hydrophobic", units_str="1", & 443 & long_name="Shortwave single scattering albedo of hydrophobic aerosols", & 444 & dim2_name="hydrophobic", dim1_name="band_sw") 445 call out_file%define_variable("asymmetry_sw_hydrophobic", units_str="1", & 446 & long_name="Shortwave asymmetry factor of hydrophobic aerosols", & 447 & dim2_name="hydrophobic", dim1_name="band_sw") 448 449 call out_file%define_variable("mass_ext_lw_hydrophobic", units_str="m2 kg-1", & 450 & long_name="Longwave mass-extinction coefficient of hydrophobic aerosols", & 451 & dim2_name="hydrophobic", dim1_name="band_lw") 452 call out_file%define_variable("ssa_lw_hydrophobic", units_str="1", & 453 & long_name="Longwave single scattering albedo of hydrophobic aerosols", & 454 & dim2_name="hydrophobic", dim1_name="band_lw") 455 call out_file%define_variable("asymmetry_lw_hydrophobic", units_str="1", & 456 & long_name="Longwave asymmetry factor of hydrophobic aerosols", & 457 & dim2_name="hydrophobic", dim1_name="band_lw") 458 459 call out_file%define_variable("mass_ext_sw_hydrophilic", units_str="m2 kg-1", & 460 & long_name="Shortwave mass-extinction coefficient of hydrophilic aerosols", & 461 & dim3_name="hydrophilic", dim2_name="relative_humidity", dim1_name="band_sw") 462 call out_file%define_variable("ssa_sw_hydrophilic", units_str="1", & 463 & long_name="Shortwave single scattering albedo of hydrophilic aerosols", & 464 & dim3_name="hydrophilic", dim2_name="relative_humidity", dim1_name="band_sw") 465 call out_file%define_variable("asymmetry_sw_hydrophilic", units_str="1", & 466 & long_name="Shortwave asymmetry factor of hydrophilic aerosols", & 467 & dim3_name="hydrophilic", dim2_name="relative_humidity", dim1_name="band_sw") 468 469 call out_file%define_variable("mass_ext_lw_hydrophilic", units_str="m2 kg-1", & 470 & long_name="Longwave mass-extinction coefficient of hydrophilic aerosols", & 471 & dim3_name="hydrophilic", dim2_name="relative_humidity", dim1_name="band_lw") 472 call out_file%define_variable("ssa_lw_hydrophilic", units_str="1", & 473 & long_name="Longwave single scattering albedo of hydrophilic aerosols", & 474 & dim3_name="hydrophilic", dim2_name="relative_humidity", dim1_name="band_lw") 475 call out_file%define_variable("asymmetry_lw_hydrophilic", units_str="1", & 476 & long_name="Longwave asymmetry factor of hydrophilic aerosols", & 477 & dim3_name="hydrophilic", dim2_name="relative_humidity", dim1_name="band_lw") 478 479 ! Write variables 480 call out_file%put("mass_ext_sw_hydrophobic", this%mass_ext_sw_phobic) 481 call out_file%put("ssa_sw_hydrophobic", this%ssa_sw_phobic) 482 call out_file%put("asymmetry_sw_hydrophobic", this%g_sw_phobic) 483 call out_file%put("mass_ext_lw_hydrophobic", this%mass_ext_lw_phobic) 484 call out_file%put("ssa_lw_hydrophobic", this%ssa_lw_phobic) 485 call out_file%put("asymmetry_lw_hydrophobic", this%g_lw_phobic) 486 call out_file%put("mass_ext_sw_hydrophilic", this%mass_ext_sw_philic) 487 call out_file%put("ssa_sw_hydrophilic", this%ssa_sw_philic) 488 call out_file%put("asymmetry_sw_hydrophilic", this%g_sw_philic) 489 call out_file%put("mass_ext_lw_hydrophilic", this%mass_ext_lw_philic) 490 call out_file%put("ssa_lw_hydrophilic", this%ssa_lw_philic) 491 call out_file%put("asymmetry_lw_hydrophilic", this%g_lw_philic) 492 493 call out_file%close() 494 495 if (lhook) call dr_hook('radiation_aerosol_optics_data:save',1,hook_handle) 496 497 end subroutine save_aerosol_optics 263 498 264 499 -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_cloud.F90
r3908 r4444 16 16 ! 2019-01-14 R. Hogan Added inv_inhom_effective_size variable 17 17 ! 2019-01-14 R. Hogan Added out_of_physical_bounds routine 18 ! 2019-06-14 R. Hogan Added capability to store any number of cloud/precip types 18 19 19 20 module radiation_cloud … … 32 33 type cloud_type 33 34 ! For maximum flexibility, an arbitrary number "ntype" of 34 ! cloud types could be stored, as follows: 35 ! integer :: ntype ! number of cloud types 36 ! integer :: nfraction ! number of cloud fractions 37 ! real(jprb), allocatable, dimension(:,:,:) :: & 38 ! mixing_ratio, & ! (ncol,nwetlev,ntype) mass mixing ratio (kg/kg) 39 ! particle_size,& ! (ncol,nwetlev,ntype) effective radius/size (m) 40 ! fraction ! (ncol,nwetlev,nfraction) areal (i.e. cloud) fraction 41 ! However, for practical purposes at the moment we consider two 42 ! cloud types, liquid cloud droplets and ice cloud 43 ! particles. The following variables are dimensioned (ncol,nlev) 44 real(jprb), allocatable, dimension(:,:) :: & 35 ! hydrometeor types can be stored, dimensioned (ncol,nlev,ntype) 36 integer :: ntype = 0 37 real(jprb), allocatable, dimension(:,:,:) :: & 38 & mixing_ratio, & ! mass mixing ratio (kg/kg) 39 & effective_radius ! (m) 40 41 ! For backwards compatibility, we also allow for the two 42 ! traditional cloud types, liquid cloud droplets and ice cloud 43 ! particles, dimensioned (ncol,nlev) 44 real(jprb), pointer, dimension(:,:) :: & 45 45 & q_liq, q_ice, & ! mass mixing ratio (kg/kg) 46 & re_liq, re_ice, & ! effective radius (m) 47 & fraction ! (0-1) Assume liq & ice completely mixed 46 & re_liq, re_ice ! effective radius (m) 47 48 ! For the moment, the different types of hydrometeor are assumed 49 ! to be mixed with each other, so there is just one cloud fraction 50 ! variable varying from 0 to 1 51 real(jprb), allocatable, dimension(:,:) :: fraction 48 52 49 53 ! The fractional standard deviation of cloud optical depth in the … … 95 99 ! in the offline code these are allocated when they are read from 96 100 ! the NetCDF file 97 subroutine allocate_cloud_arrays(this, ncol, nlev, use_inhom_effective_size)101 subroutine allocate_cloud_arrays(this, ncol, nlev, ntype, use_inhom_effective_size) 98 102 99 103 use yomhook, only : lhook, dr_hook 100 104 101 class(cloud_type), intent(inout) :: this 102 integer, intent(in) :: ncol ! Number of columns 103 integer, intent(in) :: nlev ! Number of levels 105 class(cloud_type), intent(inout), target :: this 106 integer, intent(in) :: ncol ! Number of columns 107 integer, intent(in) :: nlev ! Number of levels 108 ! Number of cloud/precip particle types. If not present then the 109 ! older cloud behaviour is assumed: two types are present, (1) 110 ! liquid and (2) ice, and they can be accessed via q_liq, q_ice, 111 ! re_liq and re_ice. 112 integer, intent(in), optional :: ntype 104 113 logical, intent(in), optional :: use_inhom_effective_size 105 114 … … 108 117 if (lhook) call dr_hook('radiation_cloud:allocate',0,hook_handle) 109 118 110 allocate(this%q_liq(ncol,nlev)) 111 allocate(this%re_liq(ncol,nlev)) 112 allocate(this%q_ice(ncol,nlev)) 113 allocate(this%re_ice(ncol,nlev)) 119 if (present(ntype)) then 120 this%ntype = ntype 121 else 122 this%ntype = 2 123 end if 124 allocate(this%mixing_ratio(ncol,nlev,this%ntype)) 125 allocate(this%effective_radius(ncol,nlev,this%ntype)) 126 nullify(this%q_liq) 127 nullify(this%q_ice) 128 nullify(this%re_liq) 129 nullify(this%re_ice) 130 if (.not. present(ntype)) then 131 ! Older interface in which only liquid and ice are supported 132 this%q_liq => this%mixing_ratio(:,:,1) 133 this%q_ice => this%mixing_ratio(:,:,2) 134 this%re_liq => this%effective_radius(:,:,1) 135 this%re_ice => this%effective_radius(:,:,2) 136 end if 137 114 138 allocate(this%fraction(ncol,nlev)) 115 139 allocate(this%overlap_param(ncol,nlev-1)) … … 140 164 if (lhook) call dr_hook('radiation_cloud:deallocate',0,hook_handle) 141 165 142 if (allocated(this%q_liq)) deallocate(this%q_liq) 143 if (allocated(this%re_liq)) deallocate(this%re_liq) 144 if (allocated(this%q_ice)) deallocate(this%q_ice) 145 if (allocated(this%re_ice)) deallocate(this%re_ice) 146 if (allocated(this%fraction)) deallocate(this%fraction) 147 if (allocated(this%overlap_param)) deallocate(this%overlap_param) 148 if (allocated(this%fractional_std)) deallocate(this%fractional_std) 166 nullify(this%q_liq) 167 nullify(this%q_ice) 168 nullify(this%re_liq) 169 nullify(this%re_ice) 170 171 if (allocated(this%mixing_ratio)) deallocate(this%mixing_ratio) 172 if (allocated(this%effective_radius)) deallocate(this%effective_radius) 173 if (allocated(this%fraction)) deallocate(this%fraction) 174 if (allocated(this%overlap_param)) deallocate(this%overlap_param) 175 if (allocated(this%fractional_std)) deallocate(this%fractional_std) 149 176 if (allocated(this%inv_cloud_effective_size)) & 150 177 & deallocate(this%inv_cloud_effective_size) … … 185 212 integer :: ncol, nlev 186 213 187 integer :: j lev214 integer :: jcol, jlev 188 215 189 216 real(jprb) :: hook_handle … … 220 247 ! top-of-atmosphere to surface). In case pressure_hl(:,1)=0, we 221 248 ! don't take the logarithm of the first pressure in each column. 222 this%overlap_param(i1:i2,1) = exp(-(R_over_g/decorrelation_length) & 223 & * thermodynamics%temperature_hl(i1:i2,2) & 224 & *log(thermodynamics%pressure_hl(i1:i2,3) & 225 & /thermodynamics%pressure_hl(i1:i2,2))) 249 do jcol = i1,i2 250 this%overlap_param(jcol,1) = exp(-(R_over_g/decorrelation_length) & 251 & * thermodynamics%temperature_hl(jcol,2) & 252 & *log(thermodynamics%pressure_hl(jcol,3) & 253 & /thermodynamics%pressure_hl(jcol,2))) 254 end do 226 255 227 256 do jlev = 2,nlev-1 228 this%overlap_param(i1:i2,jlev) = exp(-(0.5_jprb*R_over_g/decorrelation_length) & 229 & * thermodynamics%temperature_hl(i1:i2,jlev+1) & 230 & *log(thermodynamics%pressure_hl(i1:i2,jlev+2) & 231 & /thermodynamics%pressure_hl(i1:i2,jlev))) 257 do jcol = i1,i2 258 this%overlap_param(jcol,jlev) = exp(-(0.5_jprb*R_over_g/decorrelation_length) & 259 & * thermodynamics%temperature_hl(jcol,jlev+1) & 260 & *log(thermodynamics%pressure_hl(jcol,jlev+2) & 261 & /thermodynamics%pressure_hl(jcol,jlev))) 262 end do 232 263 end do 233 264 … … 237 268 ! don't take the logarithm of the last pressure in each column. 238 269 do jlev = 1,nlev-2 239 this%overlap_param(i1:i2,jlev) = exp(-(0.5_jprb*R_over_g/decorrelation_length) & 240 & * thermodynamics%temperature_hl(i1:i2,jlev+1) & 241 & *log(thermodynamics%pressure_hl(i1:i2,jlev) & 242 & /thermodynamics%pressure_hl(i1:i2,jlev+2))) 270 do jcol = i1,i2 271 this%overlap_param(jcol,jlev) = exp(-(0.5_jprb*R_over_g/decorrelation_length) & 272 & * thermodynamics%temperature_hl(jcol,jlev+1) & 273 & *log(thermodynamics%pressure_hl(jcol,jlev) & 274 & /thermodynamics%pressure_hl(jcol,jlev+2))) 275 end do 243 276 end do 244 this%overlap_param(i1:i2,nlev-1) = exp(-(R_over_g/decorrelation_length) & 245 & * thermodynamics%temperature_hl(i1:i2,nlev) & 246 & *log(thermodynamics%pressure_hl(i1:i2,nlev-1) & 247 & /thermodynamics%pressure_hl(i1:i2,nlev))) 248 277 278 do jcol = i1,i2 279 this%overlap_param(jcol,nlev-1) = exp(-(R_over_g/decorrelation_length) & 280 & * thermodynamics%temperature_hl(jcol,nlev) & 281 & *log(thermodynamics%pressure_hl(jcol,nlev-1) & 282 & /thermodynamics%pressure_hl(jcol,nlev))) 283 end do 249 284 end if 250 285 … … 580 615 integer, intent(in) :: istartcol, iendcol 581 616 582 integer :: nlev 583 integer :: jcol, jlev 617 integer :: nlev, ntype 618 integer :: jcol, jlev, jh 584 619 585 620 real(jprb) :: cloud_fraction_threshold, cloud_mixing_ratio_threshold 621 real(jprb) :: sum_mixing_ratio(istartcol:iendcol) 586 622 587 623 real(jprb) :: hook_handle … … 589 625 if (lhook) call dr_hook('radiation_cloud:crop_cloud_fraction',0,hook_handle) 590 626 591 nlev = size(this%fraction,2) 592 627 nlev = size(this%fraction,2) 628 ntype = size(this%mixing_ratio,3) 629 593 630 do jlev = 1,nlev 594 631 do jcol = istartcol,iendcol 595 if (this%fraction(jcol,jlev) < cloud_fraction_threshold & 596 & .or. this%q_liq(jcol,jlev)+this%q_ice(jcol,jlev) & 597 & < cloud_mixing_ratio_threshold) then 632 sum_mixing_ratio(jcol) = 0.0_jprb 633 end do 634 do jh = 1, ntype 635 do jcol = istartcol,iendcol 636 sum_mixing_ratio(jcol) = sum_mixing_ratio(jcol) + this%mixing_ratio(jcol,jlev,jh) 637 end do 638 end do 639 do jcol = istartcol,iendcol 640 if (this%fraction(jcol,jlev) < cloud_fraction_threshold & 641 & .or. sum_mixing_ratio(jcol) < cloud_mixing_ratio_threshold) then 598 642 this%fraction(jcol,jlev) = 0.0_jprb 599 643 end if … … 612 656 613 657 use yomhook, only : lhook, dr_hook 614 use radiation_c onfig, only : out_of_bounds_2d658 use radiation_check, only : out_of_bounds_2d, out_of_bounds_3d 615 659 616 660 class(cloud_type), intent(inout) :: this … … 631 675 end if 632 676 633 is_bad = out_of_bounds_ 2d(this%q_liq, 'q_liq', 0.0_jprb, 1.0_jprb, &677 is_bad = out_of_bounds_3d(this%mixing_ratio, 'cloud%mixing_ratio', 0.0_jprb, 1.0_jprb, & 634 678 & do_fix_local, i1=istartcol, i2=iendcol) & 635 & .or. out_of_bounds_2d(this%q_ice, 'q_ice', 0.0_jprb, 1.0_jprb, & 636 & do_fix_local, i1=istartcol, i2=iendcol) & 637 & .or. out_of_bounds_2d(this%re_liq, 're_liq', 0.0_jprb, 0.01_jprb, & 638 & do_fix_local, i1=istartcol, i2=iendcol) & 639 & .or. out_of_bounds_2d(this%re_ice, 're_ice', 0.0_jprb, 0.1_jprb, & 679 & .or. out_of_bounds_3d(this%effective_radius, 'cloud%effective_radius', 0.0_jprb, 0.1_jprb, & 640 680 & do_fix_local, i1=istartcol, i2=iendcol) & 641 681 & .or. out_of_bounds_2d(this%fraction, 'cloud%fraction', 0.0_jprb, 1.0_jprb, & -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_cloud_cover.F90
r3908 r4444 253 253 & + (1.0_jprb - overlap_alpha) & 254 254 & * (frac(jlev)+frac(jlev+1)-frac(jlev)*frac(jlev+1)) 255 255 ! Added for DWD (2020) 256 #ifdef __SX__ 257 end do 258 do jlev = 1,nlev-1 259 #endif 256 260 if (frac(jlev) >= MaxCloudFrac) then 257 261 ! Cloud cover has reached one -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_cloud_generator.F90
r3908 r4444 18 18 ! Modifications 19 19 ! 2018-02-22 R. Hogan Call masked version of PDF sampler for speed 20 ! 2020-03-31 R. Hogan More vectorizable version of Exp-Ran 20 21 21 22 module radiation_cloud_generator … … 39 40 & fractional_std, pdf_sampler, & 40 41 & od_scaling, total_cloud_cover, & 41 & is_beta_overlap)42 & use_beta_overlap, use_vectorizable_generator) 42 43 43 44 use parkind1, only : jprb … … 86 87 ! overlap parameter of Shonk et al. (2010), and needs to be 87 88 ! converted to alpha. 88 logical, intent(in), optional :: is_beta_overlap 89 logical, intent(in), optional :: use_beta_overlap 90 91 ! Do we use the more vectorizable cloud generator, at the expense 92 ! of more random numbers being needed? 93 logical, intent(in), optional :: use_vectorizable_generator 89 94 90 95 ! Outputs … … 126 131 real(jprb), dimension(nlev-1) :: pair_cloud_cover, overhang 127 132 133 logical :: use_vec_gen 134 128 135 real(jprb) :: hook_handle 129 136 … … 132 139 if (i_overlap_scheme == IOverlapExponentialRandom) then 133 140 call cum_cloud_cover_exp_ran(nlev, frac, overlap_param, & 134 & cum_cloud_cover, pair_cloud_cover, is_beta_overlap)141 & cum_cloud_cover, pair_cloud_cover, use_beta_overlap) 135 142 else if (i_overlap_scheme == IOverlapMaximumRandom) then 136 143 call cum_cloud_cover_max_ran(nlev, frac, & … … 138 145 else if (i_overlap_scheme == IOverlapExponential) then 139 146 call cum_cloud_cover_exp_exp(nlev, frac, overlap_param, & 140 & cum_cloud_cover, pair_cloud_cover, is_beta_overlap)147 & cum_cloud_cover, pair_cloud_cover, use_beta_overlap) 141 148 else 142 149 write(nulerr,'(a)') '*** Error: cloud overlap scheme not recognised' … … 183 190 od_scaling = 0.0_jprb 184 191 185 ! Expensive operation: initialize random number generator for 186 ! this column 187 call initialize_random_numbers(iseed, random_stream) 188 189 ! Compute ng random numbers to use to locate cloud top 190 call uniform_distribution(rand_top, random_stream) 191 192 ! Loop over ng columns 193 do jg = 1,ng 194 ! Find the cloud top height corresponding to the current 195 ! random number, and store in itrigger 196 trigger = rand_top(jg) * total_cloud_cover 197 jlev = ibegin 198 do while (trigger > cum_cloud_cover(jlev) .and. jlev < iend) 199 jlev = jlev + 1 192 if (present(use_vectorizable_generator)) then 193 use_vec_gen = use_vectorizable_generator 194 else 195 use_vec_gen = .false. 196 end if 197 198 if (.not. use_vec_gen) then 199 ! Original generator that minimizes the number of random 200 ! numbers used, but is not vectorizable 201 202 ! Expensive operation: initialize random number generator for 203 ! this column 204 call initialize_random_numbers(iseed, random_stream) 205 206 ! Compute ng random numbers to use to locate cloud top 207 call uniform_distribution(rand_top, random_stream) 208 209 ! Loop over ng columns 210 do jg = 1,ng 211 ! Find the cloud top height corresponding to the current 212 ! random number, and store in itrigger 213 trigger = rand_top(jg) * total_cloud_cover 214 jlev = ibegin 215 do while (trigger > cum_cloud_cover(jlev) .and. jlev < iend) 216 jlev = jlev + 1 217 end do 218 itrigger = jlev 219 220 if (i_overlap_scheme /= IOverlapExponential) then 221 call generate_column_exp_ran(ng, nlev, jg, random_stream, pdf_sampler, & 222 & frac, pair_cloud_cover, & 223 & cum_cloud_cover, overhang, fractional_std, overlap_param_inhom, & 224 & itrigger, iend, od_scaling) 225 else 226 call generate_column_exp_exp(ng, nlev, jg, random_stream, pdf_sampler, & 227 & frac, pair_cloud_cover, & 228 & cum_cloud_cover, overhang, fractional_std, overlap_param_inhom, & 229 & itrigger, iend, od_scaling) 230 end if 231 200 232 end do 201 itrigger = jlev 202 203 if (i_overlap_scheme /= IOverlapExponential) then 204 call generate_column_exp_ran(ng, nlev, jg, random_stream, pdf_sampler, & 205 & frac, pair_cloud_cover, & 206 & cum_cloud_cover, overhang, fractional_std, overlap_param_inhom, & 207 & itrigger, iend, od_scaling) 208 else 209 call generate_column_exp_exp(ng, nlev, jg, random_stream, pdf_sampler, & 210 & frac, pair_cloud_cover, & 211 & cum_cloud_cover, overhang, fractional_std, overlap_param_inhom, & 212 & itrigger, iend, od_scaling) 233 234 else 235 ! Alternative generator (only for Exp-Ran overlap so far) that 236 ! should be vectorizable but generates more random numbers, 237 ! some of which are not used 238 239 if (i_overlap_scheme == IOverlapExponential) then 240 write(nulerr,'(a)') '*** Error: vectorizable cloud generator is not available with Exp-Exp overlap' 241 call radiation_abort() 213 242 end if 214 215 end do 243 244 call generate_columns_exp_ran(ng, nlev, iseed, pdf_sampler, & 245 & total_cloud_cover, frac_threshold, frac, pair_cloud_cover, & 246 & cum_cloud_cover, overhang, fractional_std, overlap_param_inhom, & 247 & ibegin, iend, od_scaling) 248 249 end if 216 250 217 251 end if 218 219 252 220 253 if (lhook) call dr_hook('radiation_cloud_generator:cloud_generator',1,hook_handle) … … 474 507 475 508 ! Sample from a lognormal or gamma distribution to obtain the 476 ! optical depth scalings, calling the faster masked version and 477 ! assuming values outside the range itrigger:iend are already zero 509 ! optical depth scalings 510 511 ! Masked version assuming values outside the range itrigger:iend 512 ! are already zero: 478 513 call pdf_sampler%masked_sample(n_layers_to_scale, & 479 514 & fractional_std(itrigger:iend), & … … 481 516 & is_cloudy(itrigger:iend)) 482 517 518 ! ! IFS version: 519 ! !$omp simd 520 ! do jlev=itrigger,iend 521 ! if (.not. is_cloudy(jlev)) then 522 ! od_scaling(ig,jlev) = 0.0_jprb 523 ! else 524 ! call sample_from_pdf_simd(& 525 ! pdf_sampler,fractional_std(jlev),& 526 ! rand_inhom1(jlev-itrigger+1), & 527 ! od_scaling(ig,jlev)) 528 ! end if 529 ! end do 530 483 531 end subroutine generate_column_exp_exp 484 532 533 534 !--------------------------------------------------------------------- 535 ! Extract the value of a lognormal distribution with fractional 536 ! standard deviation "fsd" corresponding to the cumulative 537 ! distribution function value "cdf", and return it in x. Since this 538 ! is an elemental subroutine, fsd, cdf and x may be arrays. SIMD version. 539 subroutine sample_from_pdf_simd(this, fsd, cdf, x) 540 use parkind1, only : jprb 541 use radiation_pdf_sampler, only : pdf_sampler_type 542 implicit none 543 #if defined(__GFORTRAN__) || defined(__PGI) || defined(__NEC__) 544 #else 545 !$omp declare simd(sample_from_pdf_simd) uniform(this) & 546 !$omp linear(ref(fsd)) linear(ref(cdf)) 547 #endif 548 type(pdf_sampler_type), intent(in) :: this 549 550 ! Fractional standard deviation (0 to 4) and cumulative 551 ! distribution function (0 to 1) 552 real(jprb), intent(in) :: fsd, cdf 553 554 ! Sample from distribution 555 real(jprb), intent(out) :: x 556 557 ! Index to look-up table 558 integer :: ifsd, icdf 559 560 ! Weights in bilinear interpolation 561 real(jprb) :: wfsd, wcdf 562 563 ! Bilinear interpolation with bounds 564 wcdf = cdf * (this%ncdf-1) + 1.0_jprb 565 icdf = max(1, min(int(wcdf), this%ncdf-1)) 566 wcdf = max(0.0_jprb, min(wcdf - icdf, 1.0_jprb)) 567 568 wfsd = (fsd-this%fsd1) * this%inv_fsd_interval + 1.0_jprb 569 ifsd = max(1, min(int(wfsd), this%nfsd-1)) 570 wfsd = max(0.0_jprb, min(wfsd - ifsd, 1.0_jprb)) 571 572 x = (1.0_jprb-wcdf)*(1.0_jprb-wfsd) * this%val(icdf ,ifsd) & 573 & + (1.0_jprb-wcdf)* wfsd * this%val(icdf ,ifsd+1) & 574 & + wcdf *(1.0_jprb-wfsd) * this%val(icdf+1,ifsd) & 575 & + wcdf * wfsd * this%val(icdf+1,ifsd+1) 576 577 end subroutine sample_from_pdf_simd 578 579 580 !--------------------------------------------------------------------- 581 ! Generate columns of optical depth scalings using 582 ! exponential-random overlap (which includes maximum-random overlap 583 ! as a limiting case). This version is intended to work better on 584 ! hardware with long vector lengths. As with all calculations in 585 ! this file, we zoom into the fraction of the column with cloud at 586 ! any height, so that all spectral intervals see a cloud somewhere. 587 ! In the McICA solver, this is combined appropriately with the 588 ! clear-sky calculation. 589 subroutine generate_columns_exp_ran(ng, nlev, iseed, pdf_sampler, & 590 & total_cloud_cover, frac_threshold, frac, pair_cloud_cover, & 591 & cum_cloud_cover, overhang, fractional_std, overlap_param_inhom, & 592 & ibegin, iend, od_scaling) 593 594 use parkind1, only : jprb 595 use radiation_pdf_sampler, only : pdf_sampler_type 596 use radiation_random_numbers, only : rng_type, IRngMinstdVector, IRngNative 597 598 implicit none 599 600 ! Number of g points / columns 601 integer, intent(in) :: ng 602 603 ! Number of levels 604 integer, intent(in) :: nlev 605 606 integer, intent(in) :: iseed ! seed for random number generator 607 608 ! Stream for producing random numbers 609 !type(randomnumberstream) :: random_stream 610 type(rng_type) :: random_number_generator 611 612 ! Object for sampling from a lognormal or gamma distribution 613 type(pdf_sampler_type), intent(in) :: pdf_sampler 614 615 ! Total cloud cover using cloud fraction and overlap parameter 616 real(jprb), intent(in) :: total_cloud_cover 617 618 real(jprb), intent(in) :: frac_threshold 619 620 ! Cloud fraction, cumulative cloud cover and fractional standard 621 ! deviation in each layer 622 real(jprb), intent(in), dimension(nlev) :: frac, cum_cloud_cover, fractional_std 623 624 ! Cloud cover of a pair of layers, and amount by which cloud at 625 ! next level increases total cloud cover as seen from above 626 real(jprb), intent(in), dimension(nlev-1) :: pair_cloud_cover, overhang 627 628 ! Overlap parameter of inhomogeneities 629 real(jprb), intent(in), dimension(nlev-1) :: overlap_param_inhom 630 631 ! Top of highest cloudy layer and base of lowest 632 integer, intent(inout) :: ibegin, iend 633 634 ! Optical depth scaling to output 635 real(jprb), intent(inout), dimension(ng,nlev) :: od_scaling 636 637 ! Loop indices 638 integer :: jlev, jg 639 640 real(jprb) :: rand_cloud(ng,ibegin:iend) 641 real(jprb) :: rand_inhom(ng,ibegin-1:iend), rand_inhom2(ng,ibegin:iend) 642 643 ! Is the cloud fraction above the minimum threshold at each level 644 logical :: is_any_cloud(ibegin:iend) 645 646 ! Scaled random number for finding cloud 647 real(jprb) :: trigger(ng) 648 649 logical :: is_cloud(ng) ! Is there cloud at this level and spectral interval? 650 logical :: prev_cloud(ng) ! Was there cloud at level above? 651 logical :: first_cloud(ng) ! At level of first cloud counting down from top? 652 logical :: found_cloud(ng) ! Cloud found in this column counting down from top? 653 654 is_any_cloud = (frac(ibegin:iend) >= frac_threshold) 655 656 ! Initialize random number generator for this column, and state 657 ! that random numbers will be requested in blocks of length the 658 ! number of spectral intervals ng. 659 call random_number_generator%initialize(IRngMinstdVector, iseed=iseed, & 660 & nmaxstreams=ng) 661 662 ! Random numbers to use to locate cloud top 663 call random_number_generator%uniform_distribution(trigger) 664 665 ! Random numbers to work out whether to transition vertically from 666 ! clear to cloudy, cloudy to clear, clear to clear or cloudy to 667 ! cloudy 668 call random_number_generator%uniform_distribution(rand_cloud, is_any_cloud) 669 670 ! Random numbers to generate sub-grid cloud structure 671 call random_number_generator%uniform_distribution(rand_inhom) 672 call random_number_generator%uniform_distribution(rand_inhom2, is_any_cloud) 673 674 trigger = trigger * total_cloud_cover 675 676 ! Initialize logicals for clear-sky above first cloudy layer 677 found_cloud = .false. 678 is_cloud = .false. 679 first_cloud = .false. 680 681 ! Loop down through layers starting at the first cloudy layer 682 do jlev = ibegin,iend 683 684 if (is_any_cloud(jlev)) then 685 686 ! Added for DWD (2020) 687 !NEC$ shortloop 688 do jg = 1,ng 689 ! The intention is that all these operations are vectorizable, 690 ! since all are vector operations on vectors of length ng... 691 692 ! Copy the cloud mask between levels 693 prev_cloud(jg) = is_cloud(jg) 694 695 ! For each spectral interval, has the first cloud appeared at this level? 696 first_cloud(jg) = (trigger(jg) <= cum_cloud_cover(jlev) .and. .not. found_cloud(jg)) 697 698 ! ...if so, add to found_cloud 699 found_cloud(jg) = found_cloud(jg) .or. first_cloud(jg) 700 701 ! There is cloud at this level either if a first cloud has 702 ! appeared, or using separate probability calculations 703 ! depending on whether there is a cloud above (given by 704 ! prev_cloud) 705 is_cloud(jg) = first_cloud(jg) & 706 & .or. found_cloud(jg) .and. merge(rand_cloud(jg,jlev)*frac(jlev-1) & 707 & < frac(jlev)+frac(jlev-1)-pair_cloud_cover(jlev-1), & 708 & rand_cloud(jg,jlev)*(cum_cloud_cover(jlev-1) - frac(jlev-1)) & 709 & < pair_cloud_cover(jlev-1) - overhang(jlev-1) - frac(jlev-1), & 710 & prev_cloud(jg)) 711 ! The random number determining cloud structure decorrelates 712 ! with the one above it according to the overlap parameter, 713 ! but always decorrelates if there is clear-sky above. If 714 ! there is clear-sky in the present level, the random number 715 ! is set to zero to ensure that the optical depth scaling is 716 ! also zero. 717 rand_inhom(jg,jlev) = merge(merge(rand_inhom(jg,jlev-1), rand_inhom(jg,jlev), & 718 & rand_inhom2(jg,jlev) < overlap_param_inhom(jlev-1) & 719 & .and. prev_cloud(jg)), & 720 & 0.0_jprb, is_cloud(jg)) 721 end do 722 else 723 ! No cloud at this level 724 is_cloud = .false. 725 end if 726 end do 727 728 ! Sample from a lognormal or gamma distribution to obtain the 729 ! optical depth scalings, calling the faster masked version and 730 ! assuming values outside the range ibegin:iend are already zero 731 call pdf_sampler%masked_block_sample(iend-ibegin+1, ng, & 732 & fractional_std(ibegin:iend), & 733 & rand_inhom(:,ibegin:iend), od_scaling(:,ibegin:iend), & 734 & is_any_cloud) 735 736 end subroutine generate_columns_exp_ran 737 485 738 end module radiation_cloud_generator -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_cloud_optics.F90
r3908 r4444 19 19 20 20 implicit none 21 21 22 public 22 23 … … 271 272 type(cloud_optics_type), pointer :: ho 272 273 273 integer :: jcol, jlev 274 integer :: jcol, jlev, jb 274 275 275 276 real(jprb) :: hook_handle … … 345 346 end if 346 347 348 ! Delta-Eddington scaling in the shortwave only 347 349 if (.not. config%do_sw_delta_scaling_with_gases) then 348 ! Delta-Eddington scaling in the shortwave only349 350 call delta_eddington_scat_od(od_sw_liq, scat_od_sw_liq, g_sw_liq) 350 351 end if 352 !call delta_eddington_scat_od(od_lw_liq, scat_od_lw_liq, g_lw_liq) 353 351 354 else 352 355 ! Liquid not present: set properties to zero … … 437 440 end if 438 441 442 ! Delta-Eddington scaling in both longwave and shortwave 443 ! (assume that particles are larger than wavelength even 444 ! in longwave) 439 445 if (.not. config%do_sw_delta_scaling_with_gases) then 440 ! Delta-Eddington scaling in both longwave and shortwave441 ! (assume that particles are larger than wavelength even442 ! in longwave)443 446 call delta_eddington_scat_od(od_sw_ice, scat_od_sw_ice, g_sw_ice) 444 447 end if 445 446 448 call delta_eddington_scat_od(od_lw_ice, scat_od_lw_ice, g_lw_ice) 449 447 450 else 448 451 ! Ice not present: set properties to zero … … 458 461 ! Combine liquid and ice 459 462 if (config%do_lw_cloud_scattering) then 460 od_lw_cloud(:,jlev,jcol) = od_lw_liq + od_lw_ice 461 where (scat_od_lw_liq+scat_od_lw_ice > 0.0_jprb) 462 g_lw_cloud(:,jlev,jcol) = (g_lw_liq * scat_od_lw_liq & 463 & + g_lw_ice * scat_od_lw_ice) & 464 & / (scat_od_lw_liq+scat_od_lw_ice) 465 elsewhere 466 g_lw_cloud(:,jlev,jcol) = 0.0_jprb 467 end where 468 ssa_lw_cloud(:,jlev,jcol) = (scat_od_lw_liq + scat_od_lw_ice) & 469 & / (od_lw_liq + od_lw_ice) 463 ! Added for DWD (2020) 464 !NEC$ shortloop 465 do jb = 1, config%n_bands_lw 466 od_lw_cloud(jb,jlev,jcol) = od_lw_liq(jb) + od_lw_ice(jb) 467 if (scat_od_lw_liq(jb)+scat_od_lw_ice(jb) > 0.0_jprb) then 468 g_lw_cloud(jb,jlev,jcol) = (g_lw_liq(jb) * scat_od_lw_liq(jb) & 469 & + g_lw_ice(jb) * scat_od_lw_ice(jb)) & 470 & / (scat_od_lw_liq(jb)+scat_od_lw_ice(jb)) 471 else 472 g_lw_cloud(jb,jlev,jcol) = 0.0_jprb 473 end if 474 ssa_lw_cloud(jb,jlev,jcol) = (scat_od_lw_liq(jb) + scat_od_lw_ice(jb)) & 475 & / (od_lw_liq(jb) + od_lw_ice(jb)) 476 end do 470 477 else 471 478 ! If longwave scattering is to be neglected then the 472 479 ! best approximation is to set the optical depth equal 473 480 ! to the absorption optical depth 474 od_lw_cloud(:,jlev,jcol) = od_lw_liq - scat_od_lw_liq & 475 & + od_lw_ice - scat_od_lw_ice 481 ! Added for DWD (2020) 482 !NEC$ shortloop 483 do jb = 1, config%n_bands_lw 484 od_lw_cloud(jb,jlev,jcol) = od_lw_liq(jb) - scat_od_lw_liq(jb) & 485 & + od_lw_ice(jb) - scat_od_lw_ice(jb) 486 end do 476 487 end if 477 od_sw_cloud(:,jlev,jcol) = od_sw_liq + od_sw_ice 478 g_sw_cloud(:,jlev,jcol) = (g_sw_liq * scat_od_sw_liq & 479 & + g_sw_ice * scat_od_sw_ice) & 480 & / (scat_od_sw_liq + scat_od_sw_ice) 481 ssa_sw_cloud(:,jlev,jcol) & 482 & = (scat_od_sw_liq + scat_od_sw_ice) / (od_sw_liq + od_sw_ice) 488 ! Added for DWD (2020) 489 !NEC$ shortloop 490 do jb = 1, config%n_bands_sw 491 od_sw_cloud(jb,jlev,jcol) = od_sw_liq(jb) + od_sw_ice(jb) 492 g_sw_cloud(jb,jlev,jcol) = (g_sw_liq(jb) * scat_od_sw_liq(jb) & 493 & + g_sw_ice(jb) * scat_od_sw_ice(jb)) & 494 & / (scat_od_sw_liq(jb) + scat_od_sw_ice(jb)) 495 ssa_sw_cloud(jb,jlev,jcol) & 496 & = (scat_od_sw_liq(jb) + scat_od_sw_ice(jb)) / (od_sw_liq(jb) + od_sw_ice(jb)) 497 end do 483 498 end if ! Cloud present 484 499 end do ! Loop over column -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_config.F90
r4115 r4444 26 26 ! 2019-02-03 R. Hogan Added ability to fix out-of-physical-bounds inputs 27 27 ! 2019-02-10 R. Hogan Renamed "encroachment" to "entrapment" 28 ! 2020-05-18 R. Hogan Moved out_of_bounds_* to radiation_check.F90 29 ! 2021-07-04 R. Hogan Numerous changes for ecCKD and general cloud/aerosol optics 28 30 ! 29 31 ! Note: The aim is for ecRad in the IFS to be as similar as possible … … 37 39 38 40 use radiation_cloud_optics_data, only : cloud_optics_type 41 use radiation_general_cloud_optics_data, only : general_cloud_optics_type 39 42 use radiation_aerosol_optics_data, only : aerosol_optics_type 40 43 use radiation_pdf_sampler, only : pdf_sampler_type 41 44 use radiation_cloud_cover, only : OverlapName, & 42 45 & IOverlapMaximumRandom, IOverlapExponentialRandom, IOverlapExponential 46 use radiation_ecckd, only : ckd_model_type 43 47 44 48 implicit none … … 70 74 & IEntrapmentExplicitNonFractal, & ! As above but ignore fractal nature of clouds 71 75 & IEntrapmentMaximum ! Complete horizontal homogenization within regions (old SPARTACUS assumption) 72 73 76 end enum 74 77 … … 94 97 ! Gas models 95 98 enum, bind(c) 96 enumerator IGasModelMonochromatic, IGasModelIFSRRTMG 99 enumerator IGasModelMonochromatic, IGasModelIFSRRTMG, IGasModelECCKD 97 100 end enum 98 character(len=*), parameter :: GasModelName(0:1) = (/ 'Monochromatic', & 99 & 'RRTMG-IFS ' /) 101 character(len=*), parameter :: GasModelName(0:2) = (/ 'Monochromatic', & 102 & 'RRTMG-IFS ', & 103 & 'ECCKD '/) 100 104 101 105 ! Hydrometeor scattering models … … 130 134 integer, parameter :: NMaxAerosolTypes = 256 131 135 136 ! Maximum number of different cloud types that can be provided 137 integer, parameter :: NMaxCloudTypes = 12 138 132 139 ! Maximum number of shortwave albedo and longwave emissivity 133 140 ! intervals … … 155 162 character(len=511) :: directory_name = '.' 156 163 164 ! If this is true then support arbitrary hydrometeor types (not 165 ! just ice and liquid) and arbitrary spectral discretization (not 166 ! just RRTMG). It is required that this is true if the ecCKD gas 167 ! optics model is selected. General cloud optics has only been 168 ! available from ecRad version 1.5. 169 logical :: use_general_cloud_optics = .true. 170 171 ! If this is true then support aerosol properties at an arbitrary 172 ! spectral discretization (not just RRTMG). It is required that 173 ! this is true if the ecCKD gas optics model is selected. 174 logical :: use_general_aerosol_optics = .true. 175 157 176 ! Cloud is deemed to be present in a layer if cloud fraction 158 177 ! exceeds this value … … 168 187 ! (2000)? 169 188 logical :: use_beta_overlap = .false. 189 190 ! Use a more vectorizable McICA cloud generator, at the expense of 191 ! more random numbers being generated? This is the default on NEC 192 ! SX. 193 #ifdef __SX__ 194 logical :: use_vectorizable_generator = .true. 195 #else 196 logical :: use_vectorizable_generator = .false. 197 #endif 170 198 171 199 ! Shape of sub-grid cloud water PDF … … 236 264 logical :: do_sw_delta_scaling_with_gases = .false. 237 265 238 ! Codes describing the gas and cloud scattering models to use, the 239 ! latter of which is currently not used 266 ! Codes describing the gas model 240 267 integer :: i_gas_model = IGasModelIFSRRTMG 241 ! integer :: i_cloud_model242 268 243 269 ! Optics if i_gas_model==IGasModelMonochromatic. … … 270 296 ! according to the spectral overlap of each interval with each 271 297 ! band 272 logical :: do_nearest_spectral_sw_albedo = . true.273 logical :: do_nearest_spectral_lw_emiss = . true.298 logical :: do_nearest_spectral_sw_albedo = .false. 299 logical :: do_nearest_spectral_lw_emiss = .false. 274 300 275 301 ! User-defined monotonically increasing wavelength bounds (m) 276 302 ! between input surface albedo/emissivity intervals. Implicitly 277 ! the first interval starts at zero and the last ends at infinity. 303 ! the first interval starts at zero and the last ends at 304 ! infinity. These must be set with define_sw_albedo_intervals and 305 ! define_lw_emiss_intervals. 278 306 real(jprb) :: sw_albedo_wavelength_bound(NMaxAlbedoIntervals-1) = -1.0_jprb 279 real(jprb) :: lw_emiss_wavelength_bound( NMaxAlbedoIntervals-1) 307 real(jprb) :: lw_emiss_wavelength_bound( NMaxAlbedoIntervals-1) = -1.0_jprb 280 308 281 309 ! The index to the surface albedo/emissivity intervals for each of … … 296 324 logical :: do_3d_effects = .true. 297 325 326 character(len=511) :: cloud_type_name(NMaxCloudTypes) = ["","","","","","","","","","","",""] 327 ! & 328 ! & = ["mie_droplet ", & 329 ! & "baum-general-habit-mixture_ice"] 330 331 ! Spectral averaging method to use with generalized cloud optics; 332 ! see Edwards & Slingo (1996) for definition. Experimentation 333 ! with ecRad suggests that "thick" averaging is more accurate for 334 ! both liquid and ice clouds. 335 logical :: use_thick_cloud_spectral_averaging(NMaxCloudTypes) & 336 & = [.true.,.true.,.true.,.true.,.true.,.true., & 337 & .true.,.true.,.true.,.true.,.true.,.true.] 338 298 339 ! To what extent do we include "entrapment" effects in the 299 340 ! SPARTACUS solver? This essentially means that in a situation … … 420 461 ! doesn't start with a '/' character then it will be prepended by 421 462 ! the contents of directory_name. 422 character(len=511) :: ice_optics_override_file_name = ''423 character(len=511) :: liq_optics_override_file_name = ''463 character(len=511) :: ice_optics_override_file_name = '' 464 character(len=511) :: liq_optics_override_file_name = '' 424 465 character(len=511) :: aerosol_optics_override_file_name = '' 466 character(len=511) :: gas_optics_sw_override_file_name = '' 467 character(len=511) :: gas_optics_lw_override_file_name = '' 425 468 426 469 ! Optionally override the look-up table file for the cloud-water … … 428 471 character(len=511) :: cloud_pdf_override_file_name = '' 429 472 473 ! Do we compute cloud, aerosol and surface optical properties per 474 ! g point? Not available with RRTMG gas optics model. 475 logical :: do_cloud_aerosol_per_sw_g_point = .true. 476 logical :: do_cloud_aerosol_per_lw_g_point = .true. 477 478 ! Do we weight the mapping from surface emissivity/albedo to 479 ! g-point/band weighting by a reference Planck function (more 480 ! accurate) or weighting each wavenumber equally (less accurate 481 ! but consistent with IFS Cycle 48r1 and earlier)? 482 logical :: do_weighted_surface_mapping = .true. 483 484 ! COMPUTED PARAMETERS 485 486 ! Users of this library should not edit these parameters directly; 487 ! they are set by the "consolidate" routine 488 430 489 ! Has "consolidate" been called? 431 490 logical :: is_consolidated = .false. 432 491 433 ! COMPUTED PARAMETERS 434 ! Users of this library should not edit these parameters directly; 435 ! they are set by the "consolidate" routine 436 437 ! Wavenumber range for each band, in cm-1, which will be allocated 438 ! to be of length n_bands_sw or n_bands_lw 439 real(jprb), allocatable, dimension(:) :: wavenumber1_sw 440 real(jprb), allocatable, dimension(:) :: wavenumber2_sw 441 real(jprb), allocatable, dimension(:) :: wavenumber1_lw 442 real(jprb), allocatable, dimension(:) :: wavenumber2_lw 492 ! Fraction of each g point in each wavenumber interval, 493 ! dimensioned (n_wav_frac_[l|s]w, n_g_[l|s]w) 494 real(jprb), allocatable, dimension(:,:) :: g_frac_sw, g_frac_lw 443 495 444 496 ! If the nearest surface albedo/emissivity interval is to be used … … 490 542 integer :: n_canopy_bands_lw = 1 491 543 544 ! Data structures containing gas optics description in the case of 545 ! ecCKD 546 type(ckd_model_type) :: gas_optics_sw, gas_optics_lw 547 492 548 ! Data structure containing cloud scattering data 493 549 type(cloud_optics_type) :: cloud_optics 550 551 ! Number of general cloud types, default liquid and ice 552 integer :: n_cloud_types = 2 553 554 ! List of data structures (one per cloud type) containing cloud 555 ! scattering data 556 type(general_cloud_optics_type), allocatable :: cloud_optics_sw(:) 557 type(general_cloud_optics_type), allocatable :: cloud_optics_lw(:) 494 558 495 559 ! Data structure containing aerosol scattering data … … 502 566 character(len=511) :: ice_optics_file_name, & 503 567 & liq_optics_file_name, & 504 & aerosol_optics_file_name 568 & aerosol_optics_file_name, & 569 & gas_optics_sw_file_name, & 570 & gas_optics_lw_file_name 505 571 506 572 ! McICA PDF look-up table file name … … 515 581 ! g points or the number of bands 516 582 integer :: n_spec_sw = 0, n_spec_lw = 0 583 584 ! Number of wavenumber intervals used to describe the mapping from 585 ! g-points to wavenumber space 586 integer :: n_wav_frac_sw = 0, n_wav_frac_lw = 0 517 587 518 588 ! Dimensions to store variables that are only needed if longwave … … 539 609 procedure :: define_sw_albedo_intervals 540 610 procedure :: define_lw_emiss_intervals 541 procedure :: consolidate_intervals 611 procedure :: set_aerosol_wavelength_mono 612 procedure :: consolidate_sw_albedo_intervals 613 procedure :: consolidate_lw_emiss_intervals 542 614 543 615 end type config_type … … 574 646 logical :: do_sw, do_lw, do_clear, do_sw_direct 575 647 logical :: do_3d_effects, use_expm_everywhere, use_aerosols 648 logical :: use_general_cloud_optics, use_general_aerosol_optics 576 649 logical :: do_lw_side_emissivity 577 650 logical :: do_3d_lw_multilayer_effects, do_fu_lw_ice_optics_bug … … 579 652 logical :: do_save_radiative_properties, do_save_spectral_flux 580 653 logical :: do_save_gpoint_flux, do_surface_sw_spectral_flux 581 logical :: use_beta_overlap, do_lw_derivatives 654 logical :: use_beta_overlap, do_lw_derivatives, use_vectorizable_generator 582 655 logical :: do_sw_delta_scaling_with_gases 583 656 logical :: do_canopy_fluxes_sw, do_canopy_fluxes_lw 584 657 logical :: use_canopy_full_spectrum_sw, use_canopy_full_spectrum_lw 585 658 logical :: do_canopy_gases_sw, do_canopy_gases_lw 659 logical :: do_cloud_aerosol_per_sw_g_point, do_cloud_aerosol_per_lw_g_point 660 logical :: do_weighted_surface_mapping 586 661 integer :: n_regions, iverbose, iverbosesetup, n_aerosol_types 587 662 real(jprb):: mono_lw_wavelength, mono_lw_total_od, mono_sw_total_od … … 596 671 character(511) :: liq_optics_override_file_name, ice_optics_override_file_name 597 672 character(511) :: cloud_pdf_override_file_name 673 character(511) :: gas_optics_sw_override_file_name, gas_optics_lw_override_file_name 598 674 character(63) :: liquid_model_name, ice_model_name, gas_model_name 599 675 character(63) :: sw_solver_name, lw_solver_name, overlap_scheme_name 600 676 character(63) :: sw_entrapment_name, sw_encroachment_name, cloud_pdf_shape_name 677 character(len=511) :: cloud_type_name(NMaxCloudTypes) = ["","","","","","","","","","","",""] 678 logical :: use_thick_cloud_spectral_averaging(NMaxCloudTypes) & 679 & = [.false.,.false.,.false.,.false.,.false.,.false., & 680 & .false.,.false.,.false.,.false.,.false.,.false.] 601 681 integer :: i_aerosol_type_map(NMaxAerosolTypes) ! More than 256 is an error 602 682 603 logical :: do_nearest_spectral_sw_albedo = .true.604 logical :: do_nearest_spectral_lw_emiss = .true.683 logical :: do_nearest_spectral_sw_albedo 684 logical :: do_nearest_spectral_lw_emiss 605 685 real(jprb) :: sw_albedo_wavelength_bound(NMaxAlbedoIntervals-1) 606 686 real(jprb) :: lw_emiss_wavelength_bound( NMaxAlbedoIntervals-1) … … 609 689 610 690 integer :: iunit ! Unit number of namelist file 611 612 logical :: lldeb_conf = .false.613 691 614 692 namelist /radiation/ do_sw, do_lw, do_sw_direct, & … … 622 700 & ice_optics_override_file_name, liq_optics_override_file_name, & 623 701 & aerosol_optics_override_file_name, cloud_pdf_override_file_name, & 702 & gas_optics_sw_override_file_name, gas_optics_lw_override_file_name, & 624 703 & liquid_model_name, ice_model_name, max_3d_transfer_rate, & 625 704 & min_cloud_effective_size, overhang_factor, encroachment_scaling, & … … 627 706 & do_canopy_fluxes_sw, do_canopy_fluxes_lw, & 628 707 & do_canopy_gases_sw, do_canopy_gases_lw, & 708 & use_general_cloud_optics, use_general_aerosol_optics, & 629 709 & do_sw_delta_scaling_with_gases, overlap_scheme_name, & 630 & sw_solver_name, lw_solver_name, use_beta_overlap, &710 & sw_solver_name, lw_solver_name, use_beta_overlap, use_vectorizable_generator, & 631 711 & use_expm_everywhere, iverbose, iverbosesetup, & 632 712 & cloud_inhom_decorr_scaling, cloud_fraction_threshold, & … … 637 717 & mono_lw_single_scattering_albedo, mono_sw_single_scattering_albedo, & 638 718 & mono_lw_asymmetry_factor, mono_sw_asymmetry_factor, & 639 & cloud_pdf_shape_name, &719 & cloud_pdf_shape_name, cloud_type_name, use_thick_cloud_spectral_averaging, & 640 720 & do_nearest_spectral_sw_albedo, do_nearest_spectral_lw_emiss, & 641 721 & sw_albedo_wavelength_bound, lw_emiss_wavelength_bound, & 642 & i_sw_albedo_index, i_lw_emiss_index 643 722 & i_sw_albedo_index, i_lw_emiss_index, & 723 & do_cloud_aerosol_per_lw_g_point, & 724 & do_cloud_aerosol_per_sw_g_point, do_weighted_surface_mapping 725 644 726 real(jprb) :: hook_handle 645 727 … … 670 752 ice_optics_override_file_name = this%ice_optics_override_file_name 671 753 aerosol_optics_override_file_name = this%aerosol_optics_override_file_name 754 gas_optics_sw_override_file_name = this%gas_optics_sw_override_file_name 755 gas_optics_lw_override_file_name = this%gas_optics_lw_override_file_name 672 756 use_expm_everywhere = this%use_expm_everywhere 673 757 use_aerosols = this%use_aerosols … … 679 763 iverbose = this%iverbose 680 764 iverbosesetup = this%iverbosesetup 765 use_general_cloud_optics = this%use_general_cloud_optics 766 use_general_aerosol_optics = this%use_general_aerosol_optics 681 767 cloud_fraction_threshold = this%cloud_fraction_threshold 682 768 cloud_mixing_ratio_threshold = this%cloud_mixing_ratio_threshold 683 769 use_beta_overlap = this%use_beta_overlap 770 use_vectorizable_generator = this%use_vectorizable_generator 684 771 cloud_inhom_decorr_scaling = this%cloud_inhom_decorr_scaling 685 772 clear_to_thick_fraction = this%clear_to_thick_fraction … … 689 776 max_3d_transfer_rate = this%max_3d_transfer_rate 690 777 min_cloud_effective_size = this%min_cloud_effective_size 778 cloud_type_name = this%cloud_type_name 779 use_thick_cloud_spectral_averaging = this%use_thick_cloud_spectral_averaging 780 691 781 overhang_factor = this%overhang_factor 692 782 encroachment_scaling = -1.0_jprb … … 715 805 i_sw_albedo_index = this%i_sw_albedo_index 716 806 i_lw_emiss_index = this%i_lw_emiss_index 807 do_cloud_aerosol_per_lw_g_point = this%do_cloud_aerosol_per_lw_g_point 808 do_cloud_aerosol_per_sw_g_point = this%do_cloud_aerosol_per_sw_g_point 809 do_weighted_surface_mapping = this%do_weighted_surface_mapping 717 810 718 811 if (present(file_name) .and. present(unit)) then … … 746 839 end if 747 840 else 841 842 ! This version exits correctly, but provides less information 843 ! about how the namelist was incorrect 748 844 read(unit=iunit, iostat=iosread, nml=radiation) 845 846 ! Depending on compiler this version provides more information 847 ! about the error in the namelist 848 !read(unit=iunit, nml=radiation) 849 749 850 if (iosread /= 0) then 750 851 ! An error occurred reading the file … … 812 913 this%mono_sw_asymmetry_factor = mono_sw_asymmetry_factor 813 914 this%use_beta_overlap = use_beta_overlap 915 this%use_vectorizable_generator = use_vectorizable_generator 814 916 this%cloud_inhom_decorr_scaling = cloud_inhom_decorr_scaling 815 917 this%clear_to_thick_fraction = clear_to_thick_fraction … … 819 921 this%max_3d_transfer_rate = max_3d_transfer_rate 820 922 this%min_cloud_effective_size = max(1.0e-6_jprb, min_cloud_effective_size) 923 this%cloud_type_name = cloud_type_name 924 this%use_thick_cloud_spectral_averaging = use_thick_cloud_spectral_averaging 821 925 if (encroachment_scaling >= 0.0_jprb) then 822 926 this%overhang_factor = encroachment_scaling … … 832 936 this%ice_optics_override_file_name = ice_optics_override_file_name 833 937 this%aerosol_optics_override_file_name = aerosol_optics_override_file_name 938 this%gas_optics_sw_override_file_name = gas_optics_sw_override_file_name 939 this%gas_optics_lw_override_file_name = gas_optics_lw_override_file_name 940 this%use_general_cloud_optics = use_general_cloud_optics 941 this%use_general_aerosol_optics = use_general_aerosol_optics 834 942 this%cloud_fraction_threshold = cloud_fraction_threshold 835 943 this%cloud_mixing_ratio_threshold = cloud_mixing_ratio_threshold … … 845 953 this%i_sw_albedo_index = i_sw_albedo_index 846 954 this%i_lw_emiss_index = i_lw_emiss_index 847 848 ! AI mars 2022 849 if (lldeb_conf) then 850 print*,'**************PARAMETRES DE CONFIGURATION OFFLINE*******************' 851 print*,'config%iverbosesetup = ', iverbosesetup 852 print*,'config%do_lw = ', do_lw 853 print*,'config%do_sw = ', do_sw 854 print*,'config%do_clear = ', do_clear 855 print*,'config%do_sw_direct = ', do_sw_direct 856 print*,'config%do_3d_effects = ', do_3d_effects 857 print*,'config%do_3d_lw_multilayer_effects = ', do_3d_lw_multilayer_effects 858 print*,'config%do_lw_side_emissivity = ', do_lw_side_emissivity 859 print*,'config%use_expm_everywhere = ', use_expm_everywhere 860 print*,'config%use_aerosols = ', use_aerosols 861 print*,'config%do_lw_cloud_scattering = ', do_lw_cloud_scattering 862 print*,'config%do_lw_aerosol_scattering = ', do_lw_aerosol_scattering 863 print*,'config%nregions = ', n_regions 864 print*,'config%do_surface_sw_spectral_flux = ', do_surface_sw_spectral_flux 865 print*,'config%do_sw_delta_scaling_with_gases = ', & 866 do_sw_delta_scaling_with_gases 867 print*,'config%do_fu_lw_ice_optics_bug = ', do_fu_lw_ice_optics_bug 868 print*,'config%do_canopy_fluxes_sw = ', do_canopy_fluxes_sw 869 print*,'config%do_canopy_fluxes_lw = ', do_canopy_fluxes_lw 870 print*,'config%use_canopy_full_spectrum_sw = ', use_canopy_full_spectrum_sw 871 print*,'config%use_canopy_full_spectrum_lw = ', use_canopy_full_spectrum_lw 872 print*,'config%do_canopy_gases_sw = ', do_canopy_gases_sw 873 print*,'config%do_canopy_gases_lw = ', do_canopy_gases_lw 874 print*,'config%mono_lw_wavelength = ', mono_lw_wavelength 875 print*,'config%mono_lw_total_od = ', mono_lw_total_od 876 print*,'config%mono_sw_total_od = ', mono_sw_total_od 877 print*,'config%mono_lw_single_scattering_albedo = ', & 878 mono_lw_single_scattering_albedo 879 print*,'config%mono_sw_single_scattering_albedo = ', & 880 mono_sw_single_scattering_albedo 881 print*,'config%mono_lw_asymmetry_factor = ', mono_lw_asymmetry_factor 882 print*,'config%mono_sw_asymmetry_factor = ', mono_sw_asymmetry_factor 883 print*,'config%use_beta_overlap = ', use_beta_overlap 884 print*,'config%cloud_inhom_decorr_scaling = ', cloud_inhom_decorr_scaling 885 print*,'config%clear_to_thick_fraction = ', clear_to_thick_fraction 886 print*,'config%overhead_sun_factor = ', overhead_sun_factor 887 print*,'config%max_gas_od_3d = ', max_gas_od_3d 888 print*,'config%max_cloud_od = ', max_cloud_od 889 print*,'config%max_3d_transfer_rate = ', max_3d_transfer_rate 890 print*,'config%min_cloud_effective_size = ', & 891 max(1.0e-6_jprb,min_cloud_effective_size) 892 print*,'config%overhang_factor = ', encroachment_scaling 893 894 print*,'config%directory_name = ',directory_name 895 print*,'config%cloud_pdf_override_file_name = ',cloud_pdf_override_file_name 896 print*,'config%liq_optics_override_file_name = ',liq_optics_override_file_name 897 print*,'config%ice_optics_override_file_name = ',ice_optics_override_file_name 898 print*,'config%aerosol_optics_override_file_name = ', & 899 aerosol_optics_override_file_name 900 print*,'config%cloud_fraction_threshold = ',cloud_fraction_threshold 901 print*,'config%cloud_mixing_ratio_threshold = ',cloud_mixing_ratio_threshold 902 print*,'config%n_aerosol_types = ',n_aerosol_types 903 print*,'config%do_save_radiative_properties = ',do_save_radiative_properties 904 print*,'config%do_lw_derivatives = ',do_lw_derivatives 905 print*,'config%do_save_spectral_flux = ',do_save_spectral_flux 906 print*,'config%do_save_gpoint_flux = ',do_save_gpoint_flux 907 print*,'config%do_nearest_spectral_sw_albedo = ',do_nearest_spectral_sw_albedo 908 print*,'config%do_nearest_spectral_lw_emiss = ',do_nearest_spectral_lw_emiss 909 print*,'config%sw_albedo_wavelength_bound = ',sw_albedo_wavelength_bound 910 print*,'config%lw_emiss_wavelength_bound = ',lw_emiss_wavelength_bound 911 print*,'config%i_sw_albedo_index = ',i_sw_albedo_index 912 print*,'config%i_lw_emiss_index = ',i_lw_emiss_index 913 print*,'************************************************************************' 914 endif 955 this%do_cloud_aerosol_per_lw_g_point = do_cloud_aerosol_per_lw_g_point 956 this%do_cloud_aerosol_per_sw_g_point = do_cloud_aerosol_per_sw_g_point 957 this%do_weighted_surface_mapping = do_weighted_surface_mapping 958 915 959 if (do_save_gpoint_flux) then 916 960 ! Saving the fluxes every g-point overrides saving as averaged … … 919 963 ! save anything 920 964 this%do_save_spectral_flux = .true. 921 print*,'config%do_save_spectral_flux = .true.'922 965 end if 923 966 … … 925 968 call get_enum_code(liquid_model_name, LiquidModelName, & 926 969 & 'liquid_model_name', this%i_liq_model) 927 print*,'config%i_liq_model =', this%i_liq_model928 970 929 971 ! Determine ice optics model 930 972 call get_enum_code(ice_model_name, IceModelName, & 931 973 & 'ice_model_name', this%i_ice_model) 932 print*,'config%i_ice_model =', this%i_ice_model 974 933 975 ! Determine gas optics model 934 976 call get_enum_code(gas_model_name, GasModelName, & 935 977 & 'gas_model_name', this%i_gas_model) 936 print*,'config%%i_gas_model = ', this%i_gas_model937 978 938 979 ! Determine solvers 939 980 call get_enum_code(sw_solver_name, SolverName, & 940 981 & 'sw_solver_name', this%i_solver_sw) 941 print*,'config%i_solver_sw = ', this%i_solver_sw942 982 call get_enum_code(lw_solver_name, SolverName, & 943 983 & 'lw_solver_name', this%i_solver_lw) 944 print*,'config%i_solver_lw = ', this%i_solver_lw 984 945 985 if (len_trim(sw_encroachment_name) > 1) then 946 986 call get_enum_code(sw_encroachment_name, EncroachmentName, & … … 950 990 call get_enum_code(sw_entrapment_name, EntrapmentName, & 951 991 & 'sw_entrapment_name', this%i_3d_sw_entrapment) 952 print*,'config%i_3d_sw_entrapment = ', this%i_3d_sw_entrapment953 992 end if 954 993 … … 956 995 call get_enum_code(overlap_scheme_name, OverlapName, & 957 996 & 'overlap_scheme_name', this%i_overlap_scheme) 958 print*,'config%i_overlap_scheme = ', this%i_overlap_scheme997 959 998 ! Determine cloud PDF shape 960 999 call get_enum_code(cloud_pdf_shape_name, PdfShapeName, & 961 1000 & 'cloud_pdf_shape_name', this%i_cloud_pdf_shape) 962 print*,'config%i_cloud_pdf_shape = ', this%i_cloud_pdf_shape 1001 963 1002 this%i_aerosol_type_map = 0 964 1003 if (this%use_aerosols) then 965 1004 this%i_aerosol_type_map(1:n_aerosol_types) & 966 1005 & = i_aerosol_type_map(1:n_aerosol_types) 967 print*,'config%i_aerosol_type_map = ', this%i_aerosol_type_map968 1006 end if 969 1007 … … 975 1013 this%do_clouds = .false. 976 1014 end if 977 print*,'config%do_clouds = ', this%do_clouds 1015 1016 if (this%i_gas_model == IGasModelIFSRRTMG & 1017 & .and. (this%use_general_cloud_optics & 1018 & .or. this%use_general_aerosol_optics)) then 1019 if (this%do_sw .and. this%do_cloud_aerosol_per_sw_g_point) then 1020 write(nulout,'(a)') 'Warning: RRTMG SW only supports cloud/aerosol/surface optical properties per band, not per g-point' 1021 this%do_cloud_aerosol_per_sw_g_point = .false. 1022 end if 1023 if (this%do_lw .and. this%do_cloud_aerosol_per_lw_g_point) then 1024 write(nulout,'(a)') 'Warning: RRTMG LW only supports cloud/aerosol/surface optical properties per band, not per g-point' 1025 this%do_cloud_aerosol_per_lw_g_point = .false. 1026 end if 1027 end if 1028 978 1029 979 1030 ! Normal subroutine exit … … 993 1044 subroutine consolidate_config(this) 994 1045 1046 use parkind1, only : jprd 995 1047 use yomhook, only : lhook, dr_hook 996 1048 use radiation_io, only : nulout, nulerr, radiation_abort … … 1026 1078 write(nulerr,'(a)') '*** Error: SPARTACUS/Tripleclouds solvers can only do Exponential-Random overlap' 1027 1079 call radiation_abort('Radiation configuration error') 1080 end if 1081 1082 if (jprb < jprd .and. this%iverbosesetup >= 1 & 1083 & .and. (this%i_solver_sw == ISolverSPARTACUS & 1084 & .or. this%i_solver_lw == ISolverSPARTACUS)) then 1085 write(nulout,'(a)') 'Warning: the SPARTACUS solver may be unstable in single precision' 1086 end if 1087 1088 ! If ecCKD gas optics model is being used set relevant file names 1089 if (this%i_gas_model == IGasModelECCKD) then 1090 1091 ! This gas optics model requires the general cloud and 1092 ! aerosol optics settings 1093 if (.not. this%use_general_cloud_optics) then 1094 write(nulerr,'(a)') '*** Error: ecCKD gas optics model requires general cloud optics' 1095 call radiation_abort('Radiation configuration error') 1096 end if 1097 if (.not. this%use_general_aerosol_optics) then 1098 write(nulerr,'(a)') '*** Error: ecCKD gas optics model requires general aerosol optics' 1099 call radiation_abort('Radiation configuration error') 1100 end if 1101 1102 if (len_trim(this%gas_optics_sw_override_file_name) > 0) then 1103 if (this%gas_optics_sw_override_file_name(1:1) == '/') then 1104 this%gas_optics_sw_file_name = trim(this%gas_optics_sw_override_file_name) 1105 else 1106 this%gas_optics_sw_file_name = trim(this%directory_name) & 1107 & // '/' // trim(this%gas_optics_sw_override_file_name) 1108 end if 1109 else 1110 ! In the IFS, the gas optics files should be specified in 1111 ! ifs/module/radiation_setup.F90, not here 1112 this%gas_optics_sw_file_name = trim(this%directory_name) & 1113 & // "/ecckd-1.0_sw_climate_rgb-32b_ckd-definition.nc" 1114 end if 1115 1116 if (len_trim(this%gas_optics_lw_override_file_name) > 0) then 1117 if (this%gas_optics_lw_override_file_name(1:1) == '/') then 1118 this%gas_optics_lw_file_name = trim(this%gas_optics_lw_override_file_name) 1119 else 1120 this%gas_optics_lw_file_name = trim(this%directory_name) & 1121 & // '/' // trim(this%gas_optics_lw_override_file_name) 1122 end if 1123 else 1124 ! In the IFS, the gas optics files should be specified in 1125 ! ifs/module/radiation_setup.F90, not here 1126 this%gas_optics_lw_file_name = trim(this%directory_name) & 1127 & // "/ecckd-1.0_lw_climate_fsck-32b_ckd-definition.nc" 1128 end if 1028 1129 1029 1130 end if … … 1040 1141 ! In the IFS, the aerosol optics file should be specified in 1041 1142 ! ifs/module/radiation_setup.F90, not here 1042 this%aerosol_optics_file_name & 1043 & = trim(this%directory_name) // "/aerosol_ifs_rrtm_45R2.nc" 1143 if (this%use_general_aerosol_optics) then 1144 this%aerosol_optics_file_name & 1145 & = trim(this%directory_name) // "/aerosol_ifs_48R1.nc" 1146 else 1147 this%aerosol_optics_file_name & 1148 & = trim(this%directory_name) // "/aerosol_ifs_rrtm_46R1_with_NI_AM.nc" 1149 end if 1044 1150 end if 1045 1151 … … 1229 1335 & this%i_gas_model) 1230 1336 call print_logical(' Aerosols are', 'use_aerosols', this%use_aerosols) 1231 call print_logical(' Clouds are', 'do_clouds', this%do_clouds) 1337 if (this%use_aerosols) then 1338 call print_logical(' General aerosol optics', & 1339 & 'use_general_aerosol_optics', this%use_general_aerosol_optics) 1340 end if 1341 if (this%do_clouds) then 1342 write(nulout,'(a)') ' Clouds are ON' 1343 else 1344 write(nulout,'(a)') ' Clouds are OFF' 1345 end if 1346 if (this%do_sw) then 1347 call print_logical(' Do cloud/aerosol/surface SW properties per g-point', & 1348 & 'do_cloud_aerosol_per_sw_g_point', this%do_cloud_aerosol_per_sw_g_point) 1349 end if 1350 if (this%do_lw) then 1351 call print_logical(' Do cloud/aerosol/surface LW properties per g-point', & 1352 & 'do_cloud_aerosol_per_lw_g_point', this%do_cloud_aerosol_per_lw_g_point) 1353 end if 1232 1354 1233 1355 !--------------------------------------------------------------------- … … 1253 1375 & 'do_nearest_spectral_lw_emiss', this%do_nearest_spectral_lw_emiss) 1254 1376 end if 1377 call print_logical(' Planck-weighted surface albedo/emiss mapping', & 1378 & 'do_weighted_surface_mapping', this%do_weighted_surface_mapping) 1379 1255 1380 !--------------------------------------------------------------------- 1256 1381 if (this%do_clouds) then … … 1260 1385 call print_real(' Cloud mixing-ratio threshold', & 1261 1386 & 'cloud_mixing_ratio_threshold', this%cloud_mixing_ratio_threshold) 1262 call print_enum(' Liquid optics scheme is', LiquidModelName, & 1263 & 'i_liq_model',this%i_liq_model) 1264 call print_enum(' Ice optics scheme is', IceModelName, & 1265 & 'i_ice_model',this%i_ice_model) 1266 if (this%i_ice_model == IIceModelFu) then 1267 call print_logical(' Longwave ice optics bug in Fu scheme is', & 1268 & 'do_fu_lw_ice_optics_bug',this%do_fu_lw_ice_optics_bug) 1387 call print_logical(' General cloud optics', & 1388 & 'use_general_cloud_optics', this%use_general_cloud_optics) 1389 if (.not. this%use_general_cloud_optics) then 1390 call print_enum(' Liquid optics scheme is', LiquidModelName, & 1391 & 'i_liq_model',this%i_liq_model) 1392 call print_enum(' Ice optics scheme is', IceModelName, & 1393 & 'i_ice_model',this%i_ice_model) 1394 if (this%i_ice_model == IIceModelFu) then 1395 call print_logical(' Longwave ice optics bug in Fu scheme is', & 1396 & 'do_fu_lw_ice_optics_bug',this%do_fu_lw_ice_optics_bug) 1397 end if 1269 1398 end if 1270 1399 call print_enum(' Cloud overlap scheme is', OverlapName, & … … 1360 1489 & 'overhang_factor', this%overhang_factor) 1361 1490 end if 1491 1492 else if (this%i_solver_sw == ISolverMcICA & 1493 & .or. this%i_solver_lw == ISolverMcICA) then 1494 call print_logical(' Use vectorizable McICA cloud generator', & 1495 & 'use_vectorizable_generator', this%use_vectorizable_generator) 1362 1496 end if 1363 1497 … … 1383 1517 use parkind1, only : jprb 1384 1518 use radiation_io, only : nulout, nulerr, radiation_abort 1519 use radiation_spectral_definition, only : SolarReferenceTemperature 1385 1520 1386 1521 class(config_type), intent(in) :: this … … 1396 1531 character(len=*), optional, intent(in) :: weighting_name 1397 1532 1533 real(jprb), allocatable :: mapping(:,:) 1534 1398 1535 ! Internally we deal with wavenumber 1399 1536 real(jprb) :: wavenumber1, wavenumber2 ! cm-1 1400 1537 1538 real(jprb) :: wavenumber1_band, wavenumber2_band ! cm-1 1539 1401 1540 integer :: jband ! Loop index for spectral band 1402 1541 1403 1542 if (this%n_bands_sw <= 0) then 1404 1543 write(nulerr,'(a)') '*** Error: get_sw_weights called before number of shortwave bands set' 1405 call radiation_abort( )1544 call radiation_abort('Radiation configuration error') 1406 1545 end if 1407 1546 … … 1410 1549 wavenumber2 = 0.01_jprb / wavelength1 1411 1550 1551 call this%gas_optics_sw%spectral_def%calc_mapping_from_bands(SolarReferenceTemperature, & 1552 & [wavelength1, wavelength2], [1, 2, 3], mapping, & 1553 & use_bands=(.not. this%do_cloud_aerosol_per_sw_g_point), use_fluxes=.true.) 1554 1555 ! "mapping" now contains a 3*nband matrix, where mapping(2,:) 1556 ! contains the weights of interest. We now find the non-zero weights 1412 1557 nweights = 0 1413 1414 do jband = 1,this%n_bands_sw 1415 if (wavenumber1 < this%wavenumber2_sw(jband) & 1416 & .and. wavenumber2 > this%wavenumber1_sw(jband)) then 1558 do jband = 1,size(mapping,2) 1559 if (mapping(2,jband) > 0.0_jprb) then 1417 1560 nweights = nweights+1 1418 iband(nweights) = jband 1419 weight(nweights) = (min(wavenumber2,this%wavenumber2_sw(jband)) & 1420 & - max(wavenumber1,this%wavenumber1_sw(jband))) & 1421 & / (this%wavenumber2_sw(jband) - this%wavenumber1_sw(jband)) 1561 iband(nweights) = jband; 1562 weight(nweights) = mapping(2,jband) 1422 1563 end if 1423 1564 end do … … 1426 1567 write(nulerr,'(a,e8.4,a,e8.4,a)') '*** Error: wavelength range ', & 1427 1568 & wavelength1, ' to ', wavelength2, ' m is outside shortwave band' 1428 call radiation_abort( )1569 call radiation_abort('Radiation configuration error') 1429 1570 else if (this%iverbosesetup >= 2 .and. present(weighting_name)) then 1430 1571 write(nulout,'(a,a,a,f6.0,a,f6.0,a)') 'Spectral weights for ', & 1431 1572 & weighting_name, ' (', wavenumber1, ' to ', & 1432 1573 & wavenumber2, ' cm-1):' 1433 do jband = 1, nweights 1434 write(nulout, '(a,i0,a,f6.0,a,f6.0,a,f8.4)') ' Shortwave band ', & 1435 & iband(jband), ' (', this%wavenumber1_sw(iband(jband)), ' to ', & 1436 & this%wavenumber2_sw(iband(jband)), ' cm-1): ', weight(jband) 1437 end do 1574 if (this%do_cloud_aerosol_per_sw_g_point) then 1575 do jband = 1, nweights 1576 write(nulout, '(a,i0,a,f8.4)') ' Shortwave g point ', iband(jband), ': ', weight(jband) 1577 end do 1578 else 1579 do jband = 1, nweights 1580 wavenumber1_band = this%gas_optics_sw%spectral_def%wavenumber1_band(iband(jband)) 1581 wavenumber2_band = this%gas_optics_sw%spectral_def%wavenumber2_band(iband(jband)) 1582 write(nulout, '(a,i0,a,f6.0,a,f6.0,a,f8.4)') ' Shortwave band ', & 1583 & iband(jband), ' (', wavenumber1_band, ' to ', & 1584 & wavenumber2_band, ' cm-1): ', weight(jband) 1585 end do 1586 end if 1438 1587 end if 1439 1588 … … 1452 1601 1453 1602 use radiation_io, only : nulerr, radiation_abort 1603 use radiation_spectral_definition, only : SolarReferenceTemperature 1454 1604 1455 1605 class(config_type), intent(inout) :: this … … 1467 1617 write(nulerr,'(a,i0,a,i0)') '*** Error: ', ninterval, & 1468 1618 & ' albedo intervals exceeds maximum of ', NMaxAlbedoIntervals 1469 call radiation_abort( );1619 call radiation_abort('Radiation configuration error') 1470 1620 end if 1471 1621 … … 1480 1630 this%i_sw_albedo_index(ninterval+1:) = 0 1481 1631 1632 ! If this routine is called before setup_radiation then the 1633 ! spectral intervals are not yet known 1634 ! consolidate_sw_albedo_intervals is called later. Otherwise it 1635 ! is called immediately and overwrites any existing mapping. 1482 1636 if (this%is_consolidated) then 1483 call this%consolidate_intervals(.true., & 1484 & this%do_nearest_spectral_sw_albedo, & 1485 & this%sw_albedo_wavelength_bound, this%i_sw_albedo_index, & 1486 & this%wavenumber1_sw, this%wavenumber2_sw, & 1487 & this%i_albedo_from_band_sw, this%sw_albedo_weights) 1637 call this%consolidate_sw_albedo_intervals 1488 1638 end if 1489 1639 … … 1497 1647 1498 1648 use radiation_io, only : nulerr, radiation_abort 1649 use radiation_spectral_definition, only : TerrestrialReferenceTemperature 1499 1650 1500 1651 class(config_type), intent(inout) :: this … … 1512 1663 write(nulerr,'(a,i0,a,i0)') '*** Error: ', ninterval, & 1513 1664 & ' emissivity intervals exceeds maximum of ', NMaxAlbedoIntervals 1514 call radiation_abort( );1665 call radiation_abort('Radiation configuration error') 1515 1666 end if 1516 1667 … … 1526 1677 1527 1678 if (this%is_consolidated) then 1528 call this%consolidate_intervals(.false., & 1529 & this%do_nearest_spectral_lw_emiss, & 1530 & this%lw_emiss_wavelength_bound, this%i_lw_emiss_index, & 1531 & this%wavenumber1_lw, this%wavenumber2_lw, & 1532 & this%i_emiss_from_band_lw, this%lw_emiss_weights) 1679 call this%consolidate_lw_emiss_intervals 1533 1680 end if 1534 1681 … … 1537 1684 1538 1685 !--------------------------------------------------------------------- 1539 ! This routine consolidates either the input shortwave albedo 1540 ! intervals with the shortwave bands, or the input longwave 1541 ! emissivity intervals with the longwave bands, depending on the 1542 ! arguments provided. 1543 subroutine consolidate_intervals(this, is_sw, do_nearest, & 1544 & wavelength_bound, i_intervals, wavenumber1, wavenumber2, & 1545 & i_mapping, weights) 1546 1547 use radiation_io, only : nulout, nulerr, radiation_abort 1686 ! Set the wavelengths (m) at which monochromatic aerosol properties 1687 ! are required. This routine must be called before consolidation of 1688 ! settings. 1689 subroutine set_aerosol_wavelength_mono(this, wavelength_mono) 1690 1691 use radiation_io, only : nulerr, radiation_abort 1692 1693 class(config_type), intent(inout) :: this 1694 real(jprb), intent(in) :: wavelength_mono(:) 1695 1696 if (this%is_consolidated) then 1697 write(nulerr,'(a)') '*** Errror: set_aerosol_wavelength_mono must be called before setup_radiation' 1698 call radiation_abort('Radiation configuration error') 1699 end if 1700 1701 if (allocated(this%aerosol_optics%wavelength_mono)) then 1702 deallocate(this%aerosol_optics%wavelength_mono) 1703 end if 1704 allocate(this%aerosol_optics%wavelength_mono(size(wavelength_mono))) 1705 this%aerosol_optics%wavelength_mono = wavelength_mono 1706 1707 end subroutine set_aerosol_wavelength_mono 1708 1709 1710 !--------------------------------------------------------------------- 1711 ! Consolidate the surface shortwave albedo intervals with the 1712 ! band/g-point intervals 1713 subroutine consolidate_sw_albedo_intervals(this) 1714 1715 use radiation_io, only : nulout 1716 use radiation_spectral_definition, only : SolarReferenceTemperature 1548 1717 1549 1718 class(config_type), intent(inout) :: this 1550 ! Is this the shortwave? Otherwise longwave 1551 logical, intent(in) :: is_sw 1552 ! Do we find the nearest albedo interval to the centre of each 1553 ! band, or properly weight the contributions? This can be modified 1554 ! if there is only one albedo intervals. 1555 logical, intent(inout) :: do_nearest 1556 ! Monotonically increasing wavelength bounds between intervals, 1557 ! not including the outer bounds (which are assumed to be zero and 1558 ! infinity) 1559 real(jprb), intent(in) :: wavelength_bound(NMaxAlbedoIntervals-1) 1560 ! The albedo band indices corresponding to each interval 1561 integer, intent(in) :: i_intervals(NMaxAlbedoIntervals) 1562 ! Start and end wavenumber bounds for the ecRad bands (cm-1) 1563 real(jprb), intent(in) :: wavenumber1(:), wavenumber2(:) 1564 1565 ! if do_nearest is TRUE then the result is expressed in i_mapping, 1566 ! which will be allocated to have the same length as wavenumber1, 1567 ! and contain the index of the albedo interval corresponding to 1568 ! that band 1569 integer, allocatable, intent(inout) :: i_mapping(:) 1570 ! ...otherwise the result is expressed in "weights", of 1571 ! size(n_intervals, n_bands) containing how much of each interval 1572 ! contributes to each band. 1573 real(jprb), allocatable, intent(inout) :: weights(:,:) 1574 1575 ! Number and loop index of ecRad bands 1576 integer :: nband, jband 1577 ! Number and index of albedo/emissivity intervals 1578 integer :: ninterval, iinterval 1579 ! Sometimes an albedo or emissivity value will be used in more 1580 ! than one interval, so nvalue indicates how many values will 1581 ! actually be provided 1582 integer :: nvalue 1583 ! Wavenumber bounds of the albedo/emissivity interval 1584 real(jprb) :: wavenumber1_albedo, wavenumber2_albedo 1585 ! Reciprocal of the wavenumber range of the ecRad band 1586 real(jprb) :: recip_dwavenumber ! cm 1587 ! Midpoint/bound of wavenumber band 1588 real(jprb) :: wavenumber_mid, wavenumber_bound ! cm-1 1589 1590 nband = size(wavenumber1) 1719 1720 integer :: ninterval, jint, jband 1591 1721 1592 1722 ! Count the number of albedo/emissivity intervals 1593 1723 ninterval = 0 1594 do iinterval= 1,NMaxAlbedoIntervals1595 if ( i_intervals(iinterval) > 0) then1596 ninterval = iinterval1724 do jint = 1,NMaxAlbedoIntervals 1725 if (this%i_sw_albedo_index(jint) > 0) then 1726 ninterval = jint 1597 1727 else 1598 1728 exit … … 1600 1730 end do 1601 1731 1602 if (ninterval < 2) then 1603 ! Zero or one albedo/emissivity intervals found, so we index all 1604 ! bands to one interval 1605 if (allocated(i_mapping)) then 1606 deallocate(i_mapping) 1607 end if 1608 allocate(i_mapping(nband)) 1609 i_mapping(:) = 1 1610 do_nearest = .true. 1732 if (ninterval < 1) then 1733 ! The user has not specified shortwave albedo bands - assume 1734 ! only one 1611 1735 ninterval = 1 1612 nvalue = 1 1613 else 1614 ! Check wavelength is monotonically increasing 1615 do jband = 2,ninterval-1 1616 if (wavelength_bound(jband) <= wavelength_bound(jband-1)) then 1617 if (is_sw) then 1618 write(nulerr, '(a,a)') '*** Error: wavelength bounds for shortwave albedo intervals ', & 1619 & 'must be monotonically increasing' 1620 else 1621 write(nulerr, '(a,a)') '*** Error: wavelength bounds for longwave emissivity intervals ', & 1622 & 'must be monotonically increasing' 1623 end if 1624 call radiation_abort() 1625 end if 1626 end do 1627 1628 ! What is the maximum index, indicating the number of 1629 ! albedo/emissivity values to expect? 1630 nvalue = maxval(i_intervals(1:ninterval)) 1631 1632 if (do_nearest) then 1633 ! Simpler nearest-neighbour mapping from band to 1634 ! albedo/emissivity interval 1635 if (allocated(i_mapping)) then 1636 deallocate(i_mapping) 1637 end if 1638 allocate(i_mapping(nband)) 1639 1640 ! Loop over bands 1641 do jband = 1,nband 1642 ! Compute mid-point of band in wavenumber space (cm-1) 1643 wavenumber_mid = 0.5_jprb * (wavenumber1(jband) & 1644 & + wavenumber2(jband)) 1645 iinterval = 1 1646 ! Convert wavelength (m) into wavenumber (cm-1) at the lower 1647 ! bound of the albedo interval 1648 wavenumber_bound = 0.01_jprb / wavelength_bound(iinterval) 1649 ! Find the albedo interval that has the largest overlap with 1650 ! the band; this approach assumes that the albedo intervals 1651 ! are larger than the spectral bands 1652 do while (wavenumber_bound >= wavenumber_mid & 1653 & .and. iinterval < ninterval) 1654 iinterval = iinterval + 1 1655 if (iinterval < ninterval) then 1656 wavenumber_bound = 0.01_jprb / wavelength_bound(iinterval) 1657 else 1658 ! For the last interval there is no lower bound 1659 wavenumber_bound = 0.0_jprb 1660 end if 1661 end do 1662 ! Save the index of the band corresponding to the albedo 1663 ! interval and move onto the next band 1664 i_mapping(jband) = i_intervals(iinterval) 1665 end do 1666 else 1667 ! More accurate weighting 1668 if (allocated(weights)) then 1669 deallocate(weights) 1670 end if 1671 allocate(weights(nvalue,nband)) 1672 weights(:,:) = 0.0_jprb 1673 1674 ! Loop over bands 1675 do jband = 1,nband 1676 recip_dwavenumber = 1.0_jprb / (wavenumber2(jband) & 1677 & - wavenumber1(jband)) 1678 ! Find the first overlapping albedo band 1679 iinterval = 1 1680 ! Convert wavelength (m) into wavenumber (cm-1) at the lower 1681 ! bound (in wavenumber space) of the albedo/emissivty interval 1682 wavenumber1_albedo = 0.01_jprb / wavelength_bound(iinterval) 1683 do while (wavenumber1_albedo >= wavenumber2(jband) & 1684 & .and. iinterval < ninterval) 1685 iinterval = iinterval + 1 1686 wavenumber1_albedo = 0.01_jprb / wavelength_bound(iinterval) 1687 end do 1688 1689 wavenumber2_albedo = wavenumber2(jband) 1690 1691 ! Add all overlapping bands 1692 do while (wavenumber2_albedo > wavenumber1(jband) & 1693 & .and. iinterval <= ninterval) 1694 weights(i_intervals(iinterval),jband) & 1695 & = weights(i_intervals(iinterval),jband) & 1696 & + recip_dwavenumber & 1697 & * (min(wavenumber2_albedo,wavenumber2(jband)) & 1698 & - max(wavenumber1_albedo,wavenumber1(jband))) 1699 wavenumber2_albedo = wavenumber1_albedo 1700 iinterval = iinterval + 1 1701 if (iinterval < ninterval) then 1702 wavenumber1_albedo = 0.01_jprb / wavelength_bound(iinterval) 1703 else 1704 wavenumber1_albedo = 0.0_jprb 1705 end if 1706 end do 1707 end do 1708 end if 1709 end if 1710 1711 ! Define how many bands to use for reporting surface downwelling 1712 ! fluxes for canopy radiation scheme 1713 if (is_sw) then 1736 this%i_sw_albedo_index(1) = 1 1737 this%i_sw_albedo_index(2:) = 0 1714 1738 if (this%use_canopy_full_spectrum_sw) then 1715 1739 this%n_canopy_bands_sw = this%n_g_sw 1716 1740 else 1717 this%n_canopy_bands_sw = nvalue 1741 this%n_canopy_bands_sw = 1 1742 end if 1743 else 1744 if (this%use_canopy_full_spectrum_sw) then 1745 this%n_canopy_bands_sw = this%n_g_sw 1746 else 1747 this%n_canopy_bands_sw = maxval(this%i_sw_albedo_index(1:ninterval)) 1748 end if 1749 end if 1750 1751 if (this%do_weighted_surface_mapping) then 1752 call this%gas_optics_sw%spectral_def%calc_mapping_from_bands(SolarReferenceTemperature, & 1753 & this%sw_albedo_wavelength_bound(1:ninterval-1), this%i_sw_albedo_index(1:ninterval), & 1754 & this%sw_albedo_weights, use_bands=(.not. this%do_cloud_aerosol_per_sw_g_point)) 1755 else 1756 ! Weight each wavenumber equally as in IFS Cycles 48 and earlier 1757 call this%gas_optics_sw%spectral_def%calc_mapping_from_bands(-1.0_jprb, & 1758 & this%sw_albedo_wavelength_bound(1:ninterval-1), this%i_sw_albedo_index(1:ninterval), & 1759 & this%sw_albedo_weights, use_bands=(.not. this%do_cloud_aerosol_per_sw_g_point)) 1760 end if 1761 1762 ! Legacy method uses input band with largest weight 1763 if (this%do_nearest_spectral_sw_albedo) then 1764 allocate(this%i_albedo_from_band_sw(this%n_bands_sw)) 1765 this%i_albedo_from_band_sw = maxloc(this%sw_albedo_weights, dim=1) 1766 end if 1767 1768 if (this%iverbosesetup >= 2) then 1769 write(nulout, '(a)') 'Surface shortwave albedo' 1770 if (.not. this%do_nearest_spectral_sw_albedo) then 1771 call this%gas_optics_sw%spectral_def%print_mapping_from_bands(this%sw_albedo_weights, & 1772 & use_bands=(.not. this%do_cloud_aerosol_per_sw_g_point)) 1773 else if (ninterval <= 1) then 1774 write(nulout, '(a)') 'All shortwave bands will use the same albedo' 1775 else 1776 write(nulout, '(a,i0,a)',advance='no') 'Mapping from ', size(this%i_albedo_from_band_sw), & 1777 & ' shortwave intervals to albedo intervals:' 1778 do jband = 1,size(this%i_albedo_from_band_sw) 1779 write(nulout,'(a,i0)',advance='no') ' ', this%i_albedo_from_band_sw(jband) 1780 end do 1781 write(nulout, '()') 1782 end if 1783 end if 1784 1785 end subroutine consolidate_sw_albedo_intervals 1786 1787 1788 !--------------------------------------------------------------------- 1789 ! Consolidate the surface longwave emissivity intervals with the 1790 ! band/g-point intervals 1791 subroutine consolidate_lw_emiss_intervals(this) 1792 1793 use radiation_io, only : nulout 1794 use radiation_spectral_definition, only : TerrestrialReferenceTemperature 1795 1796 class(config_type), intent(inout) :: this 1797 1798 integer :: ninterval, jint, jband 1799 1800 ! Count the number of albedo/emissivity intervals 1801 ninterval = 0 1802 do jint = 1,NMaxAlbedoIntervals 1803 if (this%i_lw_emiss_index(jint) > 0) then 1804 ninterval = jint 1805 else 1806 exit 1807 end if 1808 end do 1809 1810 if (ninterval < 1) then 1811 ! The user has not specified longwave emissivity bands - assume 1812 ! only one 1813 ninterval = 1 1814 this%i_lw_emiss_index(1) = 1 1815 this%i_lw_emiss_index(2:) = 0 1816 if (this%use_canopy_full_spectrum_sw) then 1817 this%n_canopy_bands_lw = this%n_g_lw 1818 else 1819 this%n_canopy_bands_lw = 1 1718 1820 end if 1719 1821 else … … 1721 1823 this%n_canopy_bands_lw = this%n_g_lw 1722 1824 else 1723 this%n_canopy_bands_lw = nvalue 1724 end if 1825 this%n_canopy_bands_lw = maxval(this%i_lw_emiss_index(1:ninterval)) 1826 end if 1827 end if 1828 1829 if (this%do_weighted_surface_mapping) then 1830 call this%gas_optics_lw%spectral_def%calc_mapping_from_bands(TerrestrialReferenceTemperature, & 1831 & this%lw_emiss_wavelength_bound(1:ninterval-1), this%i_lw_emiss_index(1:ninterval), & 1832 & this%lw_emiss_weights, use_bands=(.not. this%do_cloud_aerosol_per_lw_g_point)) 1833 else 1834 ! Weight each wavenumber equally as in IFS Cycles 48 and earlier 1835 call this%gas_optics_lw%spectral_def%calc_mapping_from_bands(-1.0_jprb, & 1836 & this%lw_emiss_wavelength_bound(1:ninterval-1), this%i_lw_emiss_index(1:ninterval), & 1837 & this%lw_emiss_weights, use_bands=(.not. this%do_cloud_aerosol_per_lw_g_point)) 1838 end if 1839 1840 ! Legacy method uses input band with largest weight 1841 if (this%do_nearest_spectral_lw_emiss) then 1842 allocate(this%i_emiss_from_band_lw(this%n_bands_lw)) 1843 this%i_emiss_from_band_lw = maxloc(this%lw_emiss_weights, dim=1) 1725 1844 end if 1726 1845 1727 1846 if (this%iverbosesetup >= 2) then 1728 if (.not. do_nearest) then 1729 if (is_sw) then 1730 write(nulout, '(a,i0,a,i0,a)') 'Weighting of ', nvalue, ' albedo values in ', & 1731 & nband, ' shortwave bands (wavenumber ranges in cm-1):' 1732 else 1733 write(nulout, '(a,i0,a,i0,a)') 'Weighting of ', nvalue, ' emissivity values in ', & 1734 & nband, ' longwave bands (wavenumber ranges in cm-1):' 1735 end if 1736 do jband = 1,nband 1737 write(nulout,'(i6,a,i6,a)',advance='no') nint(wavenumber1(jband)), ' to', & 1738 & nint(wavenumber2(jband)), ':' 1739 do iinterval = 1,nvalue 1740 write(nulout,'(f5.2)',advance='no') weights(iinterval,jband) 1741 end do 1742 write(nulout, '()') 1743 end do 1847 write(nulout, '(a)') 'Surface longwave emissivity' 1848 if (.not. this%do_nearest_spectral_lw_emiss) then 1849 call this%gas_optics_lw%spectral_def%print_mapping_from_bands(this%lw_emiss_weights, & 1850 & use_bands=(.not. this%do_cloud_aerosol_per_lw_g_point)) 1744 1851 else if (ninterval <= 1) then 1745 if (is_sw) then 1746 write(nulout, '(a)') 'All shortwave bands will use the same albedo' 1747 else 1748 write(nulout, '(a)') 'All longwave bands will use the same emissivty' 1749 end if 1852 write(nulout, '(a)') 'All longwave bands will use the same emissivty' 1750 1853 else 1751 if (is_sw) then 1752 write(nulout, '(a,i0,a)',advance='no') 'Mapping from ', nband, & 1753 & ' shortwave bands to albedo intervals:' 1754 else 1755 write(nulout, '(a,i0,a)',advance='no') 'Mapping from ', nband, & 1756 & ' longwave bands to emissivity intervals:' 1757 end if 1758 do jband = 1,nband 1759 write(nulout,'(a,i0)',advance='no') ' ', i_mapping(jband) 1854 write(nulout, '(a,i0,a)',advance='no') 'Mapping from ', size(this%i_emiss_from_band_lw), & 1855 & ' longwave intervals to emissivity intervals:' 1856 do jband = 1,size(this%i_emiss_from_band_lw) 1857 write(nulout,'(a,i0)',advance='no') ' ', this%i_emiss_from_band_lw(jband) 1760 1858 end do 1761 1859 write(nulout, '()') … … 1763 1861 end if 1764 1862 1765 end subroutine consolidate_ intervals1863 end subroutine consolidate_lw_emiss_intervals 1766 1864 1767 1865 … … 1866 1964 end subroutine print_enum 1867 1965 1868 1869 !---------------------------------------------------------------------1870 ! Return .true. if 1D allocatable array "var" is out of physical1871 ! range specified by boundmin and boundmax, and issue a warning.1872 ! "do_fix" determines whether erroneous values are fixed to lie1873 ! within the physical range. To check only a subset of the array,1874 ! specify i1 and i2 for the range.1875 function out_of_bounds_1d(var, var_name, boundmin, boundmax, do_fix, i1, i2) result (is_bad)1876 1877 use radiation_io, only : nulout1878 1879 real(jprb), allocatable, intent(inout) :: var(:)1880 character(len=*), intent(in) :: var_name1881 real(jprb), intent(in) :: boundmin, boundmax1882 logical, intent(in) :: do_fix1883 integer, optional, intent(in) :: i1, i21884 1885 logical :: is_bad1886 1887 real(jprb) :: varmin, varmax1888 1889 is_bad = .false.1890 1891 if (allocated(var)) then1892 1893 if (present(i1) .and. present(i2)) then1894 varmin = minval(var(i1:i2))1895 varmax = maxval(var(i1:i2))1896 else1897 varmin = minval(var)1898 varmax = maxval(var)1899 end if1900 1901 if (varmin < boundmin .or. varmax > boundmax) then1902 write(nulout,'(a,a,a,g12.4,a,g12.4,a,g12.4,a,g12.4)',advance='no') &1903 & '*** Warning: ', var_name, ' range', varmin, ' to', varmax, &1904 & ' is out of physical range', boundmin, 'to', boundmax1905 is_bad = .true.1906 if (do_fix) then1907 if (present(i1) .and. present(i2)) then1908 var(i1:i2) = max(boundmin, min(boundmax, var(i1:i2)))1909 else1910 var = max(boundmin, min(boundmax, var))1911 end if1912 write(nulout,'(a)') ': corrected'1913 else1914 write(nulout,'(1x)')1915 end if1916 end if1917 1918 end if1919 1920 end function out_of_bounds_1d1921 1922 1923 !---------------------------------------------------------------------1924 ! Return .true. if 2D allocatable array "var" is out of physical1925 ! range specified by boundmin and boundmax, and issue a warning. To1926 ! check only a subset of the array, specify i1 and i2 for the range1927 ! of the first dimension and j1 and j2 for the range of the second.1928 function out_of_bounds_2d(var, var_name, boundmin, boundmax, do_fix, &1929 & i1, i2, j1, j2) result (is_bad)1930 1931 use radiation_io, only : nulout1932 1933 real(jprb), allocatable, intent(inout) :: var(:,:)1934 character(len=*), intent(in) :: var_name1935 real(jprb), intent(in) :: boundmin, boundmax1936 logical, intent(in) :: do_fix1937 integer, optional, intent(in) :: i1, i2, j1, j21938 1939 ! Local copies of indices1940 integer :: ii1, ii2, jj1, jj21941 1942 logical :: is_bad1943 1944 real(jprb) :: varmin, varmax1945 1946 is_bad = .false.1947 1948 if (allocated(var)) then1949 1950 if (present(i1) .and. present(i2)) then1951 ii1 = i11952 ii2 = i21953 else1954 ii1 = lbound(var,1)1955 ii2 = ubound(var,1)1956 end if1957 if (present(j1) .and. present(j2)) then1958 jj1 = j11959 jj2 = j21960 else1961 jj1 = lbound(var,2)1962 jj2 = ubound(var,2)1963 end if1964 varmin = minval(var(ii1:ii2,jj1:jj2))1965 varmax = maxval(var(ii1:ii2,jj1:jj2))1966 1967 if (varmin < boundmin .or. varmax > boundmax) then1968 write(nulout,'(a,a,a,g12.4,a,g12.4,a,g12.4,a,g12.4)',advance='no') &1969 & '*** Warning: ', var_name, ' range', varmin, ' to', varmax,&1970 & ' is out of physical range', boundmin, 'to', boundmax1971 is_bad = .true.1972 if (do_fix) then1973 var(ii1:ii2,jj1:jj2) = max(boundmin, min(boundmax, var(ii1:ii2,jj1:jj2)))1974 write(nulout,'(a)') ': corrected'1975 else1976 write(nulout,'(1x)')1977 end if1978 end if1979 1980 end if1981 1982 end function out_of_bounds_2d1983 1984 1985 !---------------------------------------------------------------------1986 ! Return .true. if 3D allocatable array "var" is out of physical1987 ! range specified by boundmin and boundmax, and issue a warning. To1988 ! check only a subset of the array, specify i1 and i2 for the range1989 ! of the first dimension, j1 and j2 for the second and k1 and k2 for1990 ! the third.1991 function out_of_bounds_3d(var, var_name, boundmin, boundmax, do_fix, &1992 & i1, i2, j1, j2, k1, k2) result (is_bad)1993 1994 use radiation_io, only : nulout1995 1996 real(jprb), allocatable, intent(inout) :: var(:,:,:)1997 character(len=*), intent(in) :: var_name1998 real(jprb), intent(in) :: boundmin, boundmax1999 logical, intent(in) :: do_fix2000 integer, optional, intent(in) :: i1, i2, j1, j2, k1, k22001 2002 ! Local copies of indices2003 integer :: ii1, ii2, jj1, jj2, kk1, kk22004 2005 logical :: is_bad2006 2007 real(jprb) :: varmin, varmax2008 2009 is_bad = .false.2010 2011 if (allocated(var)) then2012 2013 if (present(i1) .and. present(i2)) then2014 ii1 = i12015 ii2 = i22016 else2017 ii1 = lbound(var,1)2018 ii2 = ubound(var,1)2019 end if2020 if (present(j1) .and. present(j2)) then2021 jj1 = j12022 jj2 = j22023 else2024 jj1 = lbound(var,2)2025 jj2 = ubound(var,2)2026 end if2027 if (present(k1) .and. present(k2)) then2028 kk1 = k12029 kk2 = k22030 else2031 kk1 = lbound(var,3)2032 kk2 = ubound(var,3)2033 end if2034 varmin = minval(var(ii1:ii2,jj1:jj2,kk1:kk2))2035 varmax = maxval(var(ii1:ii2,jj1:jj2,kk1:kk2))2036 2037 if (varmin < boundmin .or. varmax > boundmax) then2038 write(nulout,'(a,a,a,g12.4,a,g12.4,a,g12.4,a,g12.4)',advance='no') &2039 & '*** Warning: ', var_name, ' range', varmin, ' to', varmax,&2040 & ' is out of physical range', boundmin, 'to', boundmax2041 is_bad = .true.2042 if (do_fix) then2043 var(ii1:ii2,jj1:jj2,kk1:kk2) = max(boundmin, min(boundmax, &2044 & var(ii1:ii2,jj1:jj2,kk1:kk2)))2045 write(nulout,'(a)') ': corrected'2046 else2047 write(nulout,'(1x)')2048 end if2049 end if2050 2051 end if2052 2053 end function out_of_bounds_3d2054 2055 2056 1966 end module radiation_config -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_delta_eddington.h
r3908 r4444 1 ! radiation_delta_eddington.h - Delta-Eddington scaling 1 ! radiation_delta_eddington.h - Delta-Eddington scaling -*- f90 -*- 2 2 ! 3 3 ! (C) Copyright 2015- ECMWF. … … 92 92 end subroutine delta_eddington_scat_od 93 93 94 95 !--------------------------------------------------------------------- 96 ! Revert delta-Eddington-scaled quantities in-place, back to their 97 ! original state 98 elemental subroutine revert_delta_eddington(od, ssa, g) 99 100 use parkind1, only : jprb 101 102 ! Total optical depth, single scattering albedo and asymmetry 103 ! factor 104 real(jprb), intent(inout) :: od, ssa, g 105 106 ! Fraction of the phase function deemed to be in the forward lobe 107 ! and therefore treated as if it is not scattered at all 108 real(jprb) :: f 109 110 g = g / (1.0_jprb - g) 111 f = g*g 112 ssa = ssa / (1.0_jprb - f + f*ssa); 113 od = od / (1.0_jprb - ssa*f) 114 115 end subroutine revert_delta_eddington -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_flux.F90
r3908 r4444 100 100 end type flux_type 101 101 102 ! Added for DWD (2020) 103 #ifdef __SX__ 104 logical, parameter :: use_indexed_sum_vec = .true. 105 #else 106 logical, parameter :: use_indexed_sum_vec = .false. 107 #endif 108 102 109 contains 103 110 … … 132 139 if (config%n_spec_lw == 0) then 133 140 write(nulerr,'(a)') '*** Error: number of LW spectral points to save not yet defined ' & 134 & // 'so cannot allocate dspectral flux arrays'141 & // 'so cannot allocate spectral flux arrays' 135 142 call radiation_abort() 136 143 end if … … 321 328 end if 322 329 330 if (allocated(this%lw_dn_surf_g)) deallocate(this%lw_dn_surf_g) 331 if (allocated(this%lw_dn_surf_clear_g)) deallocate(this%lw_dn_surf_clear_g) 332 if (allocated(this%sw_dn_diffuse_surf_g)) deallocate(this%sw_dn_diffuse_surf_g) 333 if (allocated(this%sw_dn_direct_surf_g)) deallocate(this%sw_dn_direct_surf_g) 334 if (allocated(this%sw_dn_diffuse_surf_clear_g)) deallocate(this%sw_dn_diffuse_surf_clear_g) 335 if (allocated(this%sw_dn_direct_surf_clear_g)) deallocate(this%sw_dn_direct_surf_clear_g) 336 323 337 if (lhook) call dr_hook('radiation_flux:deallocate',1,hook_handle) 324 338 … … 349 363 if (config%do_sw .and. config%do_surface_sw_spectral_flux) then 350 364 351 do jcol = istartcol,iendcol 352 call indexed_sum(this%sw_dn_direct_surf_g(:,jcol), & 353 & config%i_band_from_reordered_g_sw, & 354 & this%sw_dn_direct_surf_band(:,jcol)) 355 call indexed_sum(this%sw_dn_diffuse_surf_g(:,jcol), & 356 & config%i_band_from_reordered_g_sw, & 357 & this%sw_dn_surf_band(:,jcol)) 358 this%sw_dn_surf_band(:,jcol) & 359 & = this%sw_dn_surf_band(:,jcol) & 360 & + this%sw_dn_direct_surf_band(:,jcol) 361 end do 365 if (use_indexed_sum_vec) then 366 call indexed_sum_vec(this%sw_dn_direct_surf_g, & 367 & config%i_band_from_reordered_g_sw, & 368 & this%sw_dn_direct_surf_band, istartcol, iendcol) 369 call indexed_sum_vec(this%sw_dn_diffuse_surf_g, & 370 & config%i_band_from_reordered_g_sw, & 371 & this%sw_dn_surf_band, istartcol, iendcol) 372 do jcol = istartcol,iendcol 373 this%sw_dn_surf_band(:,jcol) & 374 & = this%sw_dn_surf_band(:,jcol) & 375 & + this%sw_dn_direct_surf_band(:,jcol) 376 end do 377 else 378 do jcol = istartcol,iendcol 379 call indexed_sum(this%sw_dn_direct_surf_g(:,jcol), & 380 & config%i_band_from_reordered_g_sw, & 381 & this%sw_dn_direct_surf_band(:,jcol)) 382 call indexed_sum(this%sw_dn_diffuse_surf_g(:,jcol), & 383 & config%i_band_from_reordered_g_sw, & 384 & this%sw_dn_surf_band(:,jcol)) 385 this%sw_dn_surf_band(:,jcol) & 386 & = this%sw_dn_surf_band(:,jcol) & 387 & + this%sw_dn_direct_surf_band(:,jcol) 388 end do 389 end if 362 390 363 391 if (config%do_clear) then 364 do jcol = istartcol,iendcol 365 call indexed_sum(this%sw_dn_direct_surf_clear_g(:,jcol), & 366 & config%i_band_from_reordered_g_sw, & 367 & this%sw_dn_direct_surf_clear_band(:,jcol)) 368 call indexed_sum(this%sw_dn_diffuse_surf_clear_g(:,jcol), & 369 & config%i_band_from_reordered_g_sw, & 370 & this%sw_dn_surf_clear_band(:,jcol)) 371 this%sw_dn_surf_clear_band(:,jcol) & 372 & = this%sw_dn_surf_clear_band(:,jcol) & 373 & + this%sw_dn_direct_surf_clear_band(:,jcol) 374 end do 392 if (use_indexed_sum_vec) then 393 call indexed_sum_vec(this%sw_dn_direct_surf_clear_g, & 394 & config%i_band_from_reordered_g_sw, & 395 & this%sw_dn_direct_surf_clear_band, istartcol, iendcol) 396 call indexed_sum_vec(this%sw_dn_diffuse_surf_clear_g, & 397 & config%i_band_from_reordered_g_sw, & 398 & this%sw_dn_surf_clear_band, istartcol, iendcol) 399 do jcol = istartcol,iendcol 400 this%sw_dn_surf_clear_band(:,jcol) & 401 & = this%sw_dn_surf_clear_band(:,jcol) & 402 & + this%sw_dn_direct_surf_clear_band(:,jcol) 403 end do 404 else 405 do jcol = istartcol,iendcol 406 call indexed_sum(this%sw_dn_direct_surf_clear_g(:,jcol), & 407 & config%i_band_from_reordered_g_sw, & 408 & this%sw_dn_direct_surf_clear_band(:,jcol)) 409 call indexed_sum(this%sw_dn_diffuse_surf_clear_g(:,jcol), & 410 & config%i_band_from_reordered_g_sw, & 411 & this%sw_dn_surf_clear_band(:,jcol)) 412 this%sw_dn_surf_clear_band(:,jcol) & 413 & = this%sw_dn_surf_clear_band(:,jcol) & 414 & + this%sw_dn_direct_surf_clear_band(:,jcol) 415 end do 416 end if 375 417 end if 376 418 … … 383 425 this%sw_dn_direct_surf_canopy (:,istartcol:iendcol) = this%sw_dn_direct_surf_g (:,istartcol:iendcol) 384 426 else if (config%do_nearest_spectral_sw_albedo) then 385 do jcol = istartcol,iendcol 386 call indexed_sum(this%sw_dn_direct_surf_g(:,jcol), & 387 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw), & 388 & this%sw_dn_direct_surf_canopy(:,jcol)) 389 call indexed_sum(this%sw_dn_diffuse_surf_g(:,jcol), & 390 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw), & 391 & this%sw_dn_diffuse_surf_canopy(:,jcol)) 392 end do 427 if (use_indexed_sum_vec) then 428 call indexed_sum_vec(this%sw_dn_direct_surf_g, & 429 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw), & 430 & this%sw_dn_direct_surf_canopy, istartcol, iendcol) 431 call indexed_sum_vec(this%sw_dn_diffuse_surf_g, & 432 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw), & 433 & this%sw_dn_diffuse_surf_canopy, istartcol, iendcol) 434 else 435 do jcol = istartcol,iendcol 436 call indexed_sum(this%sw_dn_direct_surf_g(:,jcol), & 437 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw), & 438 & this%sw_dn_direct_surf_canopy(:,jcol)) 439 call indexed_sum(this%sw_dn_diffuse_surf_g(:,jcol), & 440 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw), & 441 & this%sw_dn_diffuse_surf_canopy(:,jcol)) 442 end do 443 end if 393 444 else 394 445 ! More accurate calculations using weights, but requires … … 425 476 this%lw_dn_surf_canopy(:,istartcol:iendcol) = this%lw_dn_surf_g(:,istartcol:iendcol) 426 477 else if (config%do_nearest_spectral_lw_emiss) then 427 do jcol = istartcol,iendcol 428 call indexed_sum(this%lw_dn_surf_g(:,jcol), & 429 & config%i_emiss_from_band_lw(config%i_band_from_reordered_g_lw), & 430 & this%lw_dn_surf_canopy(:,jcol)) 431 end do 478 if (use_indexed_sum_vec) then 479 call indexed_sum_vec(this%lw_dn_surf_g, & 480 & config%i_emiss_from_band_lw(config%i_band_from_reordered_g_lw), & 481 & this%lw_dn_surf_canopy, istartcol, iendcol) 482 else 483 do jcol = istartcol,iendcol 484 call indexed_sum(this%lw_dn_surf_g(:,jcol), & 485 & config%i_emiss_from_band_lw(config%i_band_from_reordered_g_lw), & 486 & this%lw_dn_surf_canopy(:,jcol)) 487 end do 488 end if 432 489 else 433 490 ! Compute fluxes in each longwave emissivity interval using 434 491 ! weights; first sum over g points to get the values in bands 435 do jcol = istartcol,iendcol 436 call indexed_sum(this%lw_dn_surf_g(:,jcol), & 437 & config%i_band_from_reordered_g_lw, & 438 & lw_dn_surf_band(:,jcol)) 439 end do 492 if (use_indexed_sum_vec) then 493 call indexed_sum_vec(this%lw_dn_surf_g, & 494 & config%i_band_from_reordered_g_lw, & 495 & lw_dn_surf_band, istartcol, iendcol) 496 else 497 do jcol = istartcol,iendcol 498 call indexed_sum(this%lw_dn_surf_g(:,jcol), & 499 & config%i_band_from_reordered_g_lw, & 500 & lw_dn_surf_band(:,jcol)) 501 end do 502 end if 440 503 nalbedoband = size(config%lw_emiss_weights,1) 441 504 this%lw_dn_surf_canopy(:,istartcol:iendcol) = 0.0_jprb … … 465 528 466 529 use yomhook, only : lhook, dr_hook 467 use radiation_c onfig,only : out_of_bounds_2d530 use radiation_check, only : out_of_bounds_2d 468 531 469 532 class(flux_type), intent(inout) :: this … … 497 560 function heating_rate_out_of_physical_bounds(this, nlev, istartcol, iendcol, pressure_hl) result(is_bad) 498 561 499 use radiation_c onfig, only : out_of_bounds_2d562 use radiation_check, only : out_of_bounds_2d 500 563 use radiation_constants, only : AccelDueToGravity 501 564 … … 581 644 end subroutine indexed_sum 582 645 646 !--------------------------------------------------------------------- 647 ! Vectorized version of "add_indexed_sum" 648 subroutine indexed_sum_vec(source, ind, dest, ist, iend) 649 650 real(jprb), intent(in) :: source(:,:) 651 integer, intent(in) :: ind(:) 652 real(jprb), intent(out) :: dest(:,:) 653 integer, intent(in) :: ist, iend 654 655 integer :: ig, jg, jc 656 657 dest = 0.0 658 659 do jg = lbound(source,1), ubound(source,1) 660 ig = ind(jg) 661 do jc = ist, iend 662 dest(ig,jc) = dest(ig,jc) + source(jg,jc) 663 end do 664 end do 665 666 end subroutine indexed_sum_vec 583 667 584 668 !--------------------------------------------------------------------- -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_gas.F90
r3908 r4444 19 19 20 20 use parkind1, only : jprb 21 use radiation_gas_constants 21 22 22 23 implicit none 23 24 public 24 25 ! Gas codes; these indices match those of RRTM-LW up to 726 integer, parameter :: IGasNotPresent = 027 integer, parameter :: IH2O = 128 integer, parameter :: ICO2 = 229 integer, parameter :: IO3 = 330 integer, parameter :: IN2O = 431 integer, parameter :: ICO = 532 integer, parameter :: ICH4 = 633 integer, parameter :: IO2 = 734 integer, parameter :: ICFC11 = 835 integer, parameter :: ICFC12 = 936 integer, parameter :: IHCFC22= 1037 integer, parameter :: ICCl4 = 1138 integer, parameter :: INO2 = 1239 integer, parameter :: NMaxGases = 1240 41 ! Molar masses (g mol-1) of dry air and the various gases above42 real(jprb), parameter :: IAirMolarMass = 28.97043 real(jprb), parameter, dimension(0:NMaxGases) :: IGasMolarMass = (/ &44 & 0.0_jprb, & ! Gas not present45 & 18.0152833_jprb, & ! H2O46 & 44.011_jprb, & ! CO247 & 47.9982_jprb, & ! O348 & 44.013_jprb, & ! N2O49 & 28.0101_jprb, & ! CO50 & 16.043_jprb, & ! CH451 & 31.9988_jprb, & ! O252 & 137.3686_jprb, & ! CFC1153 & 120.914_jprb, & ! CFC1254 & 86.469_jprb, & ! HCFC2255 & 153.823_jprb, & ! CCl456 & 46.0055_jprb /) ! NO257 58 ! The corresponding names of the gases in upper and lower case, used59 ! for reading variables from the input file60 character*6, dimension(NMaxGases), parameter :: GasName &61 & = (/'H2O ','CO2 ','O3 ','N2O ','CO ','CH4 ', &62 & 'O2 ','CFC11 ','CFC12 ','HCFC22','CCl4 ','NO2 '/)63 character*6, dimension(NMaxGases), parameter :: GasLowerCaseName &64 & = (/'h2o ','co2 ','o3 ','n2o ','co ','ch4 ', &65 & 'o2 ','cfc11 ','cfc12 ','hcfc22','ccl4 ','no2 '/)66 25 67 26 ! Available units … … 121 80 122 81 !--------------------------------------------------------------------- 82 ! Allocate a derived type for holding gas mixing ratios given the 83 ! number of columns and levels 123 84 subroutine allocate_gas(this, ncol, nlev) 124 85 … … 191 152 integer, optional, intent(in) :: istartcol 192 153 193 integer :: i1, i2 154 integer :: i1, i2, jc, jk 155 194 156 195 157 real(jprb) :: hook_handle … … 245 207 this%iunits(igas) = iunits 246 208 this%is_well_mixed(igas) = .false. 247 this%mixing_ratio(i1:i2,:,igas) = mixing_ratio 248 209 210 do jk = 1,this%nlev 211 do jc = i1,i2 212 this%mixing_ratio(jc,jk,igas) = mixing_ratio(jc-i1+1,jk) 213 end do 214 end do 249 215 if (present(scale_factor)) then 250 216 this%scale_factor(igas) = scale_factor … … 276 242 real(jprb) :: hook_handle 277 243 278 integer :: i1, i2 244 integer :: i1, i2, jc, jk 279 245 280 246 if (lhook) call dr_hook('radiation_gas:put_well_mixed',0,hook_handle) … … 326 292 this%iunits(igas) = iunits 327 293 this%is_well_mixed(igas) = .true. 328 this%mixing_ratio(i1:i2,:,igas) = mixing_ratio 329 294 295 do jk = 1,this%nlev 296 do jc = i1,i2 297 this%mixing_ratio(jc,jk,igas) = mixing_ratio 298 end do 299 end do 330 300 if (present(scale_factor)) then 331 301 this%scale_factor(igas) = scale_factor … … 344 314 ! immediately, but changes the scale factor for the specified gas, 345 315 ! ready to be used in set_units_gas. 346 347 316 subroutine scale_gas(this, igas, scale_factor, lverbose) 348 317 … … 411 380 if (iunits == IMassMixingRatio & 412 381 & .and. this%iunits(igas) == IVolumeMixingRatio) then 413 sf = sf * IGasMolarMass(igas) / IAirMolarMass382 sf = sf * GasMolarMass(igas) / AirMolarMass 414 383 else if (iunits == IVolumeMixingRatio & 415 384 & .and. this%iunits(igas) == IMassMixingRatio) then 416 sf = sf * IAirMolarMass / IGasMolarMass(igas)385 sf = sf * AirMolarMass / GasMolarMass(igas) 417 386 end if 418 387 sf = sf * this%scale_factor(igas) … … 538 507 if (iunits == IMassMixingRatio & 539 508 & .and. this%iunits(igas) == IVolumeMixingRatio) then 540 sf = sf * IGasMolarMass(igas) / IAirMolarMass509 sf = sf * GasMolarMass(igas) / AirMolarMass 541 510 else if (iunits == IVolumeMixingRatio & 542 511 & .and. this%iunits(igas) == IMassMixingRatio) then 543 sf = sf * IAirMolarMass / IGasMolarMass(igas)512 sf = sf * AirMolarMass / GasMolarMass(igas) 544 513 end if 545 514 sf = sf * this%scale_factor(igas) … … 591 560 592 561 use yomhook, only : lhook, dr_hook 593 use radiation_c onfig,only : out_of_bounds_3d562 use radiation_check, only : out_of_bounds_3d 594 563 595 564 class(gas_type), intent(inout) :: this -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_ice_optics_fu.F90
r3908 r4444 61 61 real (jprb) :: iwp_gm_2 62 62 63 integer :: jb 63 64 !real(jprb) :: hook_handle 64 65 … … 70 71 iwp_gm_2 = ice_wp * 1000.0_jprb 71 72 72 od = iwp_gm_2 * (coeff(1:nb,1) + coeff(1:nb,2) * inv_de_um) 73 scat_od = od * (1.0_jprb - (coeff(1:nb,3) + de_um*(coeff(1:nb,4) & 74 & + de_um*(coeff(1:nb,5) + de_um*coeff(1:nb,6))))) 75 g = min(coeff(1:nb,7) + de_um*(coeff(1:nb,8) & 76 & + de_um*(coeff(1:nb,9) + de_um*coeff(1:nb,10))), & 73 ! Added for DWD (2020) 74 !NEC$ shortloop 75 do jb = 1, nb 76 od(jb) = iwp_gm_2 * (coeff(jb,1) + coeff(jb,2) * inv_de_um) 77 scat_od(jb) = od(jb) * (1.0_jprb - (coeff(jb,3) + de_um*(coeff(jb,4) & 78 & + de_um*(coeff(jb,5) + de_um*coeff(jb,6))))) 79 g(jb) = min(coeff(jb,7) + de_um*(coeff(jb,8) & 80 & + de_um*(coeff(jb,9) + de_um*coeff(jb,10))), & 77 81 & MaxAsymmetryFactor) 82 end do 78 83 79 84 !if (lhook) call dr_hook('radiation_ice_optics:calc_ice_optics_fu_sw',1,hook_handle) … … 106 111 real (jprb) :: iwp_gm_2 107 112 113 integer :: jb 108 114 !real(jprb) :: hook_handle 109 115 … … 116 122 iwp_gm_2 = ice_wp * 1000.0_jprb 117 123 118 od = iwp_gm_2 * (coeff(1:nb,1) + inv_de_um*(coeff(1:nb,2) & 119 & + inv_de_um*coeff(1:nb,3))) 120 scat_od = od - iwp_gm_2*inv_de_um*(coeff(1:nb,4) + de_um*(coeff(1:nb,5) & 121 & + de_um*(coeff(1:nb,6) + de_um*coeff(1:nb,7)))) 122 g = min(coeff(1:nb,8) + de_um*(coeff(1:nb,9) & 123 & + de_um*(coeff(1:nb,10) + de_um*coeff(1:nb,11))), & 124 ! Added for DWD (2020) 125 !NEC$ shortloop 126 do jb = 1, nb 127 od(jb) = iwp_gm_2 * (coeff(jb,1) + inv_de_um*(coeff(jb,2) & 128 & + inv_de_um*coeff(jb,3))) 129 scat_od(jb) = od(jb) - iwp_gm_2*inv_de_um*(coeff(jb,4) + de_um*(coeff(jb,5) & 130 & + de_um*(coeff(jb,6) + de_um*coeff(jb,7)))) 131 g(jb) = min(coeff(jb,8) + de_um*(coeff(jb,9) & 132 & + de_um*(coeff(jb,10) + de_um*coeff(jb,11))), & 124 133 & MaxAsymmetryFactor) 134 end do 125 135 126 136 !if (lhook) call dr_hook('radiation_ice_optics:calc_ice_optics_fu_lw',1,hook_handle) -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_ifs_rrtm.F90
r4115 r4444 68 68 real(jprb) :: hook_handle 69 69 70 #include "surdi.intfb.h"70 !#include "surdi.intfb.h" 71 71 #include "surrtab.intfb.h" 72 72 #include "surrtpk.intfb.h" … … 81 81 ! up now. 82 82 if (config%do_setup_ifsrrtm) then 83 call SURDI83 !call SURDI 84 84 call SURRTAB 85 85 call SURRTPK … … 89 89 end if 90 90 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 91 95 config%n_g_sw = jpgsw 92 96 config%n_g_lw = jpglw … … 97 101 ! can compute UV and photosynthetically active radiation for a 98 102 ! particular wavelength range 99 allocate(config%wavenumber1_sw(config%n_bands_sw)) 100 allocate(config%wavenumber2_sw(config%n_bands_sw)) 101 allocate(config%wavenumber1_lw(config%n_bands_lw)) 102 allocate(config%wavenumber2_lw(config%n_bands_lw)) 103 config%wavenumber1_lw = (/ 10, 350, 500, 630, 700, 820, 980, 1080, 1180, 1390, 1480, & 104 & 1800, 2080, 2250, 2380, 2600 /) 105 config%wavenumber2_lw = (/ 350, 500, 630, 700, 820, 980, 1080, 1180, 1390, 1480, 1800, & 106 & 2080, 2250, 2380, 2600, 3250 /) 107 config%wavenumber1_sw = (/ 2600, 3250, 4000, 4650, 5150, 6150, 7700, 8050, 12850, & 108 & 16000 , 22650, 29000, 38000, 820 /) 109 config%wavenumber2_sw = (/ 3250, 4000, 4650, 5150, 6150, 7700, 8050, 12850, 16000, & 110 & 22650, 29000, 38000, 50000, 2600 /) 111 print*,'allocate dans ifs_rrtm' 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 112 114 allocate(config%i_band_from_g_sw (config%n_g_sw)) 113 115 allocate(config%i_band_from_g_lw (config%n_g_lw)) … … 360 362 ! end if 361 363 362 pressure_fl(istartcol:iendcol,:) & 363 & = 0.5_jprb * (thermodynamics%pressure_hl(istartcol:iendcol,istartlev:iendlev) & 364 & +thermodynamics%pressure_hl(istartcol:iendcol,istartlev+1:iendlev+1)) 365 temperature_fl(istartcol:iendcol,:) & 366 & = 0.5_jprb * (thermodynamics%temperature_hl(istartcol:iendcol,istartlev:iendlev) & 367 & +thermodynamics%temperature_hl(istartcol:iendcol,istartlev+1:iendlev+1)) 364 do jlev=1,nlev 365 do jcol= istartcol,iendcol 366 pressure_fl(jcol,jlev) & 367 & = 0.5_jprb * (thermodynamics%pressure_hl(jcol,jlev+istartlev-1) & 368 & +thermodynamics%pressure_hl(jcol,jlev+istartlev)) 369 temperature_fl(jcol,jlev) & 370 & = 0.5_jprb * (thermodynamics%temperature_hl(jcol,jlev+istartlev-1) & 371 & +thermodynamics%temperature_hl(jcol,jlev+istartlev)) 372 end do 373 end do 368 374 369 375 ! Check we have gas mixing ratios in the right units … … 402 408 & ZRAT_N2OCO2, ZRAT_N2OCO2_1, ZRAT_O3CO2, ZRAT_O3CO2_1) 403 409 404 ZTAUAERL = 0.0_jprb410 ZTAUAERL(istartcol:iendcol,:,:) = 0.0_jprb 405 411 406 412 CALL RRTM_GAS_OPTICAL_DEPTH & … … 434 440 lw_emission = lw_emission * (1.0_jprb - lw_albedo) 435 441 else 436 ! Longwave emission has already been computed442 ! Longwave emission has already been computed 437 443 if (config%use_canopy_full_spectrum_lw) then 438 444 lw_emission = transpose(single_level%lw_emission(istartcol:iendcol,:)) … … 509 515 ! Scale the incoming solar per band, if requested 510 516 if (config%use_spectral_solar_scaling) then 511 ZINCSOL(istartcol:iendcol,:) = ZINCSOL(istartcol:iendcol,:) & 512 & * spread(single_level%spectral_solar_scaling(config%i_band_from_reordered_g_sw), & 513 & 1,iendcol-istartcol+1) 517 do jg = 1,JPGPT_SW 518 do jcol = istartcol,iendcol 519 ZINCSOL(jcol,jg) = ZINCSOL(jcol,jg) * & 520 & single_level%spectral_solar_scaling(config%i_band_from_reordered_g_sw(jg)) 521 end do 522 end do 514 523 end if 515 524 … … 518 527 ! ZINCSOL will be zero. 519 528 if (present(incoming_sw)) then 520 incoming_sw_scale = 1.0_jprb521 529 do jcol = istartcol,iendcol 522 530 if (single_level%cos_sza(jcol) > 0.0_jprb) then 531 ! Added for DWD (2020) 532 !NEC$ nounroll 523 533 incoming_sw_scale(jcol) = single_level%solar_irradiance / sum(ZINCSOL(jcol,:)) 534 else 535 incoming_sw_scale(jcol) = 1.0_jprb 524 536 end if 525 537 end do … … 546 558 else 547 559 ! G points have not been reordered 548 do j g = 1,config%n_g_sw560 do jcol = istartcol,iendcol 549 561 do jlev = 1,nlev 550 do j col = istartcol,iendcol562 do jg = 1,config%n_g_sw 551 563 ! Check for negative optical depth 552 564 od_sw (jg,nlev+1-jlev,jcol) = max(config%min_gas_od_sw, ZOD_SW(jcol,jlev,jg)) … … 555 567 end do 556 568 if (present(incoming_sw)) then 557 incoming_sw(jg,:) & 558 & = incoming_sw_scale(:) * ZINCSOL(:,jg) 569 do jg = 1,config%n_g_sw 570 incoming_sw(jg,jcol) = incoming_sw_scale(jcol) * ZINCSOL(jcol,jg) 571 end do 559 572 end if 560 573 end do … … 604 617 real(jprb) :: temperature 605 618 606 real(jprb) :: factor 619 real(jprb) :: factor, planck_tmp(istartcol:iendcol,config%n_g_lw) 607 620 real(jprb) :: ZFLUXFAC 608 621 … … 689 702 do jg = 1,config%n_g_lw 690 703 iband = config%i_band_from_g_lw(jg) 691 planck_hl(jg,jlev,:) = planck_store(:,iband) * PFRAC(:,jg,nlev+2-jlev) 704 planck_tmp(:,jg) = planck_store(:,iband) * PFRAC(:,jg,nlev+2-jlev) 705 end do 706 do jcol = istartcol,iendcol 707 planck_hl(:,jlev,jcol) = planck_tmp(jcol,:) 692 708 end do 693 709 end if -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_interface.F90
r3908 r4444 40 40 use yomhook, only : lhook, dr_hook 41 41 use radiation_config, only : config_type, ISolverMcICA, & 42 & IGasModelMonochromatic, IGasModelIFSRRTMG 42 & IGasModelMonochromatic, IGasModelIFSRRTMG, IGasModelECCKD 43 use radiation_spectral_definition, only & 44 & : SolarReferenceTemperature, TerrestrialReferenceTemperature 43 45 44 46 ! Currently there are two gas absorption models: RRTMG (default) … … 48 50 & setup_cloud_optics_mono => setup_cloud_optics, & 49 51 & setup_aerosol_optics_mono => setup_aerosol_optics 50 use radiation_ifs_rrtm, only : setup_gas_optics 52 use radiation_ifs_rrtm, only : setup_gas_optics_rrtmg => setup_gas_optics 53 use radiation_ecckd_interface,only : setup_gas_optics_ecckd => setup_gas_optics 51 54 use radiation_cloud_optics, only : setup_cloud_optics 55 use radiation_general_cloud_optics, only : setup_general_cloud_optics 52 56 use radiation_aerosol_optics, only : setup_aerosol_optics 53 57 … … 66 70 call setup_gas_optics_mono(config, trim(config%directory_name)) 67 71 else if (config%i_gas_model == IGasModelIFSRRTMG) then 68 call setup_gas_optics(config, trim(config%directory_name)) 72 call setup_gas_optics_rrtmg(config, trim(config%directory_name)) 73 else if (config%i_gas_model == IGasModelECCKD) then 74 call setup_gas_optics_ecckd(config) 69 75 end if 70 76 … … 100 106 ! Consolidate the albedo/emissivity intervals with the shortwave 101 107 ! and longwave spectral bands 102 call config%consolidate_intervals(.true., & 103 & config%do_nearest_spectral_sw_albedo, & 104 & config%sw_albedo_wavelength_bound, config%i_sw_albedo_index, & 105 & config%wavenumber1_sw, config%wavenumber2_sw, & 106 & config%i_albedo_from_band_sw, config%sw_albedo_weights) 107 call config%consolidate_intervals(.false., & 108 & config%do_nearest_spectral_lw_emiss, & 109 & config%lw_emiss_wavelength_bound, config%i_lw_emiss_index, & 110 & config%wavenumber1_lw, config%wavenumber2_lw, & 111 & config%i_emiss_from_band_lw, config%lw_emiss_weights) 108 if (config%do_sw) then 109 call config%consolidate_sw_albedo_intervals 110 end if 111 if (config%do_lw) then 112 call config%consolidate_lw_emiss_intervals 113 end if 112 114 113 115 if (config%do_clouds) then 114 116 if (config%i_gas_model == IGasModelMonochromatic) then 115 117 ! call setup_cloud_optics_mono(config) 118 elseif (config%use_general_cloud_optics) then 119 call setup_general_cloud_optics(config) 116 120 else 117 121 call setup_cloud_optics(config) … … 147 151 148 152 use radiation_config 149 use radiation_gas, only : gas_type 150 use radiation_monochromatic, only : set_gas_units_mono => set_gas_units 151 use radiation_ifs_rrtm, only : set_gas_units_ifs => set_gas_units 153 use radiation_gas, only : gas_type 154 use radiation_monochromatic, only : set_gas_units_mono => set_gas_units 155 use radiation_ifs_rrtm, only : set_gas_units_ifs => set_gas_units 156 use radiation_ecckd_interface, only : set_gas_units_ecckd => set_gas_units 152 157 153 158 type(config_type), intent(in) :: config … … 156 161 if (config%i_gas_model == IGasModelMonochromatic) then 157 162 call set_gas_units_mono(gas) 163 elseif (config%i_gas_model == IGasModelECCKD) then 164 call set_gas_units_ecckd(gas) 158 165 else 159 166 call set_gas_units_ifs(gas) … … 207 214 & cloud_optics_mono => cloud_optics, & 208 215 & add_aerosol_optics_mono => add_aerosol_optics 209 use radiation_ifs_rrtm, only : gas_optics 216 use radiation_ifs_rrtm, only : gas_optics_rrtmg => gas_optics 217 use radiation_ecckd_interface,only : gas_optics_ecckd => gas_optics 210 218 use radiation_cloud_optics, only : cloud_optics 219 use radiation_general_cloud_optics, only : general_cloud_optics 211 220 use radiation_aerosol_optics, only : add_aerosol_optics 212 221 … … 309 318 & od_lw, od_sw, ssa_sw, & 310 319 & planck_hl, lw_emission, incoming_sw) 320 else if (config%i_gas_model == IGasModelIFSRRTMG) then 321 call gas_optics_rrtmg(ncol,nlev,istartcol,iendcol, config, & 322 & single_level, thermodynamics, gas, & 323 & od_lw, od_sw, ssa_sw, lw_albedo=lw_albedo, & 324 & planck_hl=planck_hl, lw_emission=lw_emission, & 325 & incoming_sw=incoming_sw) 311 326 else 312 call gas_optics (ncol,nlev,istartcol,iendcol, config, &327 call gas_optics_ecckd(ncol,nlev,istartcol,iendcol, config, & 313 328 & single_level, thermodynamics, gas, & 314 329 & od_lw, od_sw, ssa_sw, lw_albedo=lw_albedo, & … … 330 345 call cloud_optics_mono(nlev, istartcol, iendcol, & 331 346 & config, thermodynamics, cloud, & 347 & od_lw_cloud, ssa_lw_cloud, g_lw_cloud, & 348 & od_sw_cloud, ssa_sw_cloud, g_sw_cloud) 349 elseif (config%use_general_cloud_optics) then 350 call general_cloud_optics(nlev, istartcol, iendcol, & 351 & config, thermodynamics, cloud, & 332 352 & od_lw_cloud, ssa_lw_cloud, g_lw_cloud, & 333 353 & od_sw_cloud, ssa_sw_cloud, g_sw_cloud) … … 351 371 end if 352 372 else 353 g_sw = 0.0_jprb373 g_sw(:,:,istartcol:iendcol) = 0.0_jprb 354 374 if (config%do_lw_aerosol_scattering) then 355 ssa_lw = 0.0_jprb356 g_lw = 0.0_jprb375 ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb 376 g_lw(:,:,istartcol:iendcol) = 0.0_jprb 357 377 end if 358 378 end if -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_liquid_optics_socrates.F90
r3908 r4444 52 52 real(jprb), intent(out) :: od(nb), scat_od(nb), g(nb) 53 53 54 integer :: jb 54 55 ! Local effective radius (m), after applying bounds 55 56 real(jprb) :: re … … 62 63 re = max(MinEffectiveRadius, min(re_in, MaxEffectiveRadius)) 63 64 64 od = lwp * (coeff(1:nb,1) + re*(coeff(1:nb,2) + re*coeff(1:nb,3))) & 65 & / (1.0_jprb + re*(coeff(1:nb,4) + re*(coeff(1:nb,5) & 66 & + re*coeff(1:nb,6)))) 67 scat_od = od * (1.0_jprb & 68 & - (coeff(1:nb,7) + re*(coeff(1:nb,8) + re*coeff(1:nb,9))) & 69 & / (1.0_jprb + re*(coeff(1:nb,10) + re*coeff(1:nb,11)))) 70 g = (coeff(1:nb,12) + re*(coeff(1:nb,13) + re*coeff(1:nb,14))) & 71 & / (1.0_jprb + re*(coeff(1:nb,15) + re*coeff(1:nb,16))) 65 ! Added for DWD (2020) 66 !NEC$ shortloop 67 do jb = 1, nb 68 od(jb) = lwp * (coeff(jb,1) + re*(coeff(jb,2) + re*coeff(jb,3))) & 69 & / (1.0_jprb + re*(coeff(jb,4) + re*(coeff(jb,5) & 70 & + re*coeff(jb,6)))) 71 scat_od(jb) = od(jb) * (1.0_jprb & 72 & - (coeff(jb,7) + re*(coeff(jb,8) + re*coeff(jb,9))) & 73 & / (1.0_jprb + re*(coeff(jb,10) + re*coeff(jb,11)))) 74 g(jb) = (coeff(jb,12) + re*(coeff(jb,13) + re*coeff(jb,14))) & 75 & / (1.0_jprb + re*(coeff(jb,15) + re*coeff(jb,16))) 76 end do 72 77 73 78 !if (lhook) call dr_hook('radiation_liquid_optics_socrates:calc_liq_optics_socrates',1,hook_handle) -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_matrix.F90
r3908 r4444 550 550 real(jprb), dimension(iend) :: y2, y3 551 551 552 integer :: j553 554 552 ! associate (U11 => A(:,1,1), U12 => A(:,1,2), U13 => A(1,3)) 555 553 ! LU decomposition of the *transpose* of A: -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_mcica_lw.F90
r3908 r4444 157 157 ! transmittance etc at each model level 158 158 do jlev = 1,nlev 159 ssa_total = ssa(:,jlev,jcol) 160 g_total = g(:,jlev,jcol) 161 call calc_two_stream_gammas_lw(ng, ssa_total, g_total, & 159 call calc_two_stream_gammas_lw(ng, ssa(:,jlev,jcol), g(:,jlev,jcol), & 162 160 & gamma1, gamma2) 163 161 call calc_reflectance_transmittance_lw(ng, & … … 206 204 & config%cloud_inhom_decorr_scaling, cloud%fractional_std(jcol,:), & 207 205 & config%pdf_sampler, od_scaling, total_cloud_cover, & 208 & is_beta_overlap=config%use_beta_overlap) 206 & use_beta_overlap=config%use_beta_overlap, & 207 & use_vectorizable_generator=config%use_vectorizable_generator) 209 208 210 209 ! Store total cloud cover … … 225 224 end if 226 225 227 od_cloud_new = od_scaling(:,jlev) & 228 & * od_cloud(config%i_band_from_reordered_g_lw,jlev,jcol) 229 od_total = od(:,jlev,jcol) + od_cloud_new 230 ssa_total = 0.0_jprb 231 g_total = 0.0_jprb 226 do jg = 1,ng 227 od_cloud_new(jg) = od_scaling(jg,jlev) & 228 & * od_cloud(config%i_band_from_reordered_g_lw(jg),jlev,jcol) 229 od_total(jg) = od(jg,jlev,jcol) + od_cloud_new(jg) 230 ssa_total(jg) = 0.0_jprb 231 g_total(jg) = 0.0_jprb 232 end do 232 233 233 234 if (config%do_lw_cloud_scattering) then … … 239 240 ! case that od_total > 0.0 and ssa_total > 0.0 but 240 241 ! od_total*ssa_total == 0 due to underflow 241 scat_od_total = ssa(:,jlev,jcol)*od(:,jlev,jcol) & 242 & + ssa_cloud(config%i_band_from_reordered_g_lw,jlev,jcol) & 243 & * od_cloud_new 244 where (scat_od_total > 0.0_jprb) 245 g_total = (g(:,jlev,jcol)*ssa(:,jlev,jcol)*od(:,jlev,jcol) & 246 & + g_cloud(config%i_band_from_reordered_g_lw,jlev,jcol) & 247 & * ssa_cloud(config%i_band_from_reordered_g_lw,jlev,jcol) & 248 & * od_cloud_new) & 249 & / scat_od_total 250 end where 251 where (od_total > 0.0_jprb) 252 ssa_total = scat_od_total / od_total 253 end where 242 do jg = 1,ng 243 if (od_total(jg) > 0.0_jprb) then 244 scat_od_total(jg) = ssa(jg,jlev,jcol)*od(jg,jlev,jcol) & 245 & + ssa_cloud(config%i_band_from_reordered_g_lw(jg),jlev,jcol) & 246 & * od_cloud_new(jg) 247 ssa_total(jg) = scat_od_total(jg) / od_total(jg) 248 249 if (scat_od_total(jg) > 0.0_jprb) then 250 g_total(jg) = (g(jg,jlev,jcol)*ssa(jg,jlev,jcol)*od(jg,jlev,jcol) & 251 & + g_cloud(config%i_band_from_reordered_g_lw(jg),jlev,jcol) & 252 & * ssa_cloud(config%i_band_from_reordered_g_lw(jg),jlev,jcol) & 253 & * od_cloud_new(jg)) & 254 & / scat_od_total(jg) 255 end if 256 end if 257 end do 258 254 259 else 260 255 261 do jg = 1,ng 256 262 if (od_total(jg) > 0.0_jprb) then … … 265 271 end if 266 272 end do 273 267 274 end if 268 275 … … 301 308 ! Use adding method to compute fluxes but optimize for the 302 309 ! presence of clear-sky layers 303 ! call adding_ica_lw(ng, nlev, reflectance, transmittance, source_up, source_dn, &304 ! & emission(:,jcol), albedo(:,jcol), &305 ! & flux_up, flux_dn)306 310 call fast_adding_ica_lw(ng, nlev, reflectance, transmittance, source_up, source_dn, & 307 311 & emission(:,jcol), albedo(:,jcol), & -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_mcica_sw.F90
r3908 r4444 211 211 & config%cloud_inhom_decorr_scaling, cloud%fractional_std(jcol,:), & 212 212 & config%pdf_sampler, od_scaling, total_cloud_cover, & 213 & is_beta_overlap=config%use_beta_overlap) 213 & use_beta_overlap=config%use_beta_overlap, & 214 & use_vectorizable_generator=config%use_vectorizable_generator) 214 215 215 216 ! Store total cloud cover … … 221 222 ! Compute combined gas+aerosol+cloud optical properties 222 223 if (cloud%fraction(jcol,jlev) >= config%cloud_fraction_threshold) then 223 od_cloud_new = od_scaling(:,jlev) &224 & * od_cloud(config%i_band_from_reordered_g_sw,jlev,jcol)225 od_total = od(:,jlev,jcol) + od_cloud_new226 ssa_total = 0.0_jprb227 g_total = 0.0_jprb228 ! In single precision we need to protect against the229 ! case that od_total > 0.0 and ssa_total > 0.0 but230 ! od_total*ssa_total == 0 due to underflow231 224 do jg = 1,ng 225 od_cloud_new(jg) = od_scaling(jg,jlev) & 226 & * od_cloud(config%i_band_from_reordered_g_sw(jg),jlev,jcol) 227 od_total(jg) = od(jg,jlev,jcol) + od_cloud_new(jg) 228 ssa_total(jg) = 0.0_jprb 229 g_total(jg) = 0.0_jprb 230 231 ! In single precision we need to protect against the 232 ! case that od_total > 0.0 and ssa_total > 0.0 but 233 ! od_total*ssa_total == 0 due to underflow 232 234 if (od_total(jg) > 0.0_jprb) then 233 235 scat_od = ssa(jg,jlev,jcol)*od(jg,jlev,jcol) & -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_monochromatic.F90
r3908 r4444 345 345 real(jprb), dimension(config%n_g_sw,nlev,istartcol:iendcol), intent(out) :: g_sw 346 346 347 g_sw = 0.0_jprb347 g_sw(:,:,istartcol:iendcol) = 0.0_jprb 348 348 349 349 if (config%do_lw_aerosol_scattering) then 350 ssa_lw = 0.0_jprb351 g_lw = 0.0_jprb350 ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb 351 g_lw(:,:,istartcol:iendcol) = 0.0_jprb 352 352 end if 353 353 -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_pdf_sampler.F90
r3908 r4444 1 ! radiation_pdf_sampler.F90 - Get samples from a lognormal distributionfor McICA1 ! radiation_pdf_sampler.F90 - Get samples from a PDF for McICA 2 2 ! 3 3 ! (C) Copyright 2015- ECMWF. … … 22 22 23 23 !--------------------------------------------------------------------- 24 ! Derived type for sampling from a lognormal distribution, used to 25 ! generate water content or optical depth scalings for use in the 26 ! Monte Carlo Independent Column Approximation (McICA) 24 ! Derived type for sampling from a lognormal or gamma distribution, 25 ! or other PDF, used to generate water content or optical depth 26 ! scalings for use in the Monte Carlo Independent Column 27 ! Approximation (McICA) 27 28 type pdf_sampler_type 28 29 ! Number of points in look-up table for cumulative distribution … … 43 44 procedure :: sample => sample_from_pdf 44 45 procedure :: masked_sample => sample_from_pdf_masked 46 procedure :: block_sample => sample_from_pdf_block 47 procedure :: masked_block_sample => sample_from_pdf_masked_block 45 48 procedure :: deallocate => deallocate_pdf_sampler 46 49 … … 117 120 118 121 !--------------------------------------------------------------------- 119 ! Extract the value of a lognormal distribution with fractional120 ! standard deviation "fsd" corresponding to the cumulative121 ! distribution function value "cdf", and return it in val. Since this122 ! is an elementalsubroutine, fsd, cdf and val may be arrays.122 ! Extract the value from a PDF with fractional standard deviation 123 ! "fsd" corresponding to the cumulative distribution function value 124 ! "cdf", and return it in val. Since this is an elemental 125 ! subroutine, fsd, cdf and val may be arrays. 123 126 elemental subroutine sample_from_pdf(this, fsd, cdf, val) 124 127 … … 156 159 157 160 !--------------------------------------------------------------------- 158 ! For true elements of mask, extract the values of a lognormal 159 ! distribution with fractional standard deviation "fsd" 160 ! corresponding to the cumulative distribution function values 161 ! "cdf", and return in val. For false elements of mask, return zero 162 ! in val. 161 ! For true elements of mask, extract the values of a PDF with 162 ! fractional standard deviation "fsd" corresponding to the 163 ! cumulative distribution function values "cdf", and return in 164 ! val. For false elements of mask, return zero in val. 163 165 subroutine sample_from_pdf_masked(this, nsamp, fsd, cdf, val, mask) 164 166 … … 208 210 end subroutine sample_from_pdf_masked 209 211 212 !--------------------------------------------------------------------- 213 ! Extract the values of a PDF with fractional standard deviation 214 ! "fsd" corresponding to the cumulative distribution function values 215 ! "cdf", and return in val. This version works on 2D blocks of data. 216 subroutine sample_from_pdf_block(this, nz, ng, fsd, cdf, val) 217 218 class(pdf_sampler_type), intent(in) :: this 219 220 ! Number of samples 221 integer, intent(in) :: nz, ng 222 223 ! Fractional standard deviation (0 to 4) and cumulative 224 ! distribution function (0 to 1) 225 real(jprb), intent(in) :: fsd(nz), cdf(ng, nz) 226 227 ! Sample from distribution 228 real(jprb), intent(out) :: val(:,:) 229 230 ! Loop index 231 integer :: jz, jg 232 233 ! Index to look-up table 234 integer :: ifsd, icdf 235 236 ! Weights in bilinear interpolation 237 real(jprb) :: wfsd, wcdf 238 239 do jz = 1,nz 240 do jg = 1,ng 241 if (cdf(jg, jz) > 0.0_jprb) then 242 ! Bilinear interpolation with bounds 243 wcdf = cdf(jg,jz) * (this%ncdf-1) + 1.0_jprb 244 icdf = max(1, min(int(wcdf), this%ncdf-1)) 245 wcdf = max(0.0_jprb, min(wcdf - icdf, 1.0_jprb)) 246 247 wfsd = (fsd(jz)-this%fsd1) * this%inv_fsd_interval + 1.0_jprb 248 ifsd = max(1, min(int(wfsd), this%nfsd-1)) 249 wfsd = max(0.0_jprb, min(wfsd - ifsd, 1.0_jprb)) 250 251 val(jg,jz)=(1.0_jprb-wcdf)*(1.0_jprb-wfsd) * this%val(icdf ,ifsd) & 252 & +(1.0_jprb-wcdf)* wfsd * this%val(icdf ,ifsd+1) & 253 & + wcdf *(1.0_jprb-wfsd) * this%val(icdf+1,ifsd) & 254 & + wcdf * wfsd * this%val(icdf+1,ifsd+1) 255 else 256 val(jg,jz) = 0.0_jprb 257 end if 258 end do 259 end do 260 261 end subroutine sample_from_pdf_block 262 263 !--------------------------------------------------------------------- 264 ! Extract the values of a PDF with fractional standard deviation 265 ! "fsd" corresponding to the cumulative distribution function values 266 ! "cdf", and return in val. This version works on 2D blocks of data. 267 subroutine sample_from_pdf_masked_block(this, nz, ng, fsd, cdf, val, mask) 268 269 class(pdf_sampler_type), intent(in) :: this 270 271 ! Number of samples 272 integer, intent(in) :: nz, ng 273 274 ! Fractional standard deviation (0 to 4) and cumulative 275 ! distribution function (0 to 1) 276 real(jprb), intent(in) :: fsd(nz), cdf(ng, nz) 277 278 ! Sample from distribution 279 real(jprb), intent(out) :: val(:,:) 280 281 ! Mask 282 logical, intent(in), optional :: mask(nz) 283 284 ! Loop index 285 integer :: jz, jg 286 287 ! Index to look-up table 288 integer :: ifsd, icdf 289 290 ! Weights in bilinear interpolation 291 real(jprb) :: wfsd, wcdf 292 293 do jz = 1,nz 294 295 if (mask(jz)) then 296 297 do jg = 1,ng 298 if (cdf(jg, jz) > 0.0_jprb) then 299 ! Bilinear interpolation with bounds 300 wcdf = cdf(jg,jz) * (this%ncdf-1) + 1.0_jprb 301 icdf = max(1, min(int(wcdf), this%ncdf-1)) 302 wcdf = max(0.0_jprb, min(wcdf - icdf, 1.0_jprb)) 303 304 wfsd = (fsd(jz)-this%fsd1) * this%inv_fsd_interval + 1.0_jprb 305 ifsd = max(1, min(int(wfsd), this%nfsd-1)) 306 wfsd = max(0.0_jprb, min(wfsd - ifsd, 1.0_jprb)) 307 308 val(jg,jz)=(1.0_jprb-wcdf)*(1.0_jprb-wfsd) * this%val(icdf ,ifsd) & 309 & +(1.0_jprb-wcdf)* wfsd * this%val(icdf ,ifsd+1) & 310 & + wcdf *(1.0_jprb-wfsd) * this%val(icdf+1,ifsd) & 311 & + wcdf * wfsd * this%val(icdf+1,ifsd+1) 312 else 313 val(jg,jz) = 0.0_jprb 314 end if 315 end do 316 317 end if 318 319 end do 320 321 end subroutine sample_from_pdf_masked_block 322 210 323 end module radiation_pdf_sampler -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_save.F90
r3908 r4444 33 33 ! thermodynamics object 34 34 subroutine save_fluxes(file_name, config, thermodynamics, flux, & 35 & iverbose, is_hdf5_file, experiment_name) 35 & iverbose, is_hdf5_file, experiment_name, & 36 & is_double_precision) 36 37 37 38 use yomhook, only : lhook, dr_hook … … 50 51 integer, optional, intent(in) :: iverbose 51 52 logical, optional, intent(in) :: is_hdf5_file 53 logical, optional, intent(in) :: is_double_precision 52 54 character(len=*), optional, intent(in) :: experiment_name 53 55 … … 96 98 ! output file column varies most slowly so need to transpose 97 99 call out_file%transpose_matrices(.true.) 100 101 ! Set default precision for file, if specified 102 if (present(is_double_precision)) then 103 call out_file%double_precision(is_double_precision) 104 end if 98 105 99 106 ! Spectral fluxes in memory are dimensioned (nband,ncol,nlev), but … … 885 892 & dim2_name="column", dim1_name="level", & 886 893 & units_str="m", long_name="Ice effective radius") 887 if (a llocated(cloud%re_ice)) then894 if (associated(cloud%re_ice)) then 888 895 call out_file%define_variable("re_ice", & 889 896 & dim2_name="column", dim1_name="level", & … … 966 973 call out_file%put("q_ice", cloud%q_ice) 967 974 call out_file%put("re_liquid", cloud%re_liq) 968 if (a llocated(cloud%re_ice)) then975 if (associated(cloud%re_ice)) then 969 976 call out_file%put("re_ice", cloud%re_ice) 970 977 end if -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_scheme.F90
r4388 r4444 642 642 643 643 ! Compute UV fluxes as weighted sum of appropriate shortwave bands 644 !AI ATTENTION 645 if (0.eq.1) then 644 646 PFLUX_UV (KIDIA:KFDIA) = 0.0_JPRB 645 647 DO JBAND = 1,NWEIGHT_UV … … 658 660 & * flux%sw_dn_surf_clear_band(IBAND_PAR(JBAND),KIDIA:KFDIA) 659 661 ENDDO 660 662 endif 661 663 ! Compute effective broadband emissivity 662 664 ZBLACK_BODY_NET_LW = flux%lw_dn(KIDIA:KFDIA,KLEV+1) & … … 677 679 !AI ATTENTION 678 680 !IF (YRERAD%LAPPROXSWUPDATE) THEN 681 if (0.eq.1) then 679 682 IF (rad_config%do_surface_sw_spectral_flux) THEN 680 683 PSWDIFFUSEBAND(KIDIA:KFDIA,:) = 0.0_JPRB … … 691 694 ENDDO 692 695 ENDIF 693 696 endif 694 697 CALL single_level%deallocate 695 698 CALL thermodynamics%deallocate -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_setup.F90
r4388 r4444 88 88 89 89 USE radiation_interface, ONLY : setup_radiation 90 USE radiation_aerosol_optics, ONLY : dry_aerosol_sw_mass_extinction90 ! USE radiation_aerosol_optics, ONLY : dry_aerosol_sw_mass_extinction 91 91 92 92 ! AI (propre a IFS) -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_single_level.F90
r3908 r4444 95 95 96 96 !--------------------------------------------------------------------- 97 ! Allocate the arrays of a single-level type 97 98 subroutine allocate_single_level(this, ncol, nalbedobands, nemisbands, & 98 99 & use_sw_albedo_direct, is_simple_surface) … … 142 143 143 144 !--------------------------------------------------------------------- 145 ! Deallocate the arrays of a single-level type 144 146 subroutine deallocate_single_level(this) 145 147 … … 227 229 ! Temporary storage of albedo in ecRad bands 228 230 real(jprb) :: sw_albedo_band(istartcol:iendcol, config%n_bands_sw) 229 real(jprb) :: lw_albedo_band 231 real(jprb) :: lw_albedo_band(istartcol:iendcol, config%n_bands_lw) 230 232 231 233 ! Number of albedo bands … … 233 235 234 236 ! Loop indices for ecRad bands and albedo bands 235 integer :: jband, jalbedoband 237 integer :: jband, jalbedoband, jcol 236 238 237 239 real(jprb) :: hook_handle … … 239 241 if (lhook) call dr_hook('radiation_single_level:get_albedos',0,hook_handle) 240 242 241 ! Albedos/emissivities are stored in single_level in their own 242 ! spectral intervals and with column as the first dimension 243 if (config%use_canopy_full_spectrum_sw) then 244 ! Albedos provided in each g point 245 sw_albedo_diffuse = transpose(this%sw_albedo(istartcol:iendcol,:)) 246 if (allocated(this%sw_albedo_direct)) then 247 sw_albedo_direct = transpose(this%sw_albedo_direct(istartcol:iendcol,:)) 248 end if 249 elseif (.not. config%do_nearest_spectral_sw_albedo) then 250 ! Albedos averaged accurately to ecRad spectral bands 251 nalbedoband = size(config%sw_albedo_weights,1) 252 sw_albedo_band = 0.0_jprb 253 do jband = 1,config%n_bands_sw 254 do jalbedoband = 1,nalbedoband 255 if (config%sw_albedo_weights(jalbedoband,jband) /= 0.0_jprb) then 256 sw_albedo_band(istartcol:iendcol,jband) & 257 & = sw_albedo_band(istartcol:iendcol,jband) & 258 & + config%sw_albedo_weights(jalbedoband,jband) & 259 & * this%sw_albedo(istartcol:iendcol, jalbedoband) 260 end if 261 end do 262 end do 263 264 sw_albedo_diffuse = transpose(sw_albedo_band(istartcol:iendcol, & 265 & config%i_band_from_reordered_g_sw)) 266 if (allocated(this%sw_albedo_direct)) then 243 if (config%do_sw) then 244 ! Albedos/emissivities are stored in single_level in their own 245 ! spectral intervals and with column as the first dimension 246 if (config%use_canopy_full_spectrum_sw) then 247 ! Albedos provided in each g point 248 if (size(this%sw_albedo,2) /= config%n_g_sw) then 249 write(nulerr,'(a,i0,a)') '*** Error: single_level%sw_albedo does not have the expected ', & 250 & config%n_g_sw, ' spectral intervals' 251 call radiation_abort() 252 end if 253 sw_albedo_diffuse = transpose(this%sw_albedo(istartcol:iendcol,:)) 254 if (allocated(this%sw_albedo_direct)) then 255 sw_albedo_direct = transpose(this%sw_albedo_direct(istartcol:iendcol,:)) 256 end if 257 else if (.not. config%do_nearest_spectral_sw_albedo) then 258 ! Albedos averaged accurately to ecRad spectral bands 259 nalbedoband = size(config%sw_albedo_weights,1) 260 if (size(this%sw_albedo,2) /= nalbedoband) then 261 write(nulerr,'(a,i0,a)') '*** Error: single_level%sw_albedo does not have the expected ', & 262 & nalbedoband, ' bands' 263 call radiation_abort() 264 end if 265 267 266 sw_albedo_band = 0.0_jprb 268 267 do jband = 1,config%n_bands_sw 269 268 do jalbedoband = 1,nalbedoband 270 269 if (config%sw_albedo_weights(jalbedoband,jband) /= 0.0_jprb) then 271 sw_albedo_band(istartcol:iendcol,jband) & 272 & = sw_albedo_band(istartcol:iendcol,jband) & 273 & + config%sw_albedo_weights(jalbedoband,jband) & 274 & * this%sw_albedo_direct(istartcol:iendcol, jalbedoband) 270 do jcol = istartcol,iendcol 271 sw_albedo_band(jcol,jband) & 272 & = sw_albedo_band(jcol,jband) & 273 & + config%sw_albedo_weights(jalbedoband,jband) & 274 & * this%sw_albedo(jcol, jalbedoband) 275 end do 275 276 end if 276 277 end do 277 278 end do 278 sw_albedo_direct = transpose(sw_albedo_band(istartcol:iendcol, & 279 & config%i_band_from_reordered_g_sw)) 279 280 sw_albedo_diffuse = transpose(sw_albedo_band(istartcol:iendcol, & 281 & config%i_band_from_reordered_g_sw)) 282 if (allocated(this%sw_albedo_direct)) then 283 sw_albedo_band = 0.0_jprb 284 do jband = 1,config%n_bands_sw 285 do jalbedoband = 1,nalbedoband 286 if (config%sw_albedo_weights(jalbedoband,jband) /= 0.0_jprb) then 287 sw_albedo_band(istartcol:iendcol,jband) & 288 & = sw_albedo_band(istartcol:iendcol,jband) & 289 & + config%sw_albedo_weights(jalbedoband,jband) & 290 & * this%sw_albedo_direct(istartcol:iendcol, jalbedoband) 291 end if 292 end do 293 end do 294 sw_albedo_direct = transpose(sw_albedo_band(istartcol:iendcol, & 295 & config%i_band_from_reordered_g_sw)) 296 else 297 sw_albedo_direct = sw_albedo_diffuse 298 end if 280 299 else 281 sw_albedo_direct = sw_albedo_diffuse 300 ! Albedos mapped less accurately to ecRad spectral bands 301 sw_albedo_diffuse = transpose(this%sw_albedo(istartcol:iendcol, & 302 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw))) 303 if (allocated(this%sw_albedo_direct)) then 304 sw_albedo_direct = transpose(this%sw_albedo_direct(istartcol:iendcol, & 305 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw))) 306 else 307 sw_albedo_direct = sw_albedo_diffuse 308 end if 282 309 end if 283 else 284 ! Albedos mapped less accurately to ecRad spectral bands 285 sw_albedo_diffuse = transpose(this%sw_albedo(istartcol:iendcol, & 286 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw))) 287 if (allocated(this%sw_albedo_direct)) then 288 sw_albedo_direct = transpose(this%sw_albedo_direct(istartcol:iendcol, & 289 & config%i_albedo_from_band_sw(config%i_band_from_reordered_g_sw))) 290 else 291 sw_albedo_direct = sw_albedo_diffuse 292 end if 293 end if 294 295 if (present(lw_albedo)) then 310 end if 311 312 if (config%do_lw .and. present(lw_albedo)) then 296 313 if (config%use_canopy_full_spectrum_lw) then 297 314 if (config%n_g_lw /= size(this%lw_emissivity,2)) then 298 write(nulerr,'(a)') '*** Error: single_level%lw_emissivity has the wrong number of spectral intervals' 299 call radiation_abort() 315 write(nulerr,'(a,i0,a)') '*** Error: single_level%lw_emissivity does not have the expected ', & 316 & config%n_g_lw, ' spectral intervals' 317 call radiation_abort() 300 318 end if 301 319 lw_albedo = 1.0_jprb - transpose(this%lw_emissivity(istartcol:iendcol,:)) … … 303 321 ! Albedos averaged accurately to ecRad spectral bands 304 322 nalbedoband = size(config%lw_emiss_weights,1) 323 if (nalbedoband /= size(this%lw_emissivity,2)) then 324 write(nulerr,'(a,i0,a)') '*** Error: single_level%lw_emissivity does not have the expected ', & 325 & nalbedoband, ' bands' 326 call radiation_abort() 327 end if 305 328 lw_albedo_band = 0.0_jprb 306 329 do jband = 1,config%n_bands_lw 307 330 do jalbedoband = 1,nalbedoband 308 331 if (config%lw_emiss_weights(jalbedoband,jband) /= 0.0_jprb) then 309 lw_albedo_band(istartcol:iendcol,jband) & 310 & = lw_albedo_band(istartcol:iendcol,jband) & 311 & + config%lw_emiss_weights(jalbedoband,jband) & 312 & * (1.0_jprb-this%lw_emissivity(istartcol:iendcol, jalbedoband)) 332 do jcol = istartcol,iendcol 333 lw_albedo_band(jcol,jband) & 334 & = lw_albedo_band(jcol,jband) & 335 & + config%lw_emiss_weights(jalbedoband,jband) & 336 & * (1.0_jprb-this%lw_emissivity(jcol, jalbedoband)) 337 end do 313 338 end if 314 339 end do … … 335 360 336 361 use yomhook, only : lhook, dr_hook 337 use radiation_c onfig,only : out_of_bounds_1d, out_of_bounds_2d362 use radiation_check, only : out_of_bounds_1d, out_of_bounds_2d 338 363 339 364 class(single_level_type), intent(inout) :: this -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_spartacus_lw.F90
r3908 r4444 66 66 use radiation_matrix 67 67 use radiation_two_stream, only : calc_two_stream_gammas_lw, & 68 calc_reflectance_transmittance_lw, LwDiffusivity 68 calc_reflectance_transmittance_lw, LwDiffusivityWP 69 69 use radiation_lw_derivatives, only : calc_lw_derivatives_matrix 70 70 use radiation_constants, only : Pi, GasConstantDryAir, & … … 615 615 planck_top(1:ng3D,nreg+jreg) = od_region(1:ng3D,jreg) & 616 616 & *(1.0_jprb-ssa_region(1:ng3D,jreg))*region_fracs(jreg,jlev,jcol) & 617 & *planck_hl(1:ng3D,jlev,jcol)*LwDiffusivity 617 & *planck_hl(1:ng3D,jlev,jcol)*LwDiffusivityWP 618 618 planck_top(1:ng3D,jreg) = -planck_top(1:ng3D,nreg+jreg) 619 619 planck_diff(1:ng3D,nreg+jreg) = od_region(1:ng3D,jreg) & 620 620 & * (1.0_jprb-ssa_region(1:ng3D,jreg))*region_fracs(jreg,jlev,jcol) & 621 621 & * (planck_hl(1:ng3D,jlev+1,jcol) & 622 & -planck_hl(1:ng3D,jlev,jcol))*LwDiffusivity 622 & -planck_hl(1:ng3D,jlev,jcol))*LwDiffusivityWP 623 623 planck_diff(1:ng3D,jreg) = -planck_diff(1:ng3D,nreg+jreg) 624 624 end do -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_spartacus_sw.F90
r3908 r4444 1303 1303 transfer_scaling = 1.0_jprb - (1.0_jprb - config%overhang_factor) & 1304 1304 & * cloud%overlap_param(jcol,jlev-1) & 1305 & * min(region_fracs(jreg,jlev,jcol), region_fracs(jreg,jlev-1,jcol)) 1305 & * min(region_fracs(jreg,jlev,jcol), region_fracs(jreg,jlev-1,jcol)) & 1306 1306 & / max(config%cloud_fraction_threshold, region_fracs(jreg,jlev,jcol)) 1307 1307 do jreg4 = 1,nreg -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_thermodynamics.F90
r3908 r4444 297 297 298 298 use yomhook, only : lhook, dr_hook 299 use radiation_c onfig,only : out_of_bounds_2d299 use radiation_check, only : out_of_bounds_2d 300 300 301 301 class(thermodynamics_type), intent(inout) :: this -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_tripleclouds_lw.F90
r3908 r4444 18 18 ! 2017-10-23 R. Hogan Renamed single-character variables 19 19 ! 2018-10-08 R. Hogan Call calc_region_properties 20 ! 2020-09-18 R. Hogan Replaced some array expressions with loops 21 ! 2020-09-19 R. Hogan Implement the cloud-only-scattering optimization 20 22 21 23 module radiation_tripleclouds_lw … … 28 30 #include "radiation_optical_depth_scaling.h" 29 31 32 !--------------------------------------------------------------------- 30 33 ! This module contains just one subroutine, the longwave 31 34 ! "Tripleclouds" solver in which cloud inhomogeneity is treated by … … 33 36 ! cloudy (with differing optical depth). This approach was described 34 37 ! by Shonk and Hogan (2008). 35 36 38 subroutine solver_tripleclouds_lw(nlev,istartcol,iendcol, & 37 39 & config, cloud, & … … 48 50 use radiation_regions, only : calc_region_properties 49 51 use radiation_overlap, only : calc_overlap_matrices 50 use radiation_flux, only : flux_type, & 51 & indexed_sum, add_indexed_sum 52 use radiation_flux, only : flux_type, indexed_sum 52 53 use radiation_matrix, only : singlemat_x_vec 53 54 use radiation_two_stream, only : calc_two_stream_gammas_lw, & 54 55 & calc_reflectance_transmittance_lw, & 55 56 & calc_no_scattering_transmittance_lw 57 use radiation_adding_ica_lw, only : adding_ica_lw, calc_fluxes_no_scattering_lw 56 58 use radiation_lw_derivatives, only : calc_lw_derivatives_region 57 59 … … 130 132 ! streams 131 133 real(jprb), dimension(config%n_g_lw, nregions, nlev) & 132 & :: Sup, Sdn 134 & :: source_up, source_dn 135 136 ! Clear-sky reflectance and transmittance 137 real(jprb), dimension(config%n_g_lw, nlev) & 138 & :: ref_clear, trans_clear 133 139 134 140 ! ...clear-sky equivalent 135 141 real(jprb), dimension(config%n_g_lw, nlev) & 136 & :: Sup_clear, Sdn_clear142 & :: source_up_clear, source_dn_clear 137 143 138 144 ! Total albedo of the atmosphere/surface just above a layer … … 147 153 real(jprb), dimension(config%n_g_lw, nregions, nlev+1) :: total_source 148 154 149 ! ...equivalent values for clear-skies150 real(jprb), dimension(config%n_g_lw, nlev+1) :: total_albedo_clear, total_source_clear151 152 155 ! Total albedo and source of the atmosphere just below a layer interface 153 156 real(jprb), dimension(config%n_g_lw, nregions) & … … 160 163 161 164 ! ...clear-sky equivalent (no distinction between "above/below") 162 real(jprb), dimension(config%n_g_lw ) &165 real(jprb), dimension(config%n_g_lw, nlev+1) & 163 166 & :: flux_dn_clear, flux_up_clear 164 167 … … 170 173 ! and below the ground, both treated as single-region clear skies 171 174 logical :: is_clear_sky_layer(0:nlev+1) 175 176 ! Index of the highest cloudy layer 177 integer :: i_cloud_top 172 178 173 179 integer :: jcol, jlev, jg, jreg, jreg2, ng … … 208 214 ! cloud%crop_cloud_fraction has already been called 209 215 is_clear_sky_layer = .true. 216 i_cloud_top = nlev+1 210 217 do jlev = 1,nlev 211 218 if (cloud%fraction(jcol,jlev) > 0.0_jprb) then 212 219 is_clear_sky_layer(jlev) = .false. 220 ! Get index to the first cloudy layer from the top 221 if (i_cloud_top > jlev) then 222 i_cloud_top = jlev 223 end if 213 224 end if 214 225 end do 215 216 ! -------------------------------------------------------- 217 ! Section 3: Loop over layers to compute reflectance and transmittance 226 if (config%do_lw_aerosol_scattering) then 227 ! This is actually the first layer in which we need to 228 ! consider scattering 229 i_cloud_top = 1 230 end if 231 232 ! -------------------------------------------------------- 233 ! Section 3: Clear-sky calculation 234 ! -------------------------------------------------------- 235 236 if (.not. config%do_lw_aerosol_scattering) then 237 ! No scattering in clear-sky flux calculation 238 do jlev = 1,nlev 239 ! Array-wise assignments 240 gamma1 = 0.0_jprb 241 gamma2 = 0.0_jprb 242 call calc_no_scattering_transmittance_lw(ng, od(:,jlev,jcol), & 243 & planck_hl(:,jlev,jcol), planck_hl(:,jlev+1, jcol), & 244 & trans_clear(:,jlev), source_up_clear(:,jlev), source_dn_clear(:,jlev)) 245 ref_clear(:,jlev) = 0.0_jprb 246 end do 247 ! Simple down-then-up method to compute fluxes 248 call calc_fluxes_no_scattering_lw(ng, nlev, & 249 & trans_clear, source_up_clear, source_dn_clear, & 250 & emission(:,jcol), albedo(:,jcol), & 251 & flux_up_clear, flux_dn_clear) 252 else 253 ! Scattering in clear-sky flux calculation 254 do jlev = 1,nlev 255 ! Array-wise assignments 256 gamma1 = 0.0_jprb 257 gamma2 = 0.0_jprb 258 call calc_two_stream_gammas_lw(ng, & 259 & ssa(:,jlev,jcol), g(:,jlev,jcol), gamma1, gamma2) 260 call calc_reflectance_transmittance_lw(ng, & 261 & od(:,jlev,jcol), gamma1, gamma2, & 262 & planck_hl(:,jlev,jcol), planck_hl(:,jlev+1,jcol), & 263 & ref_clear(:,jlev), trans_clear(:,jlev), & 264 & source_up_clear(:,jlev), source_dn_clear(:,jlev)) 265 end do 266 ! Use adding method to compute fluxes 267 call adding_ica_lw(ng, nlev, & 268 & ref_clear, trans_clear, source_up_clear, source_dn_clear, & 269 & emission(:,jcol), albedo(:,jcol), & 270 & flux_up_clear, flux_dn_clear) 271 end if 272 273 if (config%do_clear) then 274 ! Sum over g-points to compute broadband fluxes 275 flux%lw_up_clear(jcol,:) = sum(flux_up_clear,1) 276 flux%lw_dn_clear(jcol,:) = sum(flux_dn_clear,1) 277 ! Store surface spectral downwelling fluxes 278 flux%lw_dn_surf_clear_g(:,jcol) = flux_dn_clear(:,nlev+1) 279 ! Save the spectral fluxes if required 280 if (config%do_save_spectral_flux) then 281 do jlev = 1,nlev+1 282 call indexed_sum(flux_up_clear(:,jlev), & 283 & config%i_spec_from_reordered_g_lw, & 284 & flux%lw_up_clear_band(:,jcol,jlev)) 285 call indexed_sum(flux_dn_clear(:,jlev), & 286 & config%i_spec_from_reordered_g_lw, & 287 & flux%lw_dn_clear_band(:,jcol,jlev)) 288 end do 289 end if 290 end if 291 292 ! -------------------------------------------------------- 293 ! Section 4: Loop over cloudy layers to compute reflectance and transmittance 218 294 ! -------------------------------------------------------- 219 295 ! In this section the reflectance, transmittance and sources 220 296 ! are computed for each layer 221 do jlev = 1,nlev ! Start at top-of-atmosphere 297 298 ! Firstly, ensure clear-sky transmittance is valid for whole 299 ! depth of the atmosphere, because even above cloud it is used 300 ! by the LW derivatives 301 transmittance(:,1,:) = trans_clear(:,:) 302 ! Dummy values in cloudy regions above cloud top 303 if (i_cloud_top > 0) then 304 transmittance(:,2:,1:min(i_cloud_top,nlev)) = 1.0_jprb 305 end if 306 307 do jlev = i_cloud_top,nlev ! Start at cloud top and work down 222 308 223 309 ! Array-wise assignments … … 225 311 gamma2 = 0.0_jprb 226 312 313 ! Copy over clear-sky properties 314 reflectance(:,1,jlev) = ref_clear(:,jlev) 315 source_up(:,1,jlev) = source_up_clear(:,jlev) ! Scaled later by region size 316 source_dn(:,1,jlev) = source_dn_clear(:,jlev) ! Scaled later by region size 227 317 nreg = nregions 228 318 if (is_clear_sky_layer(jlev)) then 229 319 nreg = 1 230 320 reflectance(:,2:,jlev) = 0.0_jprb 231 transmittance(:,2:,jlev) = 0.0_jprb 232 Sup(:,2:,jlev) = 0.0_jprb 233 Sdn(:,2:,jlev) = 0.0_jprb 234 end if 235 do jreg = 1,nreg 236 if (jreg == 1) then 237 ! Clear-sky calculation 238 if (.not. config%do_lw_aerosol_scattering) then 239 call calc_no_scattering_transmittance_lw(ng, od(:,jlev,jcol), & 240 & planck_hl(:,jlev,jcol), planck_hl(:,jlev+1, jcol), & 241 & transmittance(:,1,jlev), Sup(:,1,jlev), Sdn(:,1,jlev)) 242 reflectance(:,1,jlev) = 0.0_jprb 243 else 244 call calc_two_stream_gammas_lw(ng, & 245 & ssa(:,jlev,jcol), g(:,jlev,jcol), gamma1, gamma2) 246 call calc_reflectance_transmittance_lw(ng, & 247 & od(:,jlev,jcol), gamma1, gamma2, & 248 & planck_hl(:,jlev,jcol), planck_hl(:,jlev+1,jcol), & 249 & reflectance(:,1,jlev), transmittance(:,1,jlev), & 250 & Sup(:,1,jlev), Sdn(:,1,jlev)) 251 end if 252 else 321 transmittance(:,2:,jlev) = 1.0_jprb 322 source_up(:,2:,jlev) = 0.0_jprb 323 source_dn(:,2:,jlev) = 0.0_jprb 324 else 325 do jreg = 2,nreg 253 326 ! Cloudy sky 254 327 ! Add scaled cloud optical depth to clear-sky value … … 291 364 & planck_hl(:,jlev,jcol), planck_hl(:,jlev+1,jcol), & 292 365 & reflectance(:,jreg,jlev), transmittance(:,jreg,jlev), & 293 & Sup(:,jreg,jlev), Sdn(:,jreg,jlev))366 & source_up(:,jreg,jlev), source_dn(:,jreg,jlev)) 294 367 else 295 368 ! No-scattering case: use simpler functions for … … 297 370 call calc_no_scattering_transmittance_lw(ng, od_total, & 298 371 & planck_hl(:,jlev,jcol), planck_hl(:,jlev+1, jcol), & 299 & transmittance(:,jreg,jlev), Sup(:,jreg,jlev), Sdn(:,jreg,jlev))372 & transmittance(:,jreg,jlev), source_up(:,jreg,jlev), source_dn(:,jreg,jlev)) 300 373 reflectance(:,jreg,jlev) = 0.0_jprb 301 374 end if 302 end if 303 end do 304 305 ! Copy over the clear-sky emission 306 Sup_clear(:,jlev) = Sup(:,1,jlev) 307 Sdn_clear(:,jlev) = Sdn(:,1,jlev) 308 if (.not. is_clear_sky_layer(jlev)) then 375 end do 309 376 ! Emission is scaled by the size of each region 310 377 do jreg = 1,nregions 311 Sup(:,jreg,jlev) = region_fracs(jreg,jlev,jcol) * Sup(:,jreg,jlev)312 Sdn(:,jreg,jlev) = region_fracs(jreg,jlev,jcol) * Sdn(:,jreg,jlev)378 source_up(:,jreg,jlev) = region_fracs(jreg,jlev,jcol) * source_up(:,jreg,jlev) 379 source_dn(:,jreg,jlev) = region_fracs(jreg,jlev,jcol) * source_dn(:,jreg,jlev) 313 380 end do 314 381 end if … … 317 384 318 385 ! -------------------------------------------------------- 319 ! Section 4: Compute total sources albedos386 ! Section 5: Compute total sources and albedos at each half level 320 387 ! -------------------------------------------------------- 321 388 … … 333 400 end do 334 401 end do 335 ! Equivalent surface values for computing clear-sky fluxes336 if (config%do_clear) then337 do jg = 1,ng338 total_source_clear(jg,nlev+1) = emission(jg,jcol)339 end do340 ! In the case of surface albedo there is no dependence on341 ! cloud fraction so we can copy the all-sky value342 total_albedo_clear(1:ng,nlev+1) = total_albedo(1:ng,1,nlev+1)343 end if344 402 345 403 ! Work up from the surface computing the total albedo of the 346 404 ! atmosphere and the total upwelling due to emission below each 347 405 ! level below using the adding method 348 do jlev = nlev, 1,-1406 do jlev = nlev,i_cloud_top,-1 349 407 350 408 total_albedo_below = 0.0_jprb 351 409 352 if (config%do_clear) then353 ! For clear-skies there is no need to consider "above" and354 ! "below" quantities since with no cloud overlap to worry355 ! about, these are the same356 inv_denom(:,1) = 1.0_jprb &357 & / (1.0_jprb - total_albedo_clear(:,jlev+1)*reflectance(:,1,jlev))358 total_albedo_clear(:,jlev) = reflectance(:,1,jlev) &359 & + transmittance(:,1,jlev)*transmittance(:,1,jlev)*total_albedo_clear(:,jlev+1) &360 & * inv_denom(:,1)361 total_source_clear(:,jlev) = Sup_clear(:,jlev) &362 & + transmittance(:,1,jlev)*(total_source_clear(:,jlev+1) &363 & + total_albedo_clear(:,jlev+1)*Sdn_clear(:,jlev)) &364 & * inv_denom(:,1)365 end if366 367 410 if (is_clear_sky_layer(jlev)) then 368 inv_denom(:,1) = 1.0_jprb &369 & / (1.0_jprb - total_albedo(:,1,jlev+1)*reflectance(:,1,jlev))370 411 total_albedo_below = 0.0_jprb 371 total_albedo_below(:,1) = reflectance(:,1,jlev) &372 & + transmittance(:,1,jlev)*transmittance(:,1,jlev)*total_albedo(:,1,jlev+1) &373 & * inv_denom(:,1)374 412 total_source_below = 0.0_jprb 375 total_source_below(:,1) = Sup(:,1,jlev) & 376 & + transmittance(:,1,jlev)*(total_source(:,1,jlev+1) & 377 & + total_albedo(:,1,jlev+1)*Sdn(:,1,jlev)) & 378 & * inv_denom(:,1) 413 do jg = 1,ng 414 inv_denom(jg,1) = 1.0_jprb & 415 & / (1.0_jprb - total_albedo(jg,1,jlev+1)*reflectance(jg,1,jlev)) 416 total_albedo_below(jg,1) = reflectance(jg,1,jlev) & 417 & + transmittance(jg,1,jlev)*transmittance(jg,1,jlev)*total_albedo(jg,1,jlev+1) & 418 & * inv_denom(jg,1) 419 total_source_below(jg,1) = source_up(jg,1,jlev) & 420 & + transmittance(jg,1,jlev)*(total_source(jg,1,jlev+1) & 421 & + total_albedo(jg,1,jlev+1)*source_dn(jg,1,jlev)) & 422 & * inv_denom(jg,1) 423 end do 379 424 else 380 425 inv_denom = 1.0_jprb / (1.0_jprb - total_albedo(:,:,jlev+1)*reflectance(:,:,jlev)) … … 382 427 & + transmittance(:,:,jlev)*transmittance(:,:,jlev)*total_albedo(:,:,jlev+1) & 383 428 & * inv_denom 384 total_source_below = Sup(:,:,jlev) &429 total_source_below = source_up(:,:,jlev) & 385 430 & + transmittance(:,:,jlev)*(total_source(:,:,jlev+1) & 386 & + total_albedo(:,:,jlev+1)* Sdn(:,:,jlev)) &431 & + total_albedo(:,:,jlev+1)*source_dn(:,:,jlev)) & 387 432 & * inv_denom 388 433 end if … … 415 460 416 461 ! -------------------------------------------------------- 417 ! Section 5: Compute fluxes 418 ! -------------------------------------------------------- 419 420 ! Top-of-atmosphere fluxes into the regions of the top-most 421 ! layer, zero since we assume no diffuse downwelling 422 flux_dn = 0.0_jprb 423 424 if (config%do_clear) then 425 flux_dn_clear = 0.0_jprb 462 ! Section 6: Copy over downwelling fluxes above cloud top 463 ! -------------------------------------------------------- 464 do jlev = 1,i_cloud_top 465 if (config%do_clear) then 466 ! Clear-sky fluxes have already been averaged: use these 467 flux%lw_dn(jcol,jlev) = flux%lw_dn_clear(jcol,jlev) 468 if (config%do_save_spectral_flux) then 469 flux%lw_dn_band(:,jcol,jlev) = flux%lw_dn_clear_band(:,jcol,jlev) 470 end if 471 else 472 flux%lw_dn(jcol,:) = sum(flux_dn_clear(:,jlev)) 473 if (config%do_save_spectral_flux) then 474 call indexed_sum(flux_dn_clear(:,jlev), & 475 & config%i_spec_from_reordered_g_lw, & 476 & flux%lw_dn_band(:,jcol,jlev)) 477 end if 478 end if 479 end do 480 481 ! -------------------------------------------------------- 482 ! Section 7: Compute fluxes up to top-of-atmosphere 483 ! -------------------------------------------------------- 484 485 ! Compute the fluxes just above the highest cloud 486 flux_up(:,1) = total_source(:,1,i_cloud_top) & 487 & + total_albedo(:,1,i_cloud_top)*flux_dn_clear(:,i_cloud_top) 488 flux_up(:,2:) = 0.0_jprb 489 flux%lw_up(jcol,i_cloud_top) = sum(flux_up(:,1)) 490 if (config%do_save_spectral_flux) then 491 call indexed_sum(flux_up(:,1), & 492 & config%i_spec_from_reordered_g_lw, & 493 & flux%lw_up_band(:,jcol,i_cloud_top)) 426 494 end if 427 428 ! Store the TOA broadband fluxes 429 flux%lw_up(jcol,1) = sum(total_source(:,:,1)) 430 flux%lw_dn(jcol,1) = 0.0_jprb 431 if (config%do_clear) then 432 flux%lw_up_clear(jcol,1) = sum(total_source_clear(:,1)) 433 flux%lw_dn_clear(jcol,1) = 0.0_jprb 434 end if 435 436 ! Save the spectral fluxes if required 437 if (config%do_save_spectral_flux) then 438 call indexed_sum(sum(total_source(:,:,1),2), & 439 & config%i_spec_from_reordered_g_lw, & 440 & flux%lw_up_band(:,jcol,1)) 441 flux%lw_dn_band(:,jcol,1) = 0.0_jprb 442 if (config%do_clear) then 443 call indexed_sum(total_source_clear(:,1), & 495 do jlev = i_cloud_top-1,1,-1 496 flux_up(:,1) = trans_clear(:,jlev)*flux_up(:,1) + source_up_clear(:,jlev) 497 flux%lw_up(jcol,jlev) = sum(flux_up(:,1)) 498 if (config%do_save_spectral_flux) then 499 call indexed_sum(flux_up(:,1), & 444 500 & config%i_spec_from_reordered_g_lw, & 445 & flux%lw_up_clear_band(:,jcol,1)) 446 flux%lw_dn_clear_band(:,jcol,1) = 0.0_jprb 447 end if 448 end if 501 & flux%lw_up_band(:,jcol,jlev)) 502 end if 503 end do 504 505 ! -------------------------------------------------------- 506 ! Section 8: Compute fluxes down to surface 507 ! -------------------------------------------------------- 508 509 ! Copy over downwelling spectral fluxes at top of first 510 ! scattering layer, using overlap matrix to translate to the 511 ! regions of the first layer of cloud 512 do jreg = 1,nregions 513 flux_dn(:,jreg) = v_matrix(jreg,1,i_cloud_top,jcol)*flux_dn_clear(:,i_cloud_top) 514 end do 449 515 450 516 ! Final loop back down through the atmosphere to compute fluxes 451 do jlev = 1,nlev 452 if (config%do_clear) then 453 flux_dn_clear = (transmittance(:,1,jlev)*flux_dn_clear & 454 & + reflectance(:,1,jlev)*total_source_clear(:,jlev+1) + Sdn_clear(:,jlev) ) & 455 & / (1.0_jprb - reflectance(:,1,jlev)*total_albedo_clear(:,jlev+1)) 456 flux_up_clear = total_source_clear(:,jlev+1) & 457 & + flux_dn_clear*total_albedo_clear(:,jlev+1) 458 end if 517 do jlev = i_cloud_top,nlev 459 518 460 519 if (is_clear_sky_layer(jlev)) then 461 flux_dn(:,1) = (transmittance(:,1,jlev)*flux_dn(:,1) & 462 & + reflectance(:,1,jlev)*total_source(:,1,jlev+1) + Sdn(:,1,jlev) ) & 463 & / (1.0_jprb - reflectance(:,1,jlev)*total_albedo(:,1,jlev+1)) 520 do jg = 1,ng 521 flux_dn(jg,1) = (transmittance(jg,1,jlev)*flux_dn(jg,1) & 522 & + reflectance(jg,1,jlev)*total_source(jg,1,jlev+1) + source_dn(jg,1,jlev) ) & 523 & / (1.0_jprb - reflectance(jg,1,jlev)*total_albedo(jg,1,jlev+1)) 524 flux_up(jg,1) = total_source(jg,1,jlev+1) + flux_dn(jg,1)*total_albedo(jg,1,jlev+1) 525 end do 464 526 flux_dn(:,2:) = 0.0_jprb 465 flux_up(:,1) = total_source(:,1,jlev+1) + flux_dn(:,1)*total_albedo(:,1,jlev+1)466 527 flux_up(:,2:) = 0.0_jprb 467 528 else 468 529 flux_dn = (transmittance(:,:,jlev)*flux_dn & 469 & + reflectance(:,:,jlev)*total_source(:,:,jlev+1) + Sdn(:,:,jlev) ) &530 & + reflectance(:,:,jlev)*total_source(:,:,jlev+1) + source_dn(:,:,jlev) ) & 470 531 & / (1.0_jprb - reflectance(:,:,jlev)*total_albedo(:,:,jlev+1)) 471 532 flux_up = total_source(:,:,jlev+1) + flux_dn*total_albedo(:,:,jlev+1) … … 485 546 flux%lw_up(jcol,jlev+1) = sum(sum(flux_up,1)) 486 547 flux%lw_dn(jcol,jlev+1) = sum(sum(flux_dn,1)) 487 if (config%do_clear) then488 flux%lw_up_clear(jcol,jlev+1) = sum(flux_up_clear)489 flux%lw_dn_clear(jcol,jlev+1) = sum(flux_dn_clear)490 end if491 548 492 549 ! Save the spectral fluxes if required … … 498 555 & config%i_spec_from_reordered_g_lw, & 499 556 & flux%lw_dn_band(:,jcol,jlev+1)) 500 if (config%do_clear) then 501 call indexed_sum(flux_up_clear, & 502 & config%i_spec_from_reordered_g_lw, & 503 & flux%lw_up_clear_band(:,jcol,jlev+1)) 504 call indexed_sum(flux_dn_clear, & 505 & config%i_spec_from_reordered_g_lw, & 506 & flux%lw_dn_clear_band(:,jcol,jlev+1)) 507 end if 508 end if 557 end if 509 558 510 559 end do ! Final loop over levels … … 513 562 ! are at the surface 514 563 flux%lw_dn_surf_g(:,jcol) = sum(flux_dn,2) 515 if (config%do_clear) then516 flux%lw_dn_surf_clear_g(:,jcol) = flux_dn_clear517 end if518 564 519 565 ! Compute the longwave derivatives needed by Hogan and Bozzo -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_tripleclouds_sw.F90
r3908 r4444 19 19 ! 2018-10-08 R. Hogan Call calc_region_properties 20 20 ! 2019-01-02 R. Hogan Fixed problem of do_save_spectral_flux .and. .not. do_sw_direct 21 ! 2020-09-18 R. Hogan Replaced some array expressions with loops for speed 21 22 22 23 module radiation_tripleclouds_sw … … 32 33 #include "radiation_optical_depth_scaling.h" 33 34 35 !--------------------------------------------------------------------- 34 36 ! This module contains just one subroutine, the shortwave 35 37 ! "Tripleclouds" solver in which cloud inhomogeneity is treated by … … 37 39 ! cloudy (with differing optical depth). This approach was described 38 40 ! by Shonk and Hogan (2008). 39 40 41 subroutine solver_tripleclouds_sw(nlev,istartcol,iendcol, & 41 42 & config, single_level, cloud, & … … 356 357 ! "below" quantities since with no cloud overlap to worry 357 358 ! about, these are the same 358 inv_denom(:,1) = 1.0_jprb & 359 & / (1.0_jprb - total_albedo_clear(:,jlev+1)*reflectance(:,1,jlev)) 360 total_albedo_clear(:,jlev) = reflectance(:,1,jlev) & 361 & + transmittance(:,1,jlev) * transmittance(:,1,jlev) & 362 & * total_albedo_clear(:,jlev+1) * inv_denom(:,1) 363 total_albedo_clear_direct(:,jlev) = ref_dir(:,1,jlev) & 364 & + (trans_dir_dir(:,1,jlev)*total_albedo_clear_direct(:,jlev+1) & 365 & +trans_dir_diff(:,1,jlev)*total_albedo_clear(:,jlev+1)) & 366 & * transmittance(:,1,jlev) * inv_denom(:,1) 359 do jg = 1,ng 360 inv_denom(jg,1) = 1.0_jprb & 361 & / (1.0_jprb - total_albedo_clear(jg,jlev+1)*reflectance(jg,1,jlev)) 362 total_albedo_clear(jg,jlev) = reflectance(jg,1,jlev) & 363 & + transmittance(jg,1,jlev) * transmittance(jg,1,jlev) & 364 & * total_albedo_clear(jg,jlev+1) * inv_denom(jg,1) 365 total_albedo_clear_direct(jg,jlev) = ref_dir(jg,1,jlev) & 366 & + (trans_dir_dir(jg,1,jlev)*total_albedo_clear_direct(jg,jlev+1) & 367 & +trans_dir_diff(jg,1,jlev)*total_albedo_clear(jg,jlev+1)) & 368 & * transmittance(jg,1,jlev) * inv_denom(jg,1) 369 end do 367 370 end if 368 371 369 372 if (is_clear_sky_layer(jlev)) then 370 inv_denom(:,1) = 1.0_jprb & 371 & / (1.0_jprb - total_albedo(:,1,jlev+1)*reflectance(:,1,jlev)) 372 total_albedo_below(:,1) = reflectance(:,1,jlev) & 373 & + transmittance(:,1,jlev) * transmittance(:,1,jlev) & 374 & * total_albedo(:,1,jlev+1) * inv_denom(:,1) 375 total_albedo_below_direct(:,1) = ref_dir(:,1,jlev) & 376 & + (trans_dir_dir(:,1,jlev)*total_albedo_direct(:,1,jlev+1) & 377 & +trans_dir_diff(:,1,jlev)*total_albedo(:,1,jlev+1)) & 378 & * transmittance(:,1,jlev) * inv_denom(:,1) 373 do jg = 1,ng 374 inv_denom(jg,1) = 1.0_jprb & 375 & / (1.0_jprb - total_albedo(jg,1,jlev+1)*reflectance(jg,1,jlev)) 376 total_albedo_below(jg,1) = reflectance(jg,1,jlev) & 377 & + transmittance(jg,1,jlev) * transmittance(jg,1,jlev) & 378 & * total_albedo(jg,1,jlev+1) * inv_denom(jg,1) 379 total_albedo_below_direct(jg,1) = ref_dir(jg,1,jlev) & 380 & + (trans_dir_dir(jg,1,jlev)*total_albedo_direct(jg,1,jlev+1) & 381 & +trans_dir_diff(jg,1,jlev)*total_albedo(jg,1,jlev+1)) & 382 & * transmittance(jg,1,jlev) * inv_denom(jg,1) 383 end do 379 384 else 380 385 inv_denom = 1.0_jprb / (1.0_jprb - total_albedo(:,:,jlev+1)*reflectance(:,:,jlev)) … … 488 493 do jlev = 1,nlev 489 494 if (config%do_clear) then 490 flux_dn_clear = (transmittance(:,1,jlev)*flux_dn_clear + direct_dn_clear & 491 & * (trans_dir_dir(:,1,jlev)*total_albedo_clear_direct(:,jlev+1)*reflectance(:,1,jlev) & 492 & + trans_dir_diff(:,1,jlev) )) & 493 & / (1.0_jprb - reflectance(:,1,jlev)*total_albedo_clear(:,jlev+1)) 494 direct_dn_clear = trans_dir_dir(:,1,jlev)*direct_dn_clear 495 flux_up_clear = direct_dn_clear*total_albedo_clear_direct(:,jlev+1) & 496 & + flux_dn_clear*total_albedo_clear(:,jlev+1) 495 do jg = 1,ng 496 flux_dn_clear(jg) = (transmittance(jg,1,jlev)*flux_dn_clear(jg) + direct_dn_clear(jg) & 497 & * (trans_dir_dir(jg,1,jlev)*total_albedo_clear_direct(jg,jlev+1)*reflectance(jg,1,jlev) & 498 & + trans_dir_diff(jg,1,jlev) )) & 499 & / (1.0_jprb - reflectance(jg,1,jlev)*total_albedo_clear(jg,jlev+1)) 500 direct_dn_clear(jg) = trans_dir_dir(jg,1,jlev)*direct_dn_clear(jg) 501 flux_up_clear(jg) = direct_dn_clear(jg)*total_albedo_clear_direct(jg,jlev+1) & 502 & + flux_dn_clear(jg)*total_albedo_clear(jg,jlev+1) 503 end do 497 504 end if 498 505 499 506 if (is_clear_sky_layer(jlev)) then 500 flux_dn(:,1) = (transmittance(:,1,jlev)*flux_dn(:,1) + direct_dn(:,1) & 501 & * (trans_dir_dir(:,1,jlev)*total_albedo_direct(:,1,jlev+1)*reflectance(:,1,jlev) & 502 & + trans_dir_diff(:,1,jlev) )) & 503 & / (1.0_jprb - reflectance(:,1,jlev)*total_albedo(:,1,jlev+1)) 504 direct_dn(:,1) = trans_dir_dir(:,1,jlev)*direct_dn(:,1) 505 flux_up(:,1) = direct_dn(:,1)*total_albedo_direct(:,1,jlev+1) & 506 & + flux_dn(:,1)*total_albedo(:,1,jlev+1) 507 do jg = 1,ng 508 flux_dn(jg,1) = (transmittance(jg,1,jlev)*flux_dn(jg,1) + direct_dn(jg,1) & 509 & * (trans_dir_dir(jg,1,jlev)*total_albedo_direct(jg,1,jlev+1)*reflectance(jg,1,jlev) & 510 & + trans_dir_diff(jg,1,jlev) )) & 511 & / (1.0_jprb - reflectance(jg,1,jlev)*total_albedo(jg,1,jlev+1)) 512 direct_dn(jg,1) = trans_dir_dir(jg,1,jlev)*direct_dn(jg,1) 513 flux_up(jg,1) = direct_dn(jg,1)*total_albedo_direct(jg,1,jlev+1) & 514 & + flux_dn(jg,1)*total_albedo(jg,1,jlev+1) 515 end do 516 507 517 flux_dn(:,2:) = 0.0_jprb 508 518 flux_up(:,2:) = 0.0_jprb -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_two_stream.F90
r3908 r4444 18 18 ! 2017-07-26 R Hogan Added calc_frac_scattered_diffuse_sw routine 19 19 ! 2017-10-23 R Hogan Renamed single-character variables 20 ! 2021-02-19 R Hogan Security for shortwave singularity 20 21 21 22 module radiation_two_stream … … 31 32 ! think of acos(1/lw_diffusivity) to be the effective zenith angle 32 33 ! of longwave radiation. 33 real(jprd), parameter :: LwDiffusivity = 1.66_jprd 34 real(jprd), parameter :: LwDiffusivity = 1.66_jprd 35 real(jprb), parameter :: LwDiffusivityWP = 1.66_jprb ! Working precision version 34 36 35 37 ! Shortwave diffusivity factor assumes hemispheric isotropy, assumed … … 87 89 if (lhook) call dr_hook('radiation_two_stream:calc_two_stream_gammas_lw',0,hook_handle) 88 90 #endif 89 91 ! Added for DWD (2020) 92 !NEC$ shortloop 90 93 do jg = 1, ng 91 94 ! Fu et al. (1997), Eq 2.9 and 2.10: … … 136 139 ! Zdunkowski "PIFM" (Zdunkowski et al., 1980; Contributions to 137 140 ! Atmospheric Physics 53, 147-66) 141 ! Added for DWD (2020) 142 !NEC$ shortloop 138 143 do jg = 1, ng 139 144 ! gamma1(jg) = 2.0_jprb - ssa(jg) * (1.25_jprb + 0.75_jprb*g(jg)) … … 205 210 #endif 206 211 212 ! Added for DWD (2020) 213 !NEC$ shortloop 207 214 do jg = 1, ng 208 215 if (od(jg) > 1.0e-3_jprd) then … … 293 300 #endif 294 301 302 ! Added for DWD (2020) 303 !NEC$ shortloop 295 304 do jg = 1, ng 296 305 k_exponent = sqrt(max((gamma1(jg) - gamma2(jg)) * (gamma1(jg) + gamma2(jg)), & … … 359 368 #endif 360 369 370 ! Added for DWD (2020) 371 !NEC$ shortloop 361 372 do jg = 1, ng 362 373 ! Compute upward and downward emission assuming the Planck … … 450 461 integer :: jg 451 462 463 ! Local value of cosine of solar zenith angle, in case it needs to be 464 ! tweaked to avoid near division by zero. This is intentionally in working 465 ! precision (jprb) rather than fixing at double precision (jprd). 466 real(jprb) :: mu0_local 467 452 468 #ifdef DO_DR_HOOK_TWO_STREAM 453 469 real(jprb) :: hook_handle … … 456 472 #endif 457 473 474 ! Added for DWD (2020) 475 !NEC$ shortloop 458 476 do jg = 1, ng 459 od_over_mu0 = max(od(jg) / mu0, 0.0_jprd) 460 ! In the IFS this appears to be faster without testing the value 461 ! of od_over_mu0: 462 if (.true.) then 463 ! if (od_over_mu0 > 1.0e-6_jprd) then 477 464 478 gamma4 = 1.0_jprd - gamma3(jg) 465 479 alpha1 = gamma1(jg)*gamma4 + gamma2(jg)*gamma3(jg) ! Eq. 16 466 480 alpha2 = gamma1(jg)*gamma3(jg) + gamma2(jg)*gamma4 ! Eq. 17 467 481 482 k_exponent = sqrt(max((gamma1(jg) - gamma2(jg)) * (gamma1(jg) + gamma2(jg)), & 483 & 1.0e-12_jprd)) ! Eq 18 484 485 ! We had a rare crash where k*mu0 was within around 1e-13 of 1, 486 ! leading to ref_dir and trans_dir_diff being well outside the range 487 ! 0-1. The following approach is appropriate when k_exponent is double 488 ! precision and mu0_local is single precision, although work is needed 489 ! to make this entire routine secure in single precision. 490 mu0_local = mu0 491 if (abs(1.0_jprd - k_exponent*mu0) < 1000.0_jprd * epsilon(1.0_jprd)) then 492 mu0_local = mu0 * (1.0_jprb - 10.0_jprb*epsilon(1.0_jprb)) 493 end if 494 495 od_over_mu0 = max(od(jg) / mu0_local, 0.0_jprd) 496 468 497 ! Note that if the minimum value is reduced (e.g. to 1.0e-24) 469 498 ! then noise starts to appear as a function of solar zenith 470 499 ! angle 471 k_exponent = sqrt(max((gamma1(jg) - gamma2(jg)) * (gamma1(jg) + gamma2(jg)), & 472 & 1.0e-12_jprd)) ! Eq 18 473 k_mu0 = k_exponent*mu0 500 k_mu0 = k_exponent*mu0_local 474 501 k_gamma3 = k_exponent*gamma3(jg) 475 502 k_gamma4 = k_exponent*gamma4 … … 482 509 k_2_exponential = 2.0_jprd * k_exponent * exponential 483 510 484 if (k_mu0 == 1.0_jprd) then485 k_mu0 = 1.0_jprd - 10.0_jprd*epsilon(1.0_jprd)486 end if487 488 511 reftrans_factor = 1.0_jprd / (k_exponent + gamma1(jg) + (k_exponent - gamma1(jg))*exponential2) 489 512 … … 498 521 ! to be the flux into a plane perpendicular to the direction of 499 522 ! the sun, not into a horizontal plane 500 reftrans_factor = mu0 * ssa(jg) * reftrans_factor / (1.0_jprd - k_mu0*k_mu0)523 reftrans_factor = mu0_local * ssa(jg) * reftrans_factor / (1.0_jprd - k_mu0*k_mu0) 501 524 502 525 ! Meador & Weaver (1980) Eq. 14, multiplying top & bottom by … … 505 528 & * ( (1.0_jprd - k_mu0) * (alpha2 + k_gamma3) & 506 529 & -(1.0_jprd + k_mu0) * (alpha2 - k_gamma3)*exponential2 & 507 & -k_2_exponential*(gamma3(jg) - alpha2*mu0 )*exponential0)530 & -k_2_exponential*(gamma3(jg) - alpha2*mu0_local)*exponential0) 508 531 509 532 ! Meador & Weaver (1980) Eq. 15, multiplying top & bottom by 510 533 ! exp(-k_exponent*od), minus the 1*exp(-od/mu0) term representing direct 511 534 ! unscattered transmittance. 512 trans_dir_diff(jg) = reftrans_factor * ( k_2_exponential*(gamma4 + alpha1*mu0 ) &535 trans_dir_diff(jg) = reftrans_factor * ( k_2_exponential*(gamma4 + alpha1*mu0_local) & 513 536 & - exponential0 & 514 537 & * ( (1.0_jprd + k_mu0) * (alpha1 + k_gamma4) & 515 538 & -(1.0_jprd - k_mu0) * (alpha1 - k_gamma4) * exponential2) ) 516 539 517 else 518 ! Low optical-depth limit; see equations 19, 20 and 27 from 519 ! Meador & Weaver (1980) 520 trans_diff(jg) = 1.0_jprb - gamma1(jg) * od(jg) 521 ref_diff(jg) = gamma2(jg) * od(jg) 522 trans_dir_diff(jg) = (1.0_jprb - gamma3(jg)) * ssa(jg) * od(jg) 523 ref_dir(jg) = gamma3(jg) * ssa(jg) * od(jg) 524 trans_dir_dir(jg) = 1.0_jprd - od_over_mu0 525 end if 540 ! Final check that ref_dir + trans_dir_diff <= 1 541 ref_dir(jg) = max(0.0_jprb, min(ref_dir(jg), 1.0_jprb)) 542 trans_dir_diff(jg) = max(0.0_jprb, min(trans_dir_diff(jg), 1.0_jprb-ref_dir(jg))) 543 526 544 end do 527 545 … … 587 605 #endif 588 606 607 ! Added for DWD (2020) 608 !NEC$ shortloop 589 609 do jg = 1, ng 590 610 od_over_mu0 = max(gamma0(jg) * depth, 0.0_jprd) … … 699 719 #endif 700 720 721 ! Added for DWD (2020) 722 !NEC$ shortloop 701 723 do jg = 1, ng 702 724 ! Note that if the minimum value is reduced (e.g. to 1.0e-24) -
LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/random_numbers_mix.F90
r4355 r4444 239 239 ! Generate uniformly distributed random numbers in the range 0.0<= px < 1.0 240 240 !-------------------------------------------------------------------------------- 241 ! INTEGER(KIND=JPIM), PARAMETER :: IVAR=Z"3FFFFFFF" 242 INTEGER(KIND=JPIM) :: IVAR 243 DATA IVAR /Z"3FFFFFFF"/ 241 INTEGER(KIND=JPIM), PARAMETER :: IVAR = INT(Z"3FFFFFFF",JPIM) 244 242 TYPE(RANDOMNUMBERSTREAM), INTENT(INOUT) :: YD_STREAM 245 243 REAL(KIND=JPRB), DIMENSION(:), INTENT( OUT) :: PX 244 246 245 INTEGER(KIND=JPIM) :: JJ, JK, IN, IFILLED 247 246 … … 253 252 IF(YD_STREAM%INITTEST /= INITVALUE) & 254 253 & CALL ABOR1 ('uniform_distribution called before initialize_random_numbers') 255 254 256 255 !-------------------------------------------------------------------------------- 257 256 ! Copy numbers that were generated during the last call, but not used.
Note: See TracChangeset
for help on using the changeset viewer.