Ignore:
Timestamp:
Mar 31, 2023, 8:42:57 PM (18 months ago)
Author:
lguez
Message:

Merge LMDZ_ECRad branch back into trunk!

Location:
LMDZ6/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • LMDZ6/trunk

  • LMDZ6/trunk/libf/phylmd/ecrad/radiation_cloud_generator.F90

    r3908 r4489  
    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
Note: See TracChangeset for help on using the changeset viewer.