Changeset 4444 for LMDZ6/branches


Ignore:
Timestamp:
Feb 21, 2023, 3:26:41 PM (15 months ago)
Author:
idelkadi
Message:

Update of the ECRAD radiative code version implemented in the LMDZ model.
Upgrade to the :
https://github.com/ecmwf/ecrad/trunk
Version svn : 749
UUID du dépôt : 44b0ca93-0ed8-356e-d663-ce57b7db7bff

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  
    3535  ! a NetCDF file
    3636  type netcdf_file
    37     integer :: ncid             ! NetCDF file ID
     37    integer :: ncid = -1! NetCDF file ID
    3838    integer :: iverbose ! Verbosity: 0 = report only fatal errors,
    3939                        !            1 = ...and warnings,
     
    5555    procedure :: create => create_netcdf_file
    5656    procedure :: close => close_netcdf_file
     57    procedure :: is_open
    5758    procedure :: get_real_scalar
     59    procedure :: get_int_scalar
    5860    procedure :: get_real_vector
    59     procedure :: get_integer_vector
     61    procedure :: get_int_vector
    6062    procedure :: get_real_matrix
    6163    procedure :: get_real_array3
     
    6567    procedure :: get_real_array3_indexed
    6668    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, &
    6873         &              get_real_matrix, get_real_array3, &
    69          &              get_real_array4, get_integer_vector, &
     74         &              get_real_array4, &
    7075         &              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
    7278    procedure :: get_real_scalar_attribute
    7379    procedure :: get_string_attribute
     
    8389    procedure :: put_real_scalar
    8490    procedure :: put_real_vector
     91    procedure :: put_int_vector
    8592    procedure :: put_real_matrix
    8693    procedure :: put_real_array3
     
    9198         &              put_real_matrix, put_real_array3, &
    9299         &              put_real_scalar_indexed, put_real_vector_indexed, &
    93          &              put_real_matrix_indexed
     100         &              put_real_matrix_indexed, put_int_vector
    94101    procedure :: set_verbose
    95102    procedure :: transpose_matrices
     
    101108    procedure :: attribute_exists
    102109    procedure :: global_attribute_exists
     110#ifdef NC_NETCDF4
     111    procedure :: copy_dimensions
     112#endif
     113    procedure :: copy_variable_definition
     114    procedure :: copy_variable
    103115    procedure, private :: get_array_dimensions
    104116    procedure, private :: get_variable_id
     
    257269    end if
    258270
     271    this%ncid = -1
     272
    259273  end subroutine close_netcdf_file
    260274
     
    367381
    368382    integer                        :: j, istatus
    369     integer                        :: dimids(NF90_MAX_VAR_DIMS)
     383    integer                        :: idimids(NF90_MAX_VAR_DIMS)
    370384
    371385    istatus = nf90_inquire_variable(this%ncid, ivarid, &
    372          &                          ndims=ndims, dimids=dimids)
     386         &                          ndims=ndims, dimids=idimids)
    373387    if (istatus /= NF90_NOERR) then
    374388      write(nulerr,'(a,i0,a,a)') '*** Error inquiring about NetCDF variable with id ', &
     
    379393    ndimlens(:) = 0
    380394    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))
    382396      if (istatus /= NF90_NOERR) then
    383397        write(nulerr,'(a,i0,a,i0,a,a)') '*** Error reading length of dimension ', &
     
    420434
    421435  !---------------------------------------------------------------------
     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  !---------------------------------------------------------------------
    422444  ! Return the number of dimensions of variable with name var_name, or
    423445  ! -1 if the variable is not found
     
    619641
    620642  !---------------------------------------------------------------------
     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  !---------------------------------------------------------------------
    621688  ! Read a scalar from a larger array, where "index" indexes the most
    622689  ! 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)
    624691    class(netcdf_file)           :: this
    625692    character(len=*), intent(in) :: var_name
     
    676743
    677744  !---------------------------------------------------------------------
    678   ! Read a 1D array into "vector", which must be allocatable and will
    679   ! be reallocated if necessary
     745  ! Read a 1D real array into "vector", which must be allocatable and
     746  ! will be reallocated if necessary
    680747  subroutine get_real_vector(this, var_name, vector)
    681748    class(netcdf_file)           :: this
     
    734801
    735802  !---------------------------------------------------------------------
    736   ! Read a 1D integer array into "vector", which must be allocatable
     803  ! Read a 1D character array into "vector", which must be allocatable
    737804  ! and will be reallocated if necessary
    738   subroutine get_integer_vector(this, var_name, vector)
     805  subroutine get_char_vector(this, var_name, vector)
    739806    class(netcdf_file)           :: this
    740807    character(len=*), intent(in) :: var_name
    741     integer, allocatable, intent(out) :: vector(:)
     808    character(len=1), allocatable, intent(out) :: vector(:)
    742809
    743810    integer                      :: n  ! Length of vector
     
    784851    if (istatus /= NF90_NOERR) then
    785852      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 ', &
    786912           &  var_name, ' as an integer vector: ', trim(nf90_strerror(istatus))
    787913      call my_abort('Error reading NetCDF file')
    788914    end if
    789915
    790   end subroutine get_integer_vector
    791 
     916  end subroutine get_int_vector
    792917
    793918  !---------------------------------------------------------------------
    794919  ! Read a vector of data from a larger array; the vector must be
    795920  ! 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)
    797922    class(netcdf_file)           :: this
    798923    character(len=*), intent(in) :: var_name
     
    9751100
    9761101  !---------------------------------------------------------------------
     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  !---------------------------------------------------------------------
    9771220  ! Read matrix of data from a larger array, which must be allocatable
    9781221  ! and will be reallocated if necessary.  Whether to transpose is
    9791222  ! specifed by the final optional argument, but can also be specified
    9801223  ! 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)
    9821225    class(netcdf_file)           :: this
    9831226    character(len=*), intent(in) :: var_name
     
    11871430      if (this%iverbose >= 3) then
    11881431        write(nulout,'(a,a,a,i0,i0,i0,a)',advance='no') '  Reading ', var_name, &
    1189              & ' (permuted dimensions ', i_permute_3d, ')'
     1432             & ' (permuting dimensions ', i_permute_3d, ')'
    11901433        call this%print_variable_attributes(ivarid,nulout)
    11911434      end if
     
    12351478  ! be allocatable and will be reallocated if necessary.  Whether to
    12361479  ! 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)
    12381481    class(netcdf_file)                   :: this
    12391482    character(len=*), intent(in)         :: var_name
     
    13311574        write(nulout,'(a,i0,a,a,a,i0,i0,i0,a)') '  Reading slice ', index, &
    13321575             &  ' of ', var_name, &
    1333              & ' (permuted dimensions ', i_permute_3d, ')'
     1576             & ' (permuting dimensions ', i_permute_3d, ')'
    13341577      end if
    13351578
     
    14711714      if (this%iverbose >= 3) then
    14721715        write(nulout,'(a,a,a,i0,i0,i0,a)',advance='no') '  Reading ', var_name, &
    1473              & ' (permuted dimensions ', i_permute_4d, ')'
     1716             & ' (permuting dimensions ', i_permute_4d, ')'
    14741717        call this%print_variable_attributes(ivarid,nulout)
    14751718      end if
     
    15491792    !    allocate(character(len=i_attr_len) :: attr_str)
    15501793    if (len(attr_str) < i_attr_len) then
    1551       write(nulerr,'(a,a)') '*** Error: not enough space to read attribute ', attr_name
     1794      write(nulerr,'(a,a)') '*** Not enough space to read attribute ', attr_name
    15521795      call my_abort('Error reading NetCDF file')
    15531796    end if
     
    15771820    real(jprb),       intent(out) :: attr
    15781821
    1579     integer :: i_attr_len, ivarid
     1822    integer :: ivarid
    15801823    integer :: istatus
    1581     integer :: j
    15821824
    15831825    istatus = nf90_inq_varid(this%ncid, var_name, ivarid)
     
    16241866    !    allocate(character(len=i_attr_len) :: attr_str)
    16251867    if (len(attr_str) < i_attr_len) then
    1626       write(nulerr,'(a,a)') '*** Error: not enough space to read global attribute ', attr_name
     1868      write(nulerr,'(a,a)') '*** Not enough space to read global attribute ', attr_name
    16271869      call my_abort('Error reading NetCDF file')
    16281870    end if
     
    16521894
    16531895    character(len=4000) :: attr_str
    1654     integer :: i_attr_len
    16551896    integer :: istatus
    1656     integer :: j
    16571897
    16581898    if (this%iverbose >= 4) then
    16591899      istatus = nf90_get_att(this%ncid, ivarid, 'long_name', attr_str)
    16601900      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), '"'
    16631902        istatus = nf90_get_att(this%ncid, ivarid, 'units', attr_str)
    16641903        if (istatus == NF90_NOERR) then
     
    17211960  ! names.
    17221961  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)
    17251965    class(netcdf_file)                     :: this
    17261966    character(len=*), intent(in)           :: var_name
    17271967    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
    17291969    logical,          intent(in), optional :: is_double
    17301970    character(len=*), intent(in), optional :: data_type_name
     
    17331973    logical,          intent(in), optional :: shuffle ! Shuffle bytes before compression
    17341974    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
    17371978    integer, dimension(NF90_MAX_VAR_DIMS) :: idimids
    17381979    integer :: data_type
    17391980
    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
    17411990      ! Variable is at least one dimensional
    1742       ndims = 1
     1991      ndims_local = 1
    17431992      istatus = nf90_inq_dimid(this%ncid, dim1_name, idimids(1))
    17441993      if (istatus /= NF90_NOERR) then
     
    17471996        call my_abort('Error writing NetCDF file')
    17481997      end if
    1749       if (present(dim2_name)) then
     1998      if (present(dim2_name) .and. ndims_input >= 2) then
    17501999        ! Variable is at least two dimensional
    1751         ndims = 2
     2000        ndims_local = 2
    17522001        istatus = nf90_inq_dimid(this%ncid, dim2_name, idimids(2))
    17532002        if (istatus /= NF90_NOERR) then
     
    17562005          call my_abort('Error writing NetCDF file')
    17572006        end if
    1758         if (present(dim3_name)) then
     2007        if (present(dim3_name) .and. ndims_input >= 3) then
    17592008          ! Variable is at least three dimensional
    1760           ndims = 3
     2009          ndims_local = 3
    17612010          istatus = nf90_inq_dimid(this%ncid, dim3_name, idimids(3))
    17622011          if (istatus /= NF90_NOERR) then
     
    17652014            call my_abort('Error writing NetCDF file')
    17662015          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
    17672026        end if
    17682027      end if
    17692028    else
    17702029      ! Variable is a scalar
    1771       ndims = 0
     2030      ndims_local = 0
    17722031    end if
    17732032
    17742033    ! Read output precision from optional argument "is_double" if
    17752034    ! present, otherwise from default output precision for this file
    1776     data_type = NF90_FLOAT ! Default
    17772035    if (present(data_type_name)) then
    17782036      if (data_type_name == 'double') then
     
    17872045        data_type = NF90_FLOAT
    17882046      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'
    17902048        call my_abort('Error writing NetCDF file')
    17912049      end if
    17922050    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
    17932057      data_type = NF90_DOUBLE
     2058    else
     2059      data_type = NF90_FLOAT
    17942060    end if
    17952061
    17962062    ! Define variable
    17972063#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), &
    17992065         & ivarid, deflate_level=deflate_level, shuffle=shuffle, chunksizes=chunksizes)
    18002066#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)
    18022068#endif
    18032069    if (istatus /= NF90_NOERR) then
     
    18112077      istatus = nf90_put_att(this%ncid, ivarid, "long_name", long_name)
    18122078      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, '"'
    18142081      end if
    18152082    else
    18162083      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
    18202088    if (present(units_str)) then
    18212089      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
    18232103    if (present(standard_name)) then
    18242104      istatus = nf90_put_att(this%ncid, ivarid, "standard_name", standard_name)
     
    18632143  subroutine put_global_attributes(this, title_str, inst_str, source_str, &
    18642144       &  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)
    18662146    class(netcdf_file)                     :: this
    18672147
     
    18722152    character(len=*), intent(in), optional :: contributor_name, project_str
    18732153    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
    18752155
    18762156    character(len=32)   :: date_time_str
     
    18872167         &   time_vals(1), time_vals(2), time_vals(3), time_vals(5), time_vals(6), time_vals(7)
    18882168
    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
    18902175
    18912176    if (present(title_str))   i=nf90_put_att(this%ncid, NF90_GLOBAL, "title", title_str)
     
    20572342
    20582343  !---------------------------------------------------------------------
     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  !---------------------------------------------------------------------
    20592377  ! 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)
    20612379    class(netcdf_file)             :: this
    20622380    character(len=*), intent(in)   :: var_name
    20632381    real(jprb), intent(in)         :: var(:)
    2064     integer, intent(in)            :: index
     2382    integer, intent(in)            :: index2
     2383    integer, intent(in), optional  :: index3
    20652384
    20662385    integer :: ivarid, ndims, istatus
     
    20702389    integer :: vcount(NF90_MAX_VAR_DIMS)
    20712390
     2391    character(len=512) :: var_slice_name
     2392    integer :: index_last
     2393
    20722394    call this%end_define_mode()
    20732395
     
    20762398    call this%get_array_dimensions(ivarid, ndims, ndimlens, ntotal)
    20772399    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
    20782409    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 ', ntotal
     2410      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
    20812412      call my_abort('Error writing NetCDF file')
    20822413    end if
    2083     if (index < 1 .or. index > ndimlens(ndims)) then
    2084       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)
    20862417      call my_abort('Error writing NetCDF file')
    20872418    end if
     
    20892420    ! Save the vector
    20902421    vstart(1:ndims-1) = 1
    2091     vstart(ndims)     = index
    20922422    vcount(1:ndims-1) = ndimlens(1:ndims-1)
    20932423    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
    20942432    istatus = nf90_put_var(this%ncid, ivarid, var, start=vstart, count=vcount)
    20952433    if (istatus /= NF90_NOERR) then
    2096       write(nulerr,'(a,a,a,a)') '*** Error writing vector to ', var_name, ': ', &
    2097            &                    trim(nf90_strerror(istatus))
     2434      write(nulerr,'(a,a,a,a)') '*** Error writing vector to ', trim(var_slice_name), &
     2435           &  ': ', trim(nf90_strerror(istatus))
    20982436      call my_abort('Error writing NetCDF file')
    20992437    end if
     
    21712509  ! dimensions if either optional argument transp is .true., or the
    21722510  ! 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)
    21742512    class(netcdf_file)             :: this
    21752513    character(len=*), intent(in)   :: var_name
    21762514    real(jprb), intent(in)         :: var(:,:)
    2177     integer, intent(in)            :: index
     2515    integer, intent(in)            :: index3
     2516    integer, intent(in), optional  :: index4
    21782517
    21792518    real(jprb), allocatable        :: var_transpose(:,:)
    2180     logical, optional, intent(in):: do_transp
     2519    logical, optional, intent(in)  :: do_transp
    21812520
    21822521    integer :: ivarid, ndims, nvarlen, istatus
     
    21862525    integer :: vcount(NF90_MAX_VAR_DIMS)
    21872526
     2527    character(len=512) :: var_slice_name
     2528
    21882529    logical :: do_transpose
    21892530
     
    22042545    ! ntotal is zero then there must be an unlimited dimension)
    22052546    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
    22062553    if (ntotal /= size(var,kind=jpib) .and. ntotal /= 0) then
    22072554      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 ', ntotal
     2555           & nvarlen, ' to ', trim(var_slice_name), ' which has total size ', ntotal
    22092556      call my_abort('Error writing NetCDF file')
    22102557    end if
    22112558
    22122559    vstart(1:ndims-1) = 1
    2213     vstart(ndims)     = index
    22142560    vcount(1:ndims-1) = ndimlens(1:ndims-1)
    22152561    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
    22162569
    22172570    if (do_transpose) then
    22182571      ! Save the matrix with transposition
    22192572      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), &
    22212574             & ' (transposing dimensions)'
    22222575      end if
     
    22282581      ! Save the matrix without transposition
    22292582      if (this%iverbose >= 3) then
    2230         write(nulout,'(a,i0,a,a)') '  Writing slice ', index, ' of ', var_name
     2583        write(nulout,'(a,a)') '  Writing ', trim(var_slice_name)
    22312584      end if
    22322585      istatus = nf90_put_var(this%ncid, ivarid, var, start=vstart, count=vcount)
     
    22342587
    22352588    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), &
    22372590           &                    ': ', trim(nf90_strerror(istatus))
    22382591      call my_abort('Error writing NetCDF file')
     
    22912644      if (this%iverbose >= 3) then
    22922645        write(nulout,'(a,a,a,i0,i0,i0,a)') '  Writing ', var_name, &
    2293              & ' (permuted dimensions: ', i_permute_3d, ')'
     2646             & ' (permuting dimensions: ', i_permute_3d, ')'
    22942647      end if
    22952648      n_dimlens_permuted = (/ size(var,i_permute_3d(1)), &
    22962649           &                  size(var,i_permute_3d(2)), &
    22972650           &                  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
    23042658      allocate(var_permute(n_dimlens_permuted(1), &
    23052659           &   n_dimlens_permuted(2), n_dimlens_permuted(3)))
     
    23262680  end subroutine put_real_array3
    23272681
     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
    23282901end module easy_netcdf
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_adding_ica_lw.F90

    r3908 r4444  
    296296   
    297297    ! Loop index for model level
    298     integer :: jlev
     298    integer :: jlev, jcol
    299299
    300300    real(jprb) :: hook_handle
     
    307307    ! Work down through the atmosphere computing the downward fluxes
    308308    ! at each half-level
     309! Added for DWD (2020)
     310!NEC$ outerloop_unroll(8)
    309311    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
    311315    end do
    312316
     
    316320    ! Work back up through the atmosphere computing the upward fluxes
    317321    ! at each half-level
     322! Added for DWD (2020)
     323!NEC$ outerloop_unroll(8)
    318324    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
    320328    end do
    321329   
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_adding_ica_sw.F90

    r3908 r4444  
    9898    ! also the "source", which is the upwelling flux due to direct
    9999    ! radiation that is scattered below that level
     100! Added for DWD (2020)
     101!NEC$ outerloop_unroll(8)
    100102    do jlev = nlev,1,-1
    101103      ! Next loop over columns. We could do this by indexing the
     
    128130    ! Work back down through the atmosphere computing the fluxes at
    129131    ! each half-level
     132! Added for DWD (2020)
     133!NEC$ outerloop_unroll(8)
    130134    do jlev = 1,nlev
    131135      do jcol = 1,ncol
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_aerosol.F90

    r3908 r4444  
    115115      allocate(this%g_lw  (config%n_bands_lw,istartlev:iendlev,ncol))
    116116      ! If longwave scattering by aerosol is not to be represented,
    117       ! then the user may wish to just provide absorption optical deth
    118       ! in od_lw, in which case we must set the following two
     117      ! then the user may wish to just provide absorption optical
     118      ! depth in od_lw, in which case we must set the following two
    119119      ! variables to zero
    120120      this%ssa_lw = 0.0_jprb
     
    128128
    129129  !---------------------------------------------------------------------
    130   ! Deallocate array
     130  ! Deallocate arrays
    131131  subroutine deallocate_aerosol_arrays(this)
    132132
     
    158158
    159159    use yomhook,          only : lhook, dr_hook
    160     use radiation_config, only : out_of_bounds_3d
     160    use radiation_check, only : out_of_bounds_3d
    161161
    162162    class(aerosol_type),   intent(inout) :: this
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_aerosol_optics.F90

    r4188 r4444  
    1414!
    1515! 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
    1719
    1820module radiation_aerosol_optics
     
    3638    use radiation_aerosol_optics_data, only : aerosol_optics_type
    3739    use radiation_io,                  only : nulerr, radiation_abort
    38     use setup_aerosol_optics_lmdz_m, only: setup_aerosol_optics_lmdz
     40    use setup_aerosol_optics_lmdz_m,   only: setup_aerosol_optics_lmdz
    3941
    4042    type(config_type), intent(inout) :: config
     
    4749      ! Load data from file and prepare to map config%n_aerosol_types
    4850      ! 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)
    5167
    5268      ! Check agreement in number of bands
    5369      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, ')'
    5573        call radiation_abort()
    5674      end if
     
    6482    end if
    6583
    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
    6787
    6888    if (lhook) call dr_hook('radiation_aerosol_optics:setup_aerosol_optics',1,hook_handle)
    6989
    7090  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
    71779
    72780
     
    89797         &  IAerosolClassUndefined,   IAerosolClassIgnored, &
    90798         &  IAerosolClassHydrophobic, IAerosolClassHydrophilic
    91     USE phys_local_var_mod, ONLY: rhcl
    92799
    93800    integer, intent(in) :: nlev               ! number of model levels
     
    134841
    135842    ! Loop indices for column, level, g point, band and aerosol type
    136     integer :: jcol, jlev, jg, jtype
     843    integer :: jcol, jlev, jg, jtype, jband
    137844
    138845    ! Range of levels over which aerosols are present
     
    141848    ! Indices to spectral band and relative humidity look-up table
    142849    integer :: iband, irh
     850
     851    ! Short cut for ao%itype(jtype)
     852    integer :: itype
    143853
    144854    ! Pointer to the aerosol optics coefficients for brevity of access
     
    182892
    183893      ! Set variables to zero that may not have been previously
    184       g_sw = 0.0_jprb
     894      g_sw(:,:,istartcol:iendcol) = 0.0_jprb
    185895      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)
    192901
    193902      ! Loop over position
     
    197906          ! saturation and the index to the relative-humidity index of
    198907          ! 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)
    204910
    205911          factor = ( thermodynamics%pressure_hl(jcol,jlev+1) &
     
    216922
    217923          do jtype = 1,config%n_aerosol_types
     924
     925            itype = ao%itype(jtype)
     926
    218927            ! Add the optical depth, scattering optical depth and
    219928            ! scattering optical depth-weighted asymmetry factor for
     
    222931            ! dimension being spectral band.
    223932            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
    232943              if (config%do_lw_aerosol_scattering) then
    233944                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)
    235946                od_lw_aerosol = od_lw_aerosol + local_od_lw
    236947                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)
    238949                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)
    241952              else
    242953                ! If aerosol longwave scattering is not included then we
     
    245956                od_lw_aerosol = od_lw_aerosol &
    246957                     &  + 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))
    249960              end if
    250961            else if (ao%iclass(jtype) == IAerosolClassHydrophilic) then
    251962              ! Hydrophilic aerosols require the look-up tables to
    252963              ! 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
    261974              if (config%do_lw_aerosol_scattering) then
    262975                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)
    264977                od_lw_aerosol = od_lw_aerosol + local_od_lw
    265978                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)
    267980                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)
    270983              else
    271984                ! If aerosol longwave scattering is not included then we
     
    274987                od_lw_aerosol = od_lw_aerosol &
    275988                     &  + 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))
    278991              end if
    279992            end if
     
    2951008          ! properties (noting that any gas scattering will have an
    2961009          ! asymmetry factor of zero)
    297           if (od_sw_aerosol(1) > 0.0_jprb) then
    298             do jg = 1,config%n_g_sw
    299               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
    3011014              local_scat = ssa_sw(jg,jlev,jcol) * od_sw(jg,jlev,jcol) &
    3021015                   &  + scat_sw_aerosol(iband)
     
    3041017              ! simply weights the aerosol asymmetry by the scattering
    3051018              ! 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
    3071022              ssa_sw(jg,jlev,jcol) = local_scat / local_od
    3081023              od_sw (jg,jlev,jcol) = local_od
    309             end do
    310           end if
     1024            end if
     1025          end do
    3111026
    3121027          ! Combine aerosol longwave scattering properties with gas
     
    3201035            do jg = 1,config%n_g_lw
    3211036              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
    3231039                ! All scattering is due to aerosols, therefore the
    3241040                ! asymmetry factor is equal to the value for aerosols
     
    3261042                  g_lw(jg,jlev,jcol) = scat_g_lw_aerosol(iband) &
    3271043                       &  / scat_lw_aerosol(iband)
    328                 else
    329                   g_lw(jg,jlev,jcol) = 0.0_jprb
    3301044                end if
    331                 local_od = od_lw(jg,jlev,jcol) + od_lw_aerosol(iband)
    3321045                ssa_lw(jg,jlev,jcol) = scat_lw_aerosol(iband) / local_od
    3331046                od_lw (jg,jlev,jcol) = local_od
     
    3901103    ! a point in space for each spectral band of the shortwave and
    3911104    ! longwave spectrum
    392     real(jprb), dimension(config%n_bands_sw) &
     1105    real(jprb), dimension(config%n_bands_sw,nlev) &
    3931106         & :: od_sw_aerosol, scat_sw_aerosol, scat_g_sw_aerosol
    394     real(jprb), dimension(config%n_bands_lw) :: od_lw_aerosol
    395     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) &
    3961109         & :: scat_lw_aerosol, scat_g_lw_aerosol
    3971110
    3981111    ! Loop indices for column, level, g point and band
    399     integer :: jcol, jlev, jg
     1112    integer :: jcol, jlev, jg, jb
    4001113
    4011114    ! Range of levels over which aerosols are present
     
    4221135
    4231136      ! Set variables to zero that may not have been previously
    424       g_sw = 0.0_jprb
     1137      g_sw(:,:,istartcol:iendcol) = 0.0_jprb
    4251138
    4261139      ! Loop over position
    4271140      do jcol = istartcol,iendcol
     1141! Added for DWD (2020)
     1142!NEC$ forced_collapse
    4281143        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
    4461164            do jg = 1,config%n_g_sw
    4471165              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)
    4491167              local_scat = ssa_sw(jg,jlev,jcol) * od_sw(jg,jlev,jcol) &
    450                    &  + scat_sw_aerosol(iband)
     1168                   &  + scat_sw_aerosol(iband,jlev)
    4511169              ! Note that asymmetry_sw of gases is zero so the following
    4521170              ! simply weights the aerosol asymmetry by the scattering
    4531171              ! 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)
    4551174              ssa_sw(jg,jlev,jcol) = local_scat / local_od
    4561175              od_sw (jg,jlev,jcol) = local_od
     
    4751194
    4761195      if (config%do_lw_aerosol_scattering) then
    477         ssa_lw = 0.0_jprb
    478         g_lw   = 0.0_jprb
     1196        ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb
     1197        g_lw(:,:,istartcol:iendcol)   = 0.0_jprb
    4791198 
    4801199        ! Loop over position
    4811200        do jcol = istartcol,iendcol
     1201! Added for DWD (2020)
     1202!NEC$ forced_collapse
    4821203          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)
    4861208           
    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
    4901214            do jg = 1,config%n_g_lw
    4911215              iband = config%i_band_from_reordered_g_lw(jg)
    492               if (od_lw_aerosol(iband) > 0.0_jprb) then
     1216              if (od_lw_aerosol(iband,jlev) > 0.0_jprb) then
    4931217                ! All scattering is due to aerosols, therefore the
    4941218                ! 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)
    5001222                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_od
     1223                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
    5031225                od_lw (jg,jlev,jcol) = local_od
    5041226              end if
     
    5111233        ! Loop over position
    5121234        do jcol = istartcol,iendcol
     1235! Added for DWD (2020)
     1236!NEC$ forced_collapse
    5131237          do jlev = istartlev,iendlev
    5141238            ! If aerosol longwave scattering is not included then we
    5151239            ! weight the optical depth by the single scattering
    5161240            ! 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
    5191247            do jg = 1,config%n_g_lw
    5201248              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)
    5221250            end do
    5231251          end do
     
    5361264  ! Sometimes it is useful to specify aerosol in terms of its optical
    5371265  ! depth at a particular wavelength.  This function returns the dry
    538   ! shortwave mass-extinction coefficient, i.e. the extinction cross
    539   ! section per unit mass, for aerosol of type "itype" at shortwave
    540   ! band "iband". For hydrophilic types, the value at the first
    541   ! relative humidity 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)
    5431271
    5441272    use parkind1,                      only : jprb
     1273    use radiation_io,                  only : nulerr, radiation_abort
    5451274    use radiation_config,              only : config_type
    5461275    use radiation_aerosol_optics_data, only : aerosol_optics_type, &
     
    5501279    type(config_type), intent(in), target :: config
    5511280
    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
    5541286   
    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
    5561291
    5571292    ! Pointer to the aerosol optics coefficients for brevity of access
     
    5601295    ao => config%aerosol_optics
    5611296
     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
    5621305    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))
    5641307    else if (ao%iclass(itype) == IAerosolClassHydrophilic) then
    5651308      ! Take the value at the first relative-humidity bin for the
    5661309      ! "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))
    5681311    else
    569       dry_aerosol_sw_mass_extinction = 0.0_jprb
    570     end if
    571 
    572   end function dry_aerosol_sw_mass_extinction
     1312      dry_aerosol_mass_extinction = 0.0_jprb
     1313    end if
     1314
     1315  end function dry_aerosol_mass_extinction
    5731316
    5741317
    5751318  !---------------------------------------------------------------------
    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)
    5811323
    5821324    use parkind1,                      only : jprb
     
    5911333    integer, intent(in) :: istartcol, iendcol ! range of columns to process
    5921334    type(config_type), intent(in), target :: config
    593     integer, intent(in)     :: iband ! Index of required spectral band
     1335    real(jprb), intent(in)  :: wavelength ! Requested wavelength (m)
    5941336    real(jprb), intent(in)  :: mixing_ratio(ncol,config%n_aerosol_types)
    5951337    real(jprb), intent(in)  :: relative_humidity(ncol)
     
    5981340    ! Local aerosol extinction
    5991341    real(jprb) :: ext
     1342
     1343    ! Index to the monochromatic wavelength requested
     1344    integer :: imono
    6001345
    6011346    ! Pointer to the aerosol optics coefficients for brevity of access
     
    6101355    real(jprb) :: hook_handle
    6111356
    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)
    6131358
    6141359    do jtype = 1,config%n_aerosol_types
     
    6201365
    6211366    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
    6221375
    6231376    ! Loop over position
     
    6301383        if (ao%iclass(jtype) == IAerosolClassHydrophobic) then
    6311384          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))
    6331386        else if (ao%iclass(jtype) == IAerosolClassHydrophilic) then
    6341387          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))
    6361389        end if
    6371390      end do
     
    6401393    end do
    6411394
    642     if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_sw_extinction',1,hook_handle)
    643 
    644   end subroutine aerosol_sw_extinction
     1395    if (lhook) call dr_hook('radiation_aerosol_optics:aerosol_extinction',1,hook_handle)
     1396
     1397  end subroutine aerosol_extinction
    6451398
    6461399end module radiation_aerosol_optics
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_aerosol_optics_data.F90

    r3908 r4444  
    5757     integer, allocatable, dimension(:) :: itype
    5858
     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
    5965     ! Scattering properties are provided separately in the shortwave
    6066     ! and longwave for hydrophobic and hydrophilic aerosols.
     
    6470          &  ssa_sw_phobic,      & ! Single scattering albedo
    6571          &  g_sw_phobic,        & ! Asymmetry factor
     72!          &  ssa_g_sw_phobic,    & ! ssa*g
    6673          &  mass_ext_lw_phobic, & ! Mass-extinction coefficient (m2 kg-1)
     74!          &  mass_abs_lw_phobic, & ! Mass-absorption coefficient (m2 kg-1)
    6775          &  ssa_lw_phobic,      & ! Single scattering albedo
    6876          &  g_lw_phobic           ! Asymmetry factor
    6977
    70      ! Hydrophilic aerosols are dimensioned (nband, nrh, n_type_philic):
     78     ! Hydrophilic aerosols are dimensioned (nband,nrh,n_type_philic):
    7179     real(jprb), allocatable, dimension(:,:,:) :: &
    7280          &  mass_ext_sw_philic, & ! Mass-extinction coefficient (m2 kg-1)
    7381          &  ssa_sw_philic,      & ! Single scattering albedo
    7482          &  g_sw_philic,        & ! Asymmetry factor
     83 !         &  ssa_g_sw_philic,    & ! ssa*g
    7584          &  mass_ext_lw_philic, & ! Mass-extinction coefficient (m2 kg-1)
     85 !         &  mass_abs_lw_philic, & ! Mass-absorption coefficient (m2 kg-1)
    7686          &  ssa_lw_philic,      & ! Single scattering albedo
    7787          &  g_lw_philic           ! Asymmetry factor
    7888
    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)
    8195     real(jprb), allocatable, dimension(:,:) :: &
    8296          &  mass_ext_mono_phobic, & ! Mass-extinction coefficient (m2 kg-1)
     
    8498          &  g_mono_phobic,        & ! Asymmetry factor
    8599          &  lidar_ratio_mono_phobic ! Lidar Ratio
     100     ! ...hydrophilic aerosols dimensioned (n_mono_wl,nrh,n_type_philic):
    86101     real(jprb), allocatable, dimension(:,:,:) :: &
    87102          &  mass_ext_mono_philic, & ! Mass-extinction coefficient (m2 kg-1)
     
    104119     ! The number of hydrophobic and hydrophilic types read from the
    105120     ! aerosol optics file
    106      integer :: n_type_phobic, n_type_philic
     121     integer :: n_type_phobic = 0
     122     integer :: n_type_philic = 0
    107123
    108124     ! Number of relative humidity bins
    109      integer :: nrh
     125     integer :: nrh = 0
    110126
    111127     ! Number of longwave and shortwave bands of the data in the file,
     
    121137   contains
    122138     procedure :: setup => setup_aerosol_optics
     139     procedure :: save  => save_aerosol_optics
     140     procedure :: allocate
     141     procedure :: initialize_types
    123142     procedure :: set_hydrophobic_type
    124143     procedure :: set_hydrophilic_type
     
    135154  !---------------------------------------------------------------------
    136155  ! 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)
    138157
    139158    use yomhook,              only : lhook, dr_hook
     
    143162    class(aerosol_optics_type), intent(inout) :: this
    144163    character(len=*), intent(in)              :: file_name
    145     integer, intent(in)                       :: ntype
    146164    integer, intent(in), optional             :: iverbose
    147165
    148166    ! The NetCDF file containing the aerosol optics data
    149167    type(netcdf_file)  :: file
     168
     169    real(jprb), allocatable :: wavelength_tmp(:)
    150170    integer            :: iverb
     171
    151172    real(jprb)         :: hook_handle
    152173
     
    168189      this%use_hydrophilic = .false.
    169190    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)
    170197
    171198    ! Read the raw scattering data
     
    180207         &                         this%description_phobic_str)
    181208
     209    ! Precompute ssa*g for the shortwave and mass-absorption for the
     210    ! longwave - TBD FIX
     211    !allocate(this%ssa_g_sw_phobic(...
     212
    182213    if (this%use_hydrophilic) then
    183214      call file%get('mass_ext_sw_hydrophilic', this%mass_ext_sw_philic)
     
    194225    end if
    195226
    196     ! Read the raw scattering data at selected wavelengths if
    197     ! available in the input file
     227    ! Read the monochromatic scattering data at selected wavelengths
     228    ! if available in the input file
    198229    if (file%exists('mass_ext_mono_hydrophobic')) then
    199230      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
    200256      call file%get('mass_ext_mono_hydrophobic', this%mass_ext_mono_phobic)
    201257      call file%get('ssa_mono_hydrophobic',      this%ssa_mono_phobic)
     
    233289        write(nulerr,'(a,a)') '*** Error: mass extinction for hydrophilic and hydrophobic ', &
    234290             &                'aerosol have different numbers of longwave bands'
    235         call radiation_abort()
     291        call radiation_abort('Radiation configuration error')
    236292      end if
    237293      if (size(this%mass_ext_sw_philic,1) /= this%n_bands_sw) then
    238294        write(nulerr,'(a,a)') '*** Error: mass extinction for hydrophilic and hydrophobic ', &
    239295             &                'aerosol have different numbers of shortwave bands'
    240         call radiation_abort()
     296        call radiation_abort('Radiation configuration error')
    241297      end if
    242298      if (size(this%rh_lower) /= this%nrh) then
    243299        write(nulerr,'(a)') '*** Error: size(relative_humidity1) /= size(mass_ext_sw_hydrophilic,2)'
    244         call radiation_abort()
     300        call radiation_abort('Radiation configuration error')
    245301      end if
    246302
     
    250306    end if
    251307
     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   
    252320    ! Allocate memory for mapping arrays
    253321    this%ntype = ntype
     
    258326    this%itype  = 0
    259327
    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
    263498
    264499
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_cloud.F90

    r3908 r4444  
    1616!   2019-01-14  R. Hogan  Added inv_inhom_effective_size variable
    1717!   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
    1819
    1920module radiation_cloud
     
    3233  type cloud_type
    3334    ! 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(:,:) :: &
    4545         &  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
    4852
    4953    ! The fractional standard deviation of cloud optical depth in the
     
    9599  ! in the offline code these are allocated when they are read from
    96100  ! 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)
    98102
    99103    use yomhook,     only : lhook, dr_hook
    100104
    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
    104113    logical, intent(in), optional    :: use_inhom_effective_size
    105114
     
    108117    if (lhook) call dr_hook('radiation_cloud:allocate',0,hook_handle)
    109118
    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
    114138    allocate(this%fraction(ncol,nlev))
    115139    allocate(this%overlap_param(ncol,nlev-1))
     
    140164    if (lhook) call dr_hook('radiation_cloud:deallocate',0,hook_handle)
    141165
    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)
    149176    if (allocated(this%inv_cloud_effective_size)) &
    150177         &  deallocate(this%inv_cloud_effective_size)
     
    185212    integer :: ncol, nlev
    186213
    187     integer :: jlev
     214    integer :: jcol, jlev
    188215
    189216    real(jprb)        :: hook_handle
     
    220247      ! top-of-atmosphere to surface). In case pressure_hl(:,1)=0, we
    221248      ! 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
    226255
    227256      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
    232263      end do
    233264
     
    237268       ! don't take the logarithm of the last pressure in each column.
    238269      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
    243276      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
    249284    end if
    250285
     
    580615    integer,           intent(in)    :: istartcol, iendcol
    581616
    582     integer :: nlev
    583     integer :: jcol, jlev
     617    integer :: nlev, ntype
     618    integer :: jcol, jlev, jh
    584619
    585620    real(jprb) :: cloud_fraction_threshold, cloud_mixing_ratio_threshold
     621    real(jprb) :: sum_mixing_ratio(istartcol:iendcol)
    586622
    587623    real(jprb) :: hook_handle
     
    589625    if (lhook) call dr_hook('radiation_cloud:crop_cloud_fraction',0,hook_handle)
    590626
    591     nlev = size(this%fraction,2)
    592 
     627    nlev  = size(this%fraction,2)
     628    ntype = size(this%mixing_ratio,3)
     629   
    593630    do jlev = 1,nlev
    594631      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
    598642          this%fraction(jcol,jlev) = 0.0_jprb
    599643        end if
     
    612656
    613657    use yomhook,          only : lhook, dr_hook
    614     use radiation_config, only : out_of_bounds_2d
     658    use radiation_check, only : out_of_bounds_2d, out_of_bounds_3d
    615659
    616660    class(cloud_type), intent(inout) :: this
     
    631675    end if
    632676
    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, &
    634678         &                       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, &
    640680         &                       do_fix_local, i1=istartcol, i2=iendcol) &
    641681         & .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  
    253253           &  + (1.0_jprb - overlap_alpha) &
    254254           &  * (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
    256260      if (frac(jlev) >= MaxCloudFrac) then
    257261        ! Cloud cover has reached one
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_cloud_generator.F90

    r3908 r4444  
    1818! Modifications
    1919!   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
    2021
    2122module radiation_cloud_generator
     
    3940       &  fractional_std, pdf_sampler, &
    4041       &  od_scaling, total_cloud_cover, &
    41        &  is_beta_overlap)
     42       &  use_beta_overlap, use_vectorizable_generator)
    4243
    4344    use parkind1, only           : jprb
     
    8687    ! overlap parameter of Shonk et al. (2010), and needs to be
    8788    ! 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
    8994
    9095    ! Outputs
     
    126131    real(jprb), dimension(nlev-1) :: pair_cloud_cover, overhang
    127132
     133    logical :: use_vec_gen
     134
    128135    real(jprb) :: hook_handle
    129136
     
    132139    if (i_overlap_scheme == IOverlapExponentialRandom) then
    133140      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)
    135142    else if (i_overlap_scheme == IOverlapMaximumRandom) then
    136143      call cum_cloud_cover_max_ran(nlev, frac, &
     
    138145    else if (i_overlap_scheme == IOverlapExponential) then
    139146      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)
    141148    else
    142149      write(nulerr,'(a)') '*** Error: cloud overlap scheme not recognised'
     
    183190      od_scaling = 0.0_jprb
    184191
    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         
    200232        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()
    213242        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
    216250
    217251    end if
    218 
    219252
    220253    if (lhook) call dr_hook('radiation_cloud_generator:cloud_generator',1,hook_handle)
     
    474507       
    475508    ! 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:
    478513    call pdf_sampler%masked_sample(n_layers_to_scale, &
    479514         &  fractional_std(itrigger:iend), &
     
    481516         &  is_cloudy(itrigger:iend))
    482517       
     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
    483531  end subroutine generate_column_exp_exp
    484532
     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
    485738end module radiation_cloud_generator
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_cloud_optics.F90

    r3908 r4444  
    1919
    2020  implicit none
     21
    2122  public
    2223
     
    271272    type(cloud_optics_type), pointer :: ho
    272273
    273     integer    :: jcol, jlev
     274    integer    :: jcol, jlev, jb
    274275
    275276    real(jprb) :: hook_handle
     
    345346            end if
    346347
     348            ! Delta-Eddington scaling in the shortwave only
    347349            if (.not. config%do_sw_delta_scaling_with_gases) then
    348               ! Delta-Eddington scaling in the shortwave only
    349350              call delta_eddington_scat_od(od_sw_liq, scat_od_sw_liq, g_sw_liq)
    350351            end if
     352            !call delta_eddington_scat_od(od_lw_liq, scat_od_lw_liq, g_lw_liq)
     353
    351354          else
    352355            ! Liquid not present: set properties to zero
     
    437440            end if
    438441
     442            ! Delta-Eddington scaling in both longwave and shortwave
     443            ! (assume that particles are larger than wavelength even
     444            ! in longwave)
    439445            if (.not. config%do_sw_delta_scaling_with_gases) then
    440               ! Delta-Eddington scaling in both longwave and shortwave
    441               ! (assume that particles are larger than wavelength even
    442               ! in longwave)
    443446              call delta_eddington_scat_od(od_sw_ice, scat_od_sw_ice, g_sw_ice)
    444447            end if
    445 
    446448            call delta_eddington_scat_od(od_lw_ice, scat_od_lw_ice, g_lw_ice)
     449
    447450          else
    448451            ! Ice not present: set properties to zero
     
    458461          ! Combine liquid and ice
    459462          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
    470477          else
    471478            ! If longwave scattering is to be neglected then the
    472479            ! best approximation is to set the optical depth equal
    473480            ! 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
    476487          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
    483498        end if ! Cloud present
    484499      end do ! Loop over column
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_config.F90

    r4115 r4444  
    2626!   2019-02-03  R. Hogan  Added ability to fix out-of-physical-bounds inputs
    2727!   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
    2830!
    2931! Note: The aim is for ecRad in the IFS to be as similar as possible
     
    3739
    3840  use radiation_cloud_optics_data,   only : cloud_optics_type
     41  use radiation_general_cloud_optics_data,   only : general_cloud_optics_type
    3942  use radiation_aerosol_optics_data, only : aerosol_optics_type
    4043  use radiation_pdf_sampler,         only : pdf_sampler_type
    4144  use radiation_cloud_cover,         only : OverlapName, &
    4245       & IOverlapMaximumRandom, IOverlapExponentialRandom, IOverlapExponential
     46  use radiation_ecckd,               only : ckd_model_type
    4347
    4448  implicit none
     
    7074       & IEntrapmentExplicitNonFractal, & ! As above but ignore fractal nature of clouds
    7175       & IEntrapmentMaximum ! Complete horizontal homogenization within regions (old SPARTACUS assumption)
    72 
    7376  end enum
    7477 
     
    9497  ! Gas models
    9598  enum, bind(c)
    96      enumerator IGasModelMonochromatic, IGasModelIFSRRTMG
     99     enumerator IGasModelMonochromatic, IGasModelIFSRRTMG, IGasModelECCKD
    97100  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        '/)
    100104
    101105  ! Hydrometeor scattering models
     
    130134  integer, parameter :: NMaxAerosolTypes = 256
    131135
     136  ! Maximum number of different cloud types that can be provided
     137  integer, parameter :: NMaxCloudTypes = 12
     138
    132139  ! Maximum number of shortwave albedo and longwave emissivity
    133140  ! intervals
     
    155162    character(len=511) :: directory_name = '.'
    156163
     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
    157176    ! Cloud is deemed to be present in a layer if cloud fraction
    158177    ! exceeds this value
     
    168187    ! (2000)?
    169188    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
    170198
    171199    ! Shape of sub-grid cloud water PDF
     
    236264    logical :: do_sw_delta_scaling_with_gases = .false.
    237265
    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
    240267    integer :: i_gas_model = IGasModelIFSRRTMG
    241     !     integer :: i_cloud_model
    242268
    243269    ! Optics if i_gas_model==IGasModelMonochromatic.
     
    270296    ! according to the spectral overlap of each interval with each
    271297    ! 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.
    274300
    275301    ! User-defined monotonically increasing wavelength bounds (m)
    276302    ! 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.
    278306    real(jprb) :: sw_albedo_wavelength_bound(NMaxAlbedoIntervals-1) = -1.0_jprb
    279     real(jprb) :: lw_emiss_wavelength_bound( NMaxAlbedoIntervals-1)  = -1.0_jprb
     307    real(jprb) :: lw_emiss_wavelength_bound( NMaxAlbedoIntervals-1) = -1.0_jprb
    280308
    281309    ! The index to the surface albedo/emissivity intervals for each of
     
    296324    logical :: do_3d_effects = .true.
    297325   
     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
    298339    ! To what extent do we include "entrapment" effects in the
    299340    ! SPARTACUS solver? This essentially means that in a situation
     
    420461    ! doesn't start with a '/' character then it will be prepended by
    421462    ! 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     = ''
    424465    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  = ''
    425468
    426469    ! Optionally override the look-up table file for the cloud-water
     
    428471    character(len=511) :: cloud_pdf_override_file_name = ''
    429472
     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
    430489    ! Has "consolidate" been called? 
    431490    logical :: is_consolidated = .false.
    432491
    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
    443495
    444496    ! If the nearest surface albedo/emissivity interval is to be used
     
    490542    integer :: n_canopy_bands_lw = 1
    491543
     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
    492548    ! Data structure containing cloud scattering data
    493549    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(:)
    494558
    495559    ! Data structure containing aerosol scattering data
     
    502566    character(len=511) :: ice_optics_file_name, &
    503567         &                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
    505571   
    506572    ! McICA PDF look-up table file name
     
    515581    ! g points or the number of bands
    516582    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
    517587
    518588    ! Dimensions to store variables that are only needed if longwave
     
    539609     procedure :: define_sw_albedo_intervals
    540610     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
    542614
    543615  end type config_type
     
    574646    logical :: do_sw, do_lw, do_clear, do_sw_direct
    575647    logical :: do_3d_effects, use_expm_everywhere, use_aerosols
     648    logical :: use_general_cloud_optics, use_general_aerosol_optics
    576649    logical :: do_lw_side_emissivity
    577650    logical :: do_3d_lw_multilayer_effects, do_fu_lw_ice_optics_bug
     
    579652    logical :: do_save_radiative_properties, do_save_spectral_flux
    580653    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
    582655    logical :: do_sw_delta_scaling_with_gases
    583656    logical :: do_canopy_fluxes_sw, do_canopy_fluxes_lw
    584657    logical :: use_canopy_full_spectrum_sw, use_canopy_full_spectrum_lw
    585658    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   
    586661    integer :: n_regions, iverbose, iverbosesetup, n_aerosol_types
    587662    real(jprb):: mono_lw_wavelength, mono_lw_total_od, mono_sw_total_od
     
    596671    character(511) :: liq_optics_override_file_name, ice_optics_override_file_name
    597672    character(511) :: cloud_pdf_override_file_name
     673    character(511) :: gas_optics_sw_override_file_name, gas_optics_lw_override_file_name
    598674    character(63)  :: liquid_model_name, ice_model_name, gas_model_name
    599675    character(63)  :: sw_solver_name, lw_solver_name, overlap_scheme_name
    600676    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.]
    601681    integer :: i_aerosol_type_map(NMaxAerosolTypes) ! More than 256 is an error
    602682
    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
    605685    real(jprb) :: sw_albedo_wavelength_bound(NMaxAlbedoIntervals-1)
    606686    real(jprb) :: lw_emiss_wavelength_bound( NMaxAlbedoIntervals-1)
     
    609689
    610690    integer :: iunit ! Unit number of namelist file
    611 
    612     logical :: lldeb_conf = .false.
    613691
    614692    namelist /radiation/ do_sw, do_lw, do_sw_direct, &
     
    622700         &  ice_optics_override_file_name, liq_optics_override_file_name, &
    623701         &  aerosol_optics_override_file_name, cloud_pdf_override_file_name, &
     702         &  gas_optics_sw_override_file_name, gas_optics_lw_override_file_name, &
    624703         &  liquid_model_name, ice_model_name, max_3d_transfer_rate, &
    625704         &  min_cloud_effective_size, overhang_factor, encroachment_scaling, &
     
    627706         &  do_canopy_fluxes_sw, do_canopy_fluxes_lw, &
    628707         &  do_canopy_gases_sw, do_canopy_gases_lw, &
     708         &  use_general_cloud_optics, use_general_aerosol_optics, &
    629709         &  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, &
    631711         &  use_expm_everywhere, iverbose, iverbosesetup, &
    632712         &  cloud_inhom_decorr_scaling, cloud_fraction_threshold, &
     
    637717         &  mono_lw_single_scattering_albedo, mono_sw_single_scattering_albedo, &
    638718         &  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, &
    640720         &  do_nearest_spectral_sw_albedo, do_nearest_spectral_lw_emiss, &
    641721         &  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         
    644726    real(jprb) :: hook_handle
    645727
     
    670752    ice_optics_override_file_name = this%ice_optics_override_file_name
    671753    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
    672756    use_expm_everywhere = this%use_expm_everywhere
    673757    use_aerosols = this%use_aerosols
     
    679763    iverbose = this%iverbose
    680764    iverbosesetup = this%iverbosesetup
     765    use_general_cloud_optics = this%use_general_cloud_optics
     766    use_general_aerosol_optics = this%use_general_aerosol_optics
    681767    cloud_fraction_threshold = this%cloud_fraction_threshold
    682768    cloud_mixing_ratio_threshold = this%cloud_mixing_ratio_threshold
    683769    use_beta_overlap = this%use_beta_overlap
     770    use_vectorizable_generator = this%use_vectorizable_generator
    684771    cloud_inhom_decorr_scaling = this%cloud_inhom_decorr_scaling
    685772    clear_to_thick_fraction = this%clear_to_thick_fraction
     
    689776    max_3d_transfer_rate = this%max_3d_transfer_rate
    690777    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
    691781    overhang_factor = this%overhang_factor
    692782    encroachment_scaling = -1.0_jprb
     
    715805    i_sw_albedo_index             = this%i_sw_albedo_index
    716806    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
    717810
    718811    if (present(file_name) .and. present(unit)) then
     
    746839      end if
    747840    else
     841
     842      ! This version exits correctly, but provides less information
     843      ! about how the namelist was incorrect
    748844      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
    749850      if (iosread /= 0) then
    750851        ! An error occurred reading the file
     
    812913    this%mono_sw_asymmetry_factor = mono_sw_asymmetry_factor
    813914    this%use_beta_overlap = use_beta_overlap
     915    this%use_vectorizable_generator = use_vectorizable_generator
    814916    this%cloud_inhom_decorr_scaling = cloud_inhom_decorr_scaling
    815917    this%clear_to_thick_fraction = clear_to_thick_fraction
     
    819921    this%max_3d_transfer_rate = max_3d_transfer_rate
    820922    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
    821925    if (encroachment_scaling >= 0.0_jprb) then
    822926      this%overhang_factor = encroachment_scaling
     
    832936    this%ice_optics_override_file_name = ice_optics_override_file_name
    833937    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
    834942    this%cloud_fraction_threshold = cloud_fraction_threshold
    835943    this%cloud_mixing_ratio_threshold = cloud_mixing_ratio_threshold
     
    845953    this%i_sw_albedo_index             = i_sw_albedo_index
    846954    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
    915959    if (do_save_gpoint_flux) then
    916960      ! Saving the fluxes every g-point overrides saving as averaged
     
    919963      ! save anything
    920964      this%do_save_spectral_flux = .true.
    921       print*,'config%do_save_spectral_flux = .true.'
    922965    end if
    923966
     
    925968    call get_enum_code(liquid_model_name, LiquidModelName, &
    926969         &            'liquid_model_name', this%i_liq_model)
    927     print*,'config%i_liq_model =', this%i_liq_model
    928970
    929971    ! Determine ice optics model
    930972    call get_enum_code(ice_model_name, IceModelName, &
    931973         &            'ice_model_name', this%i_ice_model)
    932     print*,'config%i_ice_model =', this%i_ice_model
     974
    933975    ! Determine gas optics model
    934976    call get_enum_code(gas_model_name, GasModelName, &
    935977         &            'gas_model_name', this%i_gas_model)
    936     print*,'config%%i_gas_model = ', this%i_gas_model
    937978
    938979    ! Determine solvers
    939980    call get_enum_code(sw_solver_name, SolverName, &
    940981         &            'sw_solver_name', this%i_solver_sw)
    941     print*,'config%i_solver_sw = ', this%i_solver_sw
    942982    call get_enum_code(lw_solver_name, SolverName, &
    943983         &            'lw_solver_name', this%i_solver_lw)
    944     print*,'config%i_solver_lw = ', this%i_solver_lw
     984
    945985    if (len_trim(sw_encroachment_name) > 1) then
    946986      call get_enum_code(sw_encroachment_name, EncroachmentName, &
     
    950990      call get_enum_code(sw_entrapment_name, EntrapmentName, &
    951991           &             'sw_entrapment_name', this%i_3d_sw_entrapment)
    952       print*,'config%i_3d_sw_entrapment = ', this%i_3d_sw_entrapment
    953992    end if
    954993
     
    956995    call get_enum_code(overlap_scheme_name, OverlapName, &
    957996         &             'overlap_scheme_name', this%i_overlap_scheme)
    958     print*,'config%i_overlap_scheme = ', this%i_overlap_scheme
     997   
    959998    ! Determine cloud PDF shape
    960999    call get_enum_code(cloud_pdf_shape_name, PdfShapeName, &
    9611000         &             'cloud_pdf_shape_name', this%i_cloud_pdf_shape)
    962     print*,'config%i_cloud_pdf_shape = ', this%i_cloud_pdf_shape
     1001
    9631002    this%i_aerosol_type_map = 0
    9641003    if (this%use_aerosols) then
    9651004      this%i_aerosol_type_map(1:n_aerosol_types) &
    9661005           &  = i_aerosol_type_map(1:n_aerosol_types)
    967       print*,'config%i_aerosol_type_map = ', this%i_aerosol_type_map
    9681006    end if
    9691007
     
    9751013      this%do_clouds = .false.
    9761014    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
    9781029
    9791030    ! Normal subroutine exit
     
    9931044  subroutine consolidate_config(this)
    9941045
     1046    use parkind1,     only : jprd
    9951047    use yomhook,      only : lhook, dr_hook
    9961048    use radiation_io, only : nulout, nulerr, radiation_abort
     
    10261078      write(nulerr,'(a)') '*** Error: SPARTACUS/Tripleclouds solvers can only do Exponential-Random overlap'
    10271079      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
    10281129
    10291130    end if
     
    10401141      ! In the IFS, the aerosol optics file should be specified in
    10411142      ! 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
    10441150    end if
    10451151
     
    12291335           &          this%i_gas_model)
    12301336      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
    12321354
    12331355      !---------------------------------------------------------------------
     
    12531375             &   'do_nearest_spectral_lw_emiss', this%do_nearest_spectral_lw_emiss)
    12541376      end if
     1377      call print_logical('  Planck-weighted surface albedo/emiss mapping', &
     1378           &   'do_weighted_surface_mapping', this%do_weighted_surface_mapping)
     1379
    12551380      !---------------------------------------------------------------------
    12561381      if (this%do_clouds) then
     
    12601385        call print_real('  Cloud mixing-ratio threshold', &
    12611386             &   '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
    12691398        end if
    12701399        call print_enum('  Cloud overlap scheme is', OverlapName, &
     
    13601489               &   'overhang_factor', this%overhang_factor)
    13611490        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)
    13621496      end if
    13631497           
     
    13831517    use parkind1, only : jprb
    13841518    use radiation_io, only : nulout, nulerr, radiation_abort
     1519    use radiation_spectral_definition, only : SolarReferenceTemperature
    13851520
    13861521    class(config_type), intent(in) :: this
     
    13961531    character(len=*), optional, intent(in) :: weighting_name
    13971532
     1533    real(jprb), allocatable   :: mapping(:,:)
     1534
    13981535    ! Internally we deal with wavenumber
    13991536    real(jprb) :: wavenumber1, wavenumber2 ! cm-1
    14001537
     1538    real(jprb) :: wavenumber1_band, wavenumber2_band ! cm-1
     1539
    14011540    integer :: jband ! Loop index for spectral band
    14021541
    14031542    if (this%n_bands_sw <= 0) then
    14041543      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')
    14061545    end if
    14071546
     
    14101549    wavenumber2 = 0.01_jprb / wavelength1
    14111550
     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
    14121557    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
    14171560        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)
    14221563      end if
    14231564    end do
     
    14261567      write(nulerr,'(a,e8.4,a,e8.4,a)') '*** Error: wavelength range ', &
    14271568           &  wavelength1, ' to ', wavelength2, ' m is outside shortwave band'
    1428       call radiation_abort()
     1569      call radiation_abort('Radiation configuration error')
    14291570    else if (this%iverbosesetup >= 2 .and. present(weighting_name)) then
    14301571      write(nulout,'(a,a,a,f6.0,a,f6.0,a)') 'Spectral weights for ', &
    14311572           &  weighting_name, ' (', wavenumber1, ' to ', &
    14321573           &  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
    14381587    end if
    14391588
     
    14521601
    14531602    use radiation_io, only : nulerr, radiation_abort
     1603    use radiation_spectral_definition, only : SolarReferenceTemperature
    14541604
    14551605    class(config_type),   intent(inout) :: this
     
    14671617      write(nulerr,'(a,i0,a,i0)') '*** Error: ', ninterval, &
    14681618           &  ' albedo intervals exceeds maximum of ', NMaxAlbedoIntervals
    1469       call radiation_abort();
     1619      call radiation_abort('Radiation configuration error')
    14701620    end if
    14711621
     
    14801630    this%i_sw_albedo_index(ninterval+1:)           = 0
    14811631
     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.
    14821636    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
    14881638    end if
    14891639
     
    14971647
    14981648    use radiation_io, only : nulerr, radiation_abort
     1649    use radiation_spectral_definition, only : TerrestrialReferenceTemperature
    14991650
    15001651    class(config_type),   intent(inout) :: this
     
    15121663      write(nulerr,'(a,i0,a,i0)') '*** Error: ', ninterval, &
    15131664           &  ' emissivity intervals exceeds maximum of ', NMaxAlbedoIntervals
    1514       call radiation_abort();
     1665      call radiation_abort('Radiation configuration error')
    15151666    end if
    15161667
     
    15261677
    15271678    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
    15331680    end if
    15341681
     
    15371684
    15381685  !---------------------------------------------------------------------
    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
    15481717
    15491718    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
    15911721
    15921722    ! Count the number of albedo/emissivity intervals
    15931723    ninterval = 0
    1594     do iinterval = 1,NMaxAlbedoIntervals
    1595       if (i_intervals(iinterval) > 0) then
    1596         ninterval = iinterval
     1724    do jint = 1,NMaxAlbedoIntervals
     1725      if (this%i_sw_albedo_index(jint) > 0) then
     1726        ninterval = jint
    15971727      else
    15981728        exit
     
    16001730    end do
    16011731
    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
    16111735      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
    17141738      if (this%use_canopy_full_spectrum_sw) then
    17151739        this%n_canopy_bands_sw = this%n_g_sw
    17161740      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
    17181820      end if
    17191821    else
     
    17211823        this%n_canopy_bands_lw = this%n_g_lw
    17221824      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)
    17251844    end if
    17261845
    17271846    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))
    17441851      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'
    17501853      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)
    17601858        end do
    17611859        write(nulout, '()')
     
    17631861    end if
    17641862
    1765   end subroutine consolidate_intervals
     1863  end subroutine consolidate_lw_emiss_intervals
    17661864
    17671865
     
    18661964  end subroutine print_enum
    18671965
    1868 
    1869   !---------------------------------------------------------------------
    1870   ! Return .true. if 1D allocatable array "var" is out of physical
    1871   ! range specified by boundmin and boundmax, and issue a warning.
    1872   ! "do_fix" determines whether erroneous values are fixed to lie
    1873   ! 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 : nulout
    1878 
    1879     real(jprb), allocatable, intent(inout) :: var(:)
    1880     character(len=*),        intent(in) :: var_name
    1881     real(jprb),              intent(in) :: boundmin, boundmax
    1882     logical,                 intent(in) :: do_fix
    1883     integer,       optional, intent(in) :: i1, i2
    1884 
    1885     logical                       :: is_bad
    1886 
    1887     real(jprb) :: varmin, varmax
    1888 
    1889     is_bad = .false.
    1890 
    1891     if (allocated(var)) then
    1892 
    1893       if (present(i1) .and. present(i2)) then
    1894         varmin = minval(var(i1:i2))
    1895         varmax = maxval(var(i1:i2))
    1896       else
    1897         varmin = minval(var)
    1898         varmax = maxval(var)
    1899       end if
    1900 
    1901       if (varmin < boundmin .or. varmax > boundmax) then
    1902         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', boundmax
    1905         is_bad = .true.
    1906         if (do_fix) then
    1907           if (present(i1) .and. present(i2)) then
    1908             var(i1:i2) = max(boundmin, min(boundmax, var(i1:i2)))
    1909           else
    1910             var = max(boundmin, min(boundmax, var))
    1911           end if
    1912           write(nulout,'(a)') ': corrected'
    1913         else
    1914           write(nulout,'(1x)')
    1915         end if
    1916       end if
    1917 
    1918     end if
    1919    
    1920   end function out_of_bounds_1d
    1921 
    1922 
    1923   !---------------------------------------------------------------------
    1924   ! Return .true. if 2D allocatable array "var" is out of physical
    1925   ! range specified by boundmin and boundmax, and issue a warning.  To
    1926   ! check only a subset of the array, specify i1 and i2 for the range
    1927   ! 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 : nulout
    1932 
    1933     real(jprb), allocatable, intent(inout) :: var(:,:)
    1934     character(len=*),        intent(in) :: var_name
    1935     real(jprb),              intent(in) :: boundmin, boundmax
    1936     logical,                 intent(in) :: do_fix
    1937     integer,       optional, intent(in) :: i1, i2, j1, j2
    1938 
    1939     ! Local copies of indices
    1940     integer :: ii1, ii2, jj1, jj2
    1941 
    1942     logical                       :: is_bad
    1943 
    1944     real(jprb) :: varmin, varmax
    1945 
    1946     is_bad = .false.
    1947 
    1948     if (allocated(var)) then
    1949 
    1950       if (present(i1) .and. present(i2)) then
    1951         ii1 = i1
    1952         ii2 = i2
    1953       else
    1954         ii1 = lbound(var,1)
    1955         ii2 = ubound(var,1)
    1956       end if
    1957       if (present(j1) .and. present(j2)) then
    1958         jj1 = j1
    1959         jj2 = j2
    1960       else
    1961         jj1 = lbound(var,2)
    1962         jj2 = ubound(var,2)
    1963       end if
    1964       varmin = minval(var(ii1:ii2,jj1:jj2))
    1965       varmax = maxval(var(ii1:ii2,jj1:jj2))
    1966 
    1967       if (varmin < boundmin .or. varmax > boundmax) then
    1968         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', boundmax
    1971         is_bad = .true.
    1972         if (do_fix) then
    1973           var(ii1:ii2,jj1:jj2) = max(boundmin, min(boundmax, var(ii1:ii2,jj1:jj2)))
    1974           write(nulout,'(a)') ': corrected'
    1975         else
    1976           write(nulout,'(1x)')
    1977         end if
    1978       end if
    1979 
    1980     end if
    1981    
    1982   end function out_of_bounds_2d
    1983 
    1984 
    1985   !---------------------------------------------------------------------
    1986   ! Return .true. if 3D allocatable array "var" is out of physical
    1987   ! range specified by boundmin and boundmax, and issue a warning.  To
    1988   ! check only a subset of the array, specify i1 and i2 for the range
    1989   ! of the first dimension, j1 and j2 for the second and k1 and k2 for
    1990   ! 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 : nulout
    1995 
    1996     real(jprb), allocatable, intent(inout) :: var(:,:,:)
    1997     character(len=*),        intent(in) :: var_name
    1998     real(jprb),              intent(in) :: boundmin, boundmax
    1999     logical,                 intent(in) :: do_fix
    2000     integer,       optional, intent(in) :: i1, i2, j1, j2, k1, k2
    2001 
    2002     ! Local copies of indices
    2003     integer :: ii1, ii2, jj1, jj2, kk1, kk2
    2004 
    2005     logical                       :: is_bad
    2006 
    2007     real(jprb) :: varmin, varmax
    2008 
    2009     is_bad = .false.
    2010 
    2011     if (allocated(var)) then
    2012 
    2013       if (present(i1) .and. present(i2)) then
    2014         ii1 = i1
    2015         ii2 = i2
    2016       else
    2017         ii1 = lbound(var,1)
    2018         ii2 = ubound(var,1)
    2019       end if
    2020       if (present(j1) .and. present(j2)) then
    2021         jj1 = j1
    2022         jj2 = j2
    2023       else
    2024         jj1 = lbound(var,2)
    2025         jj2 = ubound(var,2)
    2026       end if
    2027       if (present(k1) .and. present(k2)) then
    2028         kk1 = k1
    2029         kk2 = k2
    2030       else
    2031         kk1 = lbound(var,3)
    2032         kk2 = ubound(var,3)
    2033       end if
    2034       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) then
    2038         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', boundmax
    2041         is_bad = .true.
    2042         if (do_fix) then
    2043           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         else
    2047           write(nulout,'(1x)')
    2048         end if
    2049       end if
    2050 
    2051     end if
    2052    
    2053   end function out_of_bounds_3d
    2054 
    2055 
    20561966end 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 -*-
    22!
    33! (C) Copyright 2015- ECMWF.
     
    9292end subroutine delta_eddington_scat_od
    9393
     94
     95!---------------------------------------------------------------------
     96! Revert delta-Eddington-scaled quantities in-place, back to their
     97! original state
     98elemental 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 
     115end subroutine revert_delta_eddington
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_flux.F90

    r3908 r4444  
    100100  end type flux_type
    101101
     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
    102109contains
    103110
     
    132139        if (config%n_spec_lw == 0) then
    133140          write(nulerr,'(a)') '*** Error: number of LW spectral points to save not yet defined ' &
    134                & // 'so cannot allocated spectral flux arrays'
     141               & // 'so cannot allocate spectral flux arrays'
    135142          call radiation_abort()
    136143        end if
     
    321328    end if
    322329
     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
    323337    if (lhook) call dr_hook('radiation_flux:deallocate',1,hook_handle)
    324338
     
    349363    if (config%do_sw .and. config%do_surface_sw_spectral_flux) then
    350364
    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
    362390
    363391      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
    375417      end if
    376418
     
    383425        this%sw_dn_direct_surf_canopy (:,istartcol:iendcol) = this%sw_dn_direct_surf_g (:,istartcol:iendcol)
    384426      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
    393444      else
    394445        ! More accurate calculations using weights, but requires
     
    425476        this%lw_dn_surf_canopy(:,istartcol:iendcol) = this%lw_dn_surf_g(:,istartcol:iendcol)
    426477      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
    432489      else
    433490        ! Compute fluxes in each longwave emissivity interval using
    434491        ! 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
    440503        nalbedoband = size(config%lw_emiss_weights,1)
    441504        this%lw_dn_surf_canopy(:,istartcol:iendcol) = 0.0_jprb
     
    465528
    466529    use yomhook,          only : lhook, dr_hook
    467     use radiation_config, only : out_of_bounds_2d
     530    use radiation_check, only : out_of_bounds_2d
    468531
    469532    class(flux_type), intent(inout) :: this
     
    497560  function heating_rate_out_of_physical_bounds(this, nlev, istartcol, iendcol, pressure_hl) result(is_bad)
    498561   
    499     use radiation_config, only : out_of_bounds_2d
     562    use radiation_check, only : out_of_bounds_2d
    500563    use radiation_constants, only : AccelDueToGravity
    501564
     
    581644  end subroutine indexed_sum
    582645
     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
    583667
    584668  !---------------------------------------------------------------------
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_gas.F90

    r3908 r4444  
    1919
    2020  use parkind1, only : jprb
     21  use radiation_gas_constants
    2122
    2223  implicit none
    2324  public
    24 
    25   ! Gas codes; these indices match those of RRTM-LW up to 7
    26   integer, parameter :: IGasNotPresent = 0
    27   integer, parameter :: IH2O   = 1
    28   integer, parameter :: ICO2   = 2
    29   integer, parameter :: IO3    = 3
    30   integer, parameter :: IN2O   = 4
    31   integer, parameter :: ICO    = 5
    32   integer, parameter :: ICH4   = 6
    33   integer, parameter :: IO2    = 7
    34   integer, parameter :: ICFC11 = 8
    35   integer, parameter :: ICFC12 = 9
    36   integer, parameter :: IHCFC22= 10
    37   integer, parameter :: ICCl4  = 11
    38   integer, parameter :: INO2   = 12
    39   integer, parameter :: NMaxGases = 12
    40 
    41   ! Molar masses (g mol-1) of dry air and the various gases above
    42   real(jprb), parameter :: IAirMolarMass = 28.970
    43   real(jprb), parameter, dimension(0:NMaxGases) :: IGasMolarMass = (/ &
    44        & 0.0_jprb,        & ! Gas not present
    45        & 18.0152833_jprb, & ! H2O
    46        & 44.011_jprb,     & ! CO2
    47        & 47.9982_jprb,    & ! O3
    48        & 44.013_jprb,     & ! N2O
    49        & 28.0101_jprb,    & ! CO
    50        & 16.043_jprb,     & ! CH4
    51        & 31.9988_jprb,    & ! O2
    52        & 137.3686_jprb,   & ! CFC11
    53        & 120.914_jprb,    & ! CFC12
    54        & 86.469_jprb,     & ! HCFC22
    55        & 153.823_jprb,    & ! CCl4   
    56        & 46.0055_jprb /)    ! NO2
    57 
    58   ! The corresponding names of the gases in upper and lower case, used
    59   ! for reading variables from the input file
    60   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   '/)
    6625
    6726  ! Available units
     
    12180
    12281  !---------------------------------------------------------------------
     82  ! Allocate a derived type for holding gas mixing ratios given the
     83  ! number of columns and levels
    12384  subroutine allocate_gas(this, ncol, nlev)
    12485
     
    191152    integer,    optional, intent(in)    :: istartcol
    192153
    193     integer :: i1, i2
     154    integer :: i1, i2, jc, jk
     155
    194156
    195157    real(jprb)                          :: hook_handle
     
    245207    this%iunits(igas) = iunits
    246208    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
    249215    if (present(scale_factor)) then
    250216      this%scale_factor(igas) = scale_factor
     
    276242    real(jprb)                          :: hook_handle
    277243
    278     integer :: i1, i2
     244    integer :: i1, i2, jc, jk
    279245
    280246    if (lhook) call dr_hook('radiation_gas:put_well_mixed',0,hook_handle)
     
    326292    this%iunits(igas)                  = iunits
    327293    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
    330300    if (present(scale_factor)) then
    331301      this%scale_factor(igas) = scale_factor
     
    344314  ! immediately, but changes the scale factor for the specified gas,
    345315  ! ready to be used in set_units_gas.
    346 
    347316  subroutine scale_gas(this, igas, scale_factor, lverbose)
    348317
     
    411380        if (iunits == IMassMixingRatio &
    412381             &   .and. this%iunits(igas) == IVolumeMixingRatio) then
    413           sf = sf * IGasMolarMass(igas) / IAirMolarMass
     382          sf = sf * GasMolarMass(igas) / AirMolarMass
    414383        else if (iunits == IVolumeMixingRatio &
    415384             &   .and. this%iunits(igas) == IMassMixingRatio) then
    416           sf = sf * IAirMolarMass / IGasMolarMass(igas)
     385          sf = sf * AirMolarMass / GasMolarMass(igas)
    417386        end if
    418387        sf = sf * this%scale_factor(igas)
     
    538507      if (iunits == IMassMixingRatio &
    539508           &   .and. this%iunits(igas) == IVolumeMixingRatio) then
    540         sf = sf * IGasMolarMass(igas) / IAirMolarMass
     509        sf = sf * GasMolarMass(igas) / AirMolarMass
    541510      else if (iunits == IVolumeMixingRatio &
    542511           &   .and. this%iunits(igas) == IMassMixingRatio) then
    543         sf = sf * IAirMolarMass / IGasMolarMass(igas)
     512        sf = sf * AirMolarMass / GasMolarMass(igas)
    544513      end if
    545514      sf = sf * this%scale_factor(igas)
     
    591560
    592561    use yomhook,          only : lhook, dr_hook
    593     use radiation_config, only : out_of_bounds_3d
     562    use radiation_check, only : out_of_bounds_3d
    594563
    595564    class(gas_type),   intent(inout) :: this
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_ice_optics_fu.F90

    r3908 r4444  
    6161    real (jprb) :: iwp_gm_2
    6262
     63    integer :: jb
    6364    !real(jprb)  :: hook_handle
    6465
     
    7071    iwp_gm_2  = ice_wp * 1000.0_jprb
    7172
    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))), &
    7781         &  MaxAsymmetryFactor)
     82    end do
    7883
    7984    !if (lhook) call dr_hook('radiation_ice_optics:calc_ice_optics_fu_sw',1,hook_handle)
     
    106111    real (jprb) :: iwp_gm_2
    107112
     113    integer :: jb
    108114    !real(jprb)  :: hook_handle
    109115
     
    116122    iwp_gm_2  = ice_wp * 1000.0_jprb
    117123
    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))), &
    124133         &  MaxAsymmetryFactor)
     134    end do
    125135
    126136    !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  
    6868    real(jprb) :: hook_handle
    6969
    70 #include "surdi.intfb.h"
     70!#include "surdi.intfb.h"
    7171#include "surrtab.intfb.h"
    7272#include "surrtpk.intfb.h"
     
    8181    ! up now.
    8282    if (config%do_setup_ifsrrtm) then
    83       call SURDI
     83      !call SURDI
    8484      call SURRTAB
    8585      call SURRTPK
     
    8989    end if
    9090
     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
    9195    config%n_g_sw = jpgsw
    9296    config%n_g_lw = jpglw
     
    97101    ! can compute UV and photosynthetically active radiation for a
    98102    ! 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
    112114    allocate(config%i_band_from_g_sw          (config%n_g_sw))
    113115    allocate(config%i_band_from_g_lw          (config%n_g_lw))
     
    360362!    end if
    361363
    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
    368374   
    369375    ! Check we have gas mixing ratios in the right units
     
    402408         &  ZRAT_N2OCO2, ZRAT_N2OCO2_1, ZRAT_O3CO2, ZRAT_O3CO2_1)   
    403409
    404     ZTAUAERL = 0.0_jprb
     410    ZTAUAERL(istartcol:iendcol,:,:) = 0.0_jprb
    405411
    406412    CALL RRTM_GAS_OPTICAL_DEPTH &
     
    434440        lw_emission = lw_emission * (1.0_jprb - lw_albedo)
    435441      else
    436       ! Longwave emission has already been computed
     442        ! Longwave emission has already been computed
    437443        if (config%use_canopy_full_spectrum_lw) then
    438444          lw_emission = transpose(single_level%lw_emission(istartcol:iendcol,:))
     
    509515    ! Scale the incoming solar per band, if requested
    510516    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
    514523    end if
    515524
     
    518527    ! ZINCSOL will be zero.
    519528    if (present(incoming_sw)) then
    520       incoming_sw_scale = 1.0_jprb
    521529      do jcol = istartcol,iendcol
    522530        if (single_level%cos_sza(jcol) > 0.0_jprb) then
     531! Added for DWD (2020)
     532!NEC$ nounroll
    523533          incoming_sw_scale(jcol) = single_level%solar_irradiance / sum(ZINCSOL(jcol,:))
     534        else
     535          incoming_sw_scale(jcol) = 1.0_jprb
    524536        end if
    525537      end do
     
    546558    else
    547559      ! G points have not been reordered
    548       do jg = 1,config%n_g_sw
     560      do jcol = istartcol,iendcol
    549561        do jlev = 1,nlev
    550           do jcol = istartcol,iendcol
     562          do jg = 1,config%n_g_sw
    551563            ! Check for negative optical depth
    552564            od_sw (jg,nlev+1-jlev,jcol) = max(config%min_gas_od_sw, ZOD_SW(jcol,jlev,jg))
     
    555567        end do
    556568        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
    559572        end if
    560573      end do
     
    604617    real(jprb) :: temperature
    605618
    606     real(jprb) :: factor
     619    real(jprb) :: factor, planck_tmp(istartcol:iendcol,config%n_g_lw)
    607620    real(jprb) :: ZFLUXFAC
    608621
     
    689702          do jg = 1,config%n_g_lw
    690703            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,:)
    692708          end do
    693709        end if
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_interface.F90

    r3908 r4444  
    4040    use yomhook,          only : lhook, dr_hook
    4141    use radiation_config, only : config_type, ISolverMcICA, &
    42          &   IGasModelMonochromatic, IGasModelIFSRRTMG
     42         &   IGasModelMonochromatic, IGasModelIFSRRTMG, IGasModelECCKD
     43    use radiation_spectral_definition, only &
     44         &  : SolarReferenceTemperature, TerrestrialReferenceTemperature
    4345
    4446    ! Currently there are two gas absorption models: RRTMG (default)
     
    4850         &   setup_cloud_optics_mono   => setup_cloud_optics, &
    4951         &   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
    5154    use radiation_cloud_optics,   only :  setup_cloud_optics
     55    use radiation_general_cloud_optics, only :  setup_general_cloud_optics
    5256    use radiation_aerosol_optics, only :  setup_aerosol_optics
    5357
     
    6670      call setup_gas_optics_mono(config, trim(config%directory_name))
    6771    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)
    6975    end if
    7076
     
    100106    ! Consolidate the albedo/emissivity intervals with the shortwave
    101107    ! 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
    112114
    113115    if (config%do_clouds) then
    114116      if (config%i_gas_model == IGasModelMonochromatic) then
    115117        !      call setup_cloud_optics_mono(config)
     118      elseif (config%use_general_cloud_optics) then
     119        call setup_general_cloud_optics(config)
    116120      else
    117121        call setup_cloud_optics(config)
     
    147151   
    148152    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
    152157
    153158    type(config_type), intent(in)    :: config
     
    156161    if (config%i_gas_model == IGasModelMonochromatic) then
    157162      call set_gas_units_mono(gas)
     163    elseif (config%i_gas_model == IGasModelECCKD) then
     164      call set_gas_units_ecckd(gas)
    158165    else
    159166      call set_gas_units_ifs(gas)
     
    207214         &   cloud_optics_mono       => cloud_optics, &
    208215         &   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
    210218    use radiation_cloud_optics,   only : cloud_optics
     219    use radiation_general_cloud_optics, only : general_cloud_optics
    211220    use radiation_aerosol_optics, only : add_aerosol_optics
    212221
     
    309318             &  od_lw, od_sw, ssa_sw, &
    310319             &  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)
    311326      else
    312         call gas_optics(ncol,nlev,istartcol,iendcol, config, &
     327        call gas_optics_ecckd(ncol,nlev,istartcol,iendcol, config, &
    313328             &  single_level, thermodynamics, gas, &
    314329             &  od_lw, od_sw, ssa_sw, lw_albedo=lw_albedo, &
     
    330345          call cloud_optics_mono(nlev, istartcol, iendcol, &
    331346               &  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, &
    332352               &  od_lw_cloud, ssa_lw_cloud, g_lw_cloud, &
    333353               &  od_sw_cloud, ssa_sw_cloud, g_sw_cloud)
     
    351371        end if
    352372      else
    353         g_sw = 0.0_jprb
     373        g_sw(:,:,istartcol:iendcol) = 0.0_jprb
    354374        if (config%do_lw_aerosol_scattering) then
    355           ssa_lw = 0.0_jprb
    356           g_lw   = 0.0_jprb
     375          ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb
     376          g_lw(:,:,istartcol:iendcol)   = 0.0_jprb
    357377        end if
    358378      end if
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_liquid_optics_socrates.F90

    r3908 r4444  
    5252    real(jprb), intent(out) :: od(nb), scat_od(nb), g(nb)
    5353
     54    integer    :: jb
    5455    ! Local effective radius (m), after applying bounds
    5556    real(jprb) :: re
     
    6263    re = max(MinEffectiveRadius, min(re_in, MaxEffectiveRadius))
    6364
    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
    7277
    7378    !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  
    550550    real(jprb), dimension(iend) :: y2, y3
    551551
    552     integer :: j
    553 
    554552    !    associate (U11 => A(:,1,1), U12 => A(:,1,2), U13 => A(1,3))
    555553    ! LU decomposition of the *transpose* of A:
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_mcica_lw.F90

    r3908 r4444  
    157157        ! transmittance etc at each model level
    158158        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), &
    162160               &  gamma1, gamma2)
    163161          call calc_reflectance_transmittance_lw(ng, &
     
    206204           &  config%cloud_inhom_decorr_scaling, cloud%fractional_std(jcol,:), &
    207205           &  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)
    209208     
    210209      ! Store total cloud cover
     
    225224            end if
    226225
    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
    232233
    233234            if (config%do_lw_cloud_scattering) then
     
    239240                ! case that od_total > 0.0 and ssa_total > 0.0 but
    240241                ! 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
    254259              else
     260
    255261                do jg = 1,ng
    256262                  if (od_total(jg) > 0.0_jprb) then
     
    265271                  end if
    266272                end do
     273
    267274              end if
    268275           
     
    301308          ! Use adding method to compute fluxes but optimize for the
    302309          ! 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)
    306310          call fast_adding_ica_lw(ng, nlev, reflectance, transmittance, source_up, source_dn, &
    307311               &  emission(:,jcol), albedo(:,jcol), &
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_mcica_sw.F90

    r3908 r4444  
    211211             &  config%cloud_inhom_decorr_scaling, cloud%fractional_std(jcol,:), &
    212212             &  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)
    214215
    215216        ! Store total cloud cover
     
    221222            ! Compute combined gas+aerosol+cloud optical properties
    222223            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_new
    226               ssa_total = 0.0_jprb
    227               g_total   = 0.0_jprb
    228               ! In single precision we need to protect against the
    229               ! case that od_total > 0.0 and ssa_total > 0.0 but
    230               ! od_total*ssa_total == 0 due to underflow
    231224              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
    232234                if (od_total(jg) > 0.0_jprb) then
    233235                  scat_od = ssa(jg,jlev,jcol)*od(jg,jlev,jcol) &
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_monochromatic.F90

    r3908 r4444  
    345345    real(jprb), dimension(config%n_g_sw,nlev,istartcol:iendcol), intent(out) :: g_sw
    346346
    347     g_sw = 0.0_jprb
     347    g_sw(:,:,istartcol:iendcol) = 0.0_jprb
    348348
    349349    if (config%do_lw_aerosol_scattering) then
    350       ssa_lw = 0.0_jprb
    351       g_lw   = 0.0_jprb
     350      ssa_lw(:,:,istartcol:iendcol) = 0.0_jprb
     351      g_lw(:,:,istartcol:iendcol)   = 0.0_jprb
    352352    end if
    353353
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_pdf_sampler.F90

    r3908 r4444  
    1 ! radiation_pdf_sampler.F90 - Get samples from a lognormal distribution for McICA
     1! radiation_pdf_sampler.F90 - Get samples from a PDF for McICA
    22!
    33! (C) Copyright 2015- ECMWF.
     
    2222
    2323  !---------------------------------------------------------------------
    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)
    2728  type pdf_sampler_type
    2829    ! Number of points in look-up table for cumulative distribution
     
    4344    procedure :: sample => sample_from_pdf
    4445    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
    4548    procedure :: deallocate => deallocate_pdf_sampler
    4649
     
    117120
    118121  !---------------------------------------------------------------------
    119   ! Extract the value of a lognormal distribution with fractional
    120   ! standard deviation "fsd" corresponding to the cumulative
    121   ! distribution function value "cdf", and return it in val. Since this
    122   ! is an elemental subroutine, 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.
    123126  elemental subroutine sample_from_pdf(this, fsd, cdf, val)
    124127   
     
    156159
    157160  !---------------------------------------------------------------------
    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.
    163165  subroutine sample_from_pdf_masked(this, nsamp, fsd, cdf, val, mask)
    164166   
     
    208210  end subroutine sample_from_pdf_masked
    209211
     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
    210323end module radiation_pdf_sampler
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_save.F90

    r3908 r4444  
    3333  ! thermodynamics object
    3434  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)
    3637
    3738    use yomhook,                  only : lhook, dr_hook
     
    5051    integer,          optional, intent(in) :: iverbose
    5152    logical,          optional, intent(in) :: is_hdf5_file
     53    logical,          optional, intent(in) :: is_double_precision
    5254    character(len=*), optional, intent(in) :: experiment_name
    5355
     
    9698    ! output file column varies most slowly so need to transpose
    9799    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
    98105
    99106    ! Spectral fluxes in memory are dimensioned (nband,ncol,nlev), but
     
    885892           &   dim2_name="column", dim1_name="level", &
    886893           &   units_str="m", long_name="Ice effective radius")
    887       if (allocated(cloud%re_ice)) then
     894      if (associated(cloud%re_ice)) then
    888895        call out_file%define_variable("re_ice", &
    889896             &   dim2_name="column", dim1_name="level", &
     
    966973      call out_file%put("q_ice", cloud%q_ice)
    967974      call out_file%put("re_liquid", cloud%re_liq)
    968       if (allocated(cloud%re_ice)) then
     975      if (associated(cloud%re_ice)) then
    969976        call out_file%put("re_ice", cloud%re_ice)
    970977      end if
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_scheme.F90

    r4388 r4444  
    642642
    643643! Compute UV fluxes as weighted sum of appropriate shortwave bands
     644!AI ATTENTION
     645if (0.eq.1) then
    644646PFLUX_UV       (KIDIA:KFDIA) = 0.0_JPRB
    645647DO JBAND = 1,NWEIGHT_UV
     
    658660       &  * flux%sw_dn_surf_clear_band(IBAND_PAR(JBAND),KIDIA:KFDIA)
    659661ENDDO
    660 
     662endif
    661663! Compute effective broadband emissivity
    662664ZBLACK_BODY_NET_LW = flux%lw_dn(KIDIA:KFDIA,KLEV+1) &
     
    677679!AI ATTENTION
    678680!IF (YRERAD%LAPPROXSWUPDATE) THEN
     681if (0.eq.1) then
    679682IF (rad_config%do_surface_sw_spectral_flux) THEN
    680683  PSWDIFFUSEBAND(KIDIA:KFDIA,:) = 0.0_JPRB
     
    691694  ENDDO
    692695ENDIF
    693 
     696endif
    694697CALL single_level%deallocate
    695698CALL thermodynamics%deallocate
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_setup.F90

    r4388 r4444  
    8888
    8989    USE radiation_interface,      ONLY : setup_radiation
    90     USE radiation_aerosol_optics, ONLY : dry_aerosol_sw_mass_extinction
     90!    USE radiation_aerosol_optics, ONLY : dry_aerosol_sw_mass_extinction
    9191
    9292! AI (propre a IFS)   
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_single_level.F90

    r3908 r4444  
    9595 
    9696  !---------------------------------------------------------------------
     97  ! Allocate the arrays of a single-level type
    9798  subroutine allocate_single_level(this, ncol, nalbedobands, nemisbands, &
    9899       &                           use_sw_albedo_direct, is_simple_surface)
     
    142143
    143144  !---------------------------------------------------------------------
     145  ! Deallocate the arrays of a single-level type
    144146  subroutine deallocate_single_level(this)
    145147
     
    227229    ! Temporary storage of albedo in ecRad bands
    228230    real(jprb) :: sw_albedo_band(istartcol:iendcol, config%n_bands_sw)
    229     real(jprb) :: lw_albedo_band (istartcol:iendcol, config%n_bands_lw)
     231    real(jprb) :: lw_albedo_band(istartcol:iendcol, config%n_bands_lw)
    230232
    231233    ! Number of albedo bands
     
    233235
    234236    ! Loop indices for ecRad bands and albedo bands
    235     integer :: jband, jalbedoband
     237    integer :: jband, jalbedoband, jcol
    236238
    237239    real(jprb) :: hook_handle
     
    239241    if (lhook) call dr_hook('radiation_single_level:get_albedos',0,hook_handle)
    240242
    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
    267266        sw_albedo_band = 0.0_jprb
    268267        do jband = 1,config%n_bands_sw
    269268          do jalbedoband = 1,nalbedoband
    270269            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
    275276            end if
    276277          end do
    277278        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
    280299      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
    282309      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
    296313      if (config%use_canopy_full_spectrum_lw) then
    297314        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()
    300318        end if
    301319        lw_albedo = 1.0_jprb - transpose(this%lw_emissivity(istartcol:iendcol,:))
     
    303321        ! Albedos averaged accurately to ecRad spectral bands
    304322        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
    305328        lw_albedo_band = 0.0_jprb
    306329        do jband = 1,config%n_bands_lw
    307330          do jalbedoband = 1,nalbedoband
    308331            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
    313338            end if
    314339          end do
     
    335360
    336361    use yomhook,          only : lhook, dr_hook
    337     use radiation_config, only : out_of_bounds_1d, out_of_bounds_2d
     362    use radiation_check, only : out_of_bounds_1d, out_of_bounds_2d
    338363
    339364    class(single_level_type), intent(inout) :: this
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_spartacus_lw.F90

    r3908 r4444  
    6666    use radiation_matrix
    6767    use radiation_two_stream,     only : calc_two_stream_gammas_lw, &
    68          calc_reflectance_transmittance_lw, LwDiffusivity
     68         calc_reflectance_transmittance_lw, LwDiffusivityWP
    6969    use radiation_lw_derivatives, only : calc_lw_derivatives_matrix
    7070    use radiation_constants,      only : Pi, GasConstantDryAir, &
     
    615615            planck_top(1:ng3D,nreg+jreg) = od_region(1:ng3D,jreg) &
    616616                 &  *(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
    618618            planck_top(1:ng3D,jreg) = -planck_top(1:ng3D,nreg+jreg)
    619619            planck_diff(1:ng3D,nreg+jreg) = od_region(1:ng3D,jreg) &
    620620                 &  * (1.0_jprb-ssa_region(1:ng3D,jreg))*region_fracs(jreg,jlev,jcol) &
    621621                 &  * (planck_hl(1:ng3D,jlev+1,jcol) &
    622                  &  -planck_hl(1:ng3D,jlev,jcol))*LwDiffusivity
     622                 &  -planck_hl(1:ng3D,jlev,jcol))*LwDiffusivityWP
    623623            planck_diff(1:ng3D,jreg) = -planck_diff(1:ng3D,nreg+jreg)
    624624          end do
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_spartacus_sw.F90

    r3908 r4444  
    13031303                  transfer_scaling = 1.0_jprb - (1.0_jprb - config%overhang_factor) &
    13041304                       &  * 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)) &
    13061306                       &  / max(config%cloud_fraction_threshold, region_fracs(jreg,jlev,jcol))
    13071307                  do jreg4 = 1,nreg
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_thermodynamics.F90

    r3908 r4444  
    297297
    298298    use yomhook,          only : lhook, dr_hook
    299     use radiation_config, only : out_of_bounds_2d
     299    use radiation_check, only : out_of_bounds_2d
    300300
    301301    class(thermodynamics_type), intent(inout) :: this
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_tripleclouds_lw.F90

    r3908 r4444  
    1818!   2017-10-23  R. Hogan  Renamed single-character variables
    1919!   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
    2022
    2123module radiation_tripleclouds_lw
     
    2830#include "radiation_optical_depth_scaling.h"
    2931
     32  !---------------------------------------------------------------------
    3033  ! This module contains just one subroutine, the longwave
    3134  ! "Tripleclouds" solver in which cloud inhomogeneity is treated by
     
    3336  ! cloudy (with differing optical depth). This approach was described
    3437  ! by Shonk and Hogan (2008).
    35 
    3638  subroutine solver_tripleclouds_lw(nlev,istartcol,iendcol, &
    3739       &  config, cloud, &
     
    4850    use radiation_regions, only        : calc_region_properties
    4951    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
    5253    use radiation_matrix, only         : singlemat_x_vec
    5354    use radiation_two_stream, only     : calc_two_stream_gammas_lw, &
    5455         &                               calc_reflectance_transmittance_lw, &
    5556         &                               calc_no_scattering_transmittance_lw
     57    use radiation_adding_ica_lw, only  : adding_ica_lw, calc_fluxes_no_scattering_lw
    5658    use radiation_lw_derivatives, only : calc_lw_derivatives_region
    5759
     
    130132    ! streams
    131133    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
    133139
    134140    ! ...clear-sky equivalent
    135141    real(jprb), dimension(config%n_g_lw, nlev) &
    136          &  :: Sup_clear, Sdn_clear
     142         &  :: source_up_clear, source_dn_clear
    137143
    138144    ! Total albedo of the atmosphere/surface just above a layer
     
    147153    real(jprb), dimension(config%n_g_lw, nregions, nlev+1) :: total_source
    148154
    149     ! ...equivalent values for clear-skies
    150     real(jprb), dimension(config%n_g_lw, nlev+1) :: total_albedo_clear, total_source_clear
    151 
    152155    ! Total albedo and source of the atmosphere just below a layer interface
    153156    real(jprb), dimension(config%n_g_lw, nregions) &
     
    160163
    161164    ! ...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) &
    163166         &  :: flux_dn_clear, flux_up_clear
    164167
     
    170173    ! and below the ground, both treated as single-region clear skies
    171174    logical :: is_clear_sky_layer(0:nlev+1)
     175
     176    ! Index of the highest cloudy layer
     177    integer :: i_cloud_top
    172178
    173179    integer :: jcol, jlev, jg, jreg, jreg2, ng
     
    208214      ! cloud%crop_cloud_fraction has already been called
    209215      is_clear_sky_layer = .true.
     216      i_cloud_top = nlev+1
    210217      do jlev = 1,nlev
    211218        if (cloud%fraction(jcol,jlev) > 0.0_jprb) then
    212219          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
    213224        end if
    214225      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
    218294      ! --------------------------------------------------------
    219295      ! In this section the reflectance, transmittance and sources
    220296      ! 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
    222308
    223309        ! Array-wise assignments
     
    225311        gamma2 = 0.0_jprb
    226312
     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
    227317        nreg = nregions
    228318        if (is_clear_sky_layer(jlev)) then
    229319          nreg = 1
    230320          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
    253326            ! Cloudy sky
    254327            ! Add scaled cloud optical depth to clear-sky value
     
    291364                   &  planck_hl(:,jlev,jcol), planck_hl(:,jlev+1,jcol), &
    292365                   &  reflectance(:,jreg,jlev), transmittance(:,jreg,jlev), &
    293                    &  Sup(:,jreg,jlev), Sdn(:,jreg,jlev))
     366                   &  source_up(:,jreg,jlev), source_dn(:,jreg,jlev))
    294367            else
    295368              ! No-scattering case: use simpler functions for
     
    297370              call calc_no_scattering_transmittance_lw(ng, od_total, &
    298371                   &  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))
    300373              reflectance(:,jreg,jlev) = 0.0_jprb
    301374            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
    309376          ! Emission is scaled by the size of each region
    310377          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)
    313380          end do
    314381        end if
     
    317384
    318385      ! --------------------------------------------------------
    319       ! Section 4: Compute total sources albedos
     386      ! Section 5: Compute total sources and albedos at each half level
    320387      ! --------------------------------------------------------
    321388
     
    333400        end do
    334401      end do
    335       ! Equivalent surface values for computing clear-sky fluxes
    336       if (config%do_clear) then
    337         do jg = 1,ng
    338           total_source_clear(jg,nlev+1) = emission(jg,jcol)
    339         end do
    340         ! In the case of surface albedo there is no dependence on
    341         ! cloud fraction so we can copy the all-sky value
    342         total_albedo_clear(1:ng,nlev+1) = total_albedo(1:ng,1,nlev+1)
    343       end if
    344402
    345403      ! Work up from the surface computing the total albedo of the
    346404      ! atmosphere and the total upwelling due to emission below each
    347405      ! level below using the adding method
    348       do jlev = nlev,1,-1
     406      do jlev = nlev,i_cloud_top,-1
    349407
    350408        total_albedo_below        = 0.0_jprb
    351409
    352         if (config%do_clear) then
    353           ! For clear-skies there is no need to consider "above" and
    354           ! "below" quantities since with no cloud overlap to worry
    355           ! about, these are the same
    356           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 if
    366 
    367410        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))
    370411          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)
    374412          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
    379424        else
    380425          inv_denom = 1.0_jprb / (1.0_jprb - total_albedo(:,:,jlev+1)*reflectance(:,:,jlev))
     
    382427               &  + transmittance(:,:,jlev)*transmittance(:,:,jlev)*total_albedo(:,:,jlev+1) &
    383428               &  * inv_denom
    384           total_source_below = Sup(:,:,jlev) &
     429          total_source_below = source_up(:,:,jlev) &
    385430               &  + transmittance(:,:,jlev)*(total_source(:,:,jlev+1) &
    386                &  + total_albedo(:,:,jlev+1)*Sdn(:,:,jlev)) &
     431               &  + total_albedo(:,:,jlev+1)*source_dn(:,:,jlev)) &
    387432               &  * inv_denom
    388433        end if
     
    415460
    416461      ! --------------------------------------------------------
    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))
    426494      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), &
    444500               &           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
    449515
    450516      ! 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
    459518
    460519        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
    464526          flux_dn(:,2:)  = 0.0_jprb
    465           flux_up(:,1) = total_source(:,1,jlev+1) + flux_dn(:,1)*total_albedo(:,1,jlev+1)
    466527          flux_up(:,2:)  = 0.0_jprb
    467528        else
    468529          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) ) &
    470531               &  / (1.0_jprb - reflectance(:,:,jlev)*total_albedo(:,:,jlev+1))
    471532          flux_up = total_source(:,:,jlev+1) + flux_dn*total_albedo(:,:,jlev+1)
     
    485546        flux%lw_up(jcol,jlev+1) = sum(sum(flux_up,1))
    486547        flux%lw_dn(jcol,jlev+1) = sum(sum(flux_dn,1))
    487         if (config%do_clear) then
    488           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 if
    491548
    492549        ! Save the spectral fluxes if required
     
    498555               &           config%i_spec_from_reordered_g_lw, &
    499556               &           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
    509558
    510559      end do ! Final loop over levels
     
    513562      ! are at the surface
    514563      flux%lw_dn_surf_g(:,jcol) = sum(flux_dn,2)
    515       if (config%do_clear) then
    516         flux%lw_dn_surf_clear_g(:,jcol) = flux_dn_clear
    517       end if
    518564
    519565      ! Compute the longwave derivatives needed by Hogan and Bozzo
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_tripleclouds_sw.F90

    r3908 r4444  
    1919!   2018-10-08  R. Hogan  Call calc_region_properties
    2020!   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
    2122
    2223module radiation_tripleclouds_sw
     
    3233#include "radiation_optical_depth_scaling.h"
    3334
     35  !---------------------------------------------------------------------
    3436  ! This module contains just one subroutine, the shortwave
    3537  ! "Tripleclouds" solver in which cloud inhomogeneity is treated by
     
    3739  ! cloudy (with differing optical depth). This approach was described
    3840  ! by Shonk and Hogan (2008).
    39 
    4041  subroutine solver_tripleclouds_sw(nlev,istartcol,iendcol, &
    4142       &  config, single_level, cloud, &
     
    356357          ! "below" quantities since with no cloud overlap to worry
    357358          ! 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
    367370        end if
    368371
    369372        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
    379384        else
    380385          inv_denom = 1.0_jprb / (1.0_jprb - total_albedo(:,:,jlev+1)*reflectance(:,:,jlev))
     
    488493      do jlev = 1,nlev
    489494        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
    497504        end if
    498505
    499506        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
    507517          flux_dn(:,2:)  = 0.0_jprb
    508518          flux_up(:,2:)  = 0.0_jprb
  • LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/radiation_two_stream.F90

    r3908 r4444  
    1818!   2017-07-26  R Hogan  Added calc_frac_scattered_diffuse_sw routine
    1919!   2017-10-23  R Hogan  Renamed single-character variables
     20!   2021-02-19  R Hogan  Security for shortwave singularity
    2021
    2122module radiation_two_stream
     
    3132  ! think of acos(1/lw_diffusivity) to be the effective zenith angle
    3233  ! 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
    3436
    3537  ! Shortwave diffusivity factor assumes hemispheric isotropy, assumed
     
    8789    if (lhook) call dr_hook('radiation_two_stream:calc_two_stream_gammas_lw',0,hook_handle)
    8890#endif
    89 
     91! Added for DWD (2020)
     92!NEC$ shortloop
    9093    do jg = 1, ng
    9194      ! Fu et al. (1997), Eq 2.9 and 2.10:
     
    136139    ! Zdunkowski "PIFM" (Zdunkowski et al., 1980; Contributions to
    137140    ! Atmospheric Physics 53, 147-66)
     141! Added for DWD (2020)
     142!NEC$ shortloop
    138143    do jg = 1, ng
    139144      !      gamma1(jg) = 2.0_jprb  - ssa(jg) * (1.25_jprb + 0.75_jprb*g(jg))
     
    205210#endif
    206211
     212! Added for DWD (2020)
     213!NEC$ shortloop
    207214    do jg = 1, ng
    208215      if (od(jg) > 1.0e-3_jprd) then
     
    293300#endif
    294301
     302! Added for DWD (2020)
     303!NEC$ shortloop
    295304    do jg = 1, ng
    296305      k_exponent = sqrt(max((gamma1(jg) - gamma2(jg)) * (gamma1(jg) + gamma2(jg)), &
     
    359368#endif
    360369
     370! Added for DWD (2020)
     371!NEC$ shortloop
    361372    do jg = 1, ng
    362373      ! Compute upward and downward emission assuming the Planck
     
    450461    integer    :: jg
    451462
     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
    452468#ifdef DO_DR_HOOK_TWO_STREAM
    453469    real(jprb) :: hook_handle
     
    456472#endif
    457473
     474! Added for DWD (2020)
     475!NEC$ shortloop
    458476    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
    464478        gamma4 = 1.0_jprd - gamma3(jg)
    465479        alpha1 = gamma1(jg)*gamma4     + gamma2(jg)*gamma3(jg) ! Eq. 16
    466480        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
    468497        ! Note that if the minimum value is reduced (e.g. to 1.0e-24)
    469498        ! then noise starts to appear as a function of solar zenith
    470499        ! 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
    474501        k_gamma3 = k_exponent*gamma3(jg)
    475502        k_gamma4 = k_exponent*gamma4
     
    482509        k_2_exponential = 2.0_jprd * k_exponent * exponential
    483510       
    484         if (k_mu0 == 1.0_jprd) then
    485           k_mu0 = 1.0_jprd - 10.0_jprd*epsilon(1.0_jprd)
    486         end if
    487        
    488511        reftrans_factor = 1.0_jprd / (k_exponent + gamma1(jg) + (k_exponent - gamma1(jg))*exponential2)
    489512       
     
    498521        ! to be the flux into a plane perpendicular to the direction of
    499522        ! 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)
    501524       
    502525        ! Meador & Weaver (1980) Eq. 14, multiplying top & bottom by
     
    505528             &  * ( (1.0_jprd - k_mu0) * (alpha2 + k_gamma3) &
    506529             &     -(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)
    508531       
    509532        ! Meador & Weaver (1980) Eq. 15, multiplying top & bottom by
    510533        ! exp(-k_exponent*od), minus the 1*exp(-od/mu0) term representing direct
    511534        ! 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) &
    513536            & - exponential0 &
    514537            & * ( (1.0_jprd + k_mu0) * (alpha1 + k_gamma4) &
    515538            &    -(1.0_jprd - k_mu0) * (alpha1 - k_gamma4) * exponential2) )
    516539
    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
    526544    end do
    527545   
     
    587605#endif
    588606
     607! Added for DWD (2020)
     608!NEC$ shortloop
    589609    do jg = 1, ng
    590610      od_over_mu0 = max(gamma0(jg) * depth, 0.0_jprd)
     
    699719#endif
    700720
     721! Added for DWD (2020)
     722!NEC$ shortloop
    701723    do jg = 1, ng
    702724      ! 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  
    239239  ! Generate uniformly distributed random numbers in the range 0.0<= px < 1.0
    240240  !--------------------------------------------------------------------------------
    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)
    244242  TYPE(RANDOMNUMBERSTREAM), INTENT(INOUT) :: YD_STREAM
    245243  REAL(KIND=JPRB), DIMENSION(:),     INTENT(  OUT) :: PX
     244
    246245  INTEGER(KIND=JPIM)                :: JJ, JK, IN, IFILLED
    247246 
     
    253252  IF(YD_STREAM%INITTEST /= INITVALUE) &
    254253    & CALL ABOR1 ('uniform_distribution called before initialize_random_numbers')
    255  
     254
    256255  !--------------------------------------------------------------------------------
    257256  ! Copy numbers that were generated during the last call, but not used.
Note: See TracChangeset for help on using the changeset viewer.