LCOV - code coverage report
Current view: top level - src - mo_percentile.f90 (source / functions) Hit Total Coverage
Test: forces coverage Lines: 354 374 94.7 %
Date: 2024-03-13 19:03:28 Functions: 10 10 100.0 %

          Line data    Source code
       1             : !> \file mo_percentile.f90
       2             : !> \brief \copybrief mo_percentile
       3             : !> \details \copydetails mo_percentile
       4             : 
       5             : !> \brief  Median and percentiles.
       6             : !> \details This module provides routines for median and percentiles.
       7             : !> \changelog
       8             : !! - Matthias Cuntz, Mar 2011
       9             : !!   - written
      10             : !! - Juliane Mai, Jul 2012
      11             : !!   - different interpolation schemes in percentiles
      12             : !! - Matthias Cuntz, Juliane Mai, Jul 2012
      13             : !!   - uses previous of ksmallest to half execution time
      14             : !! - Matthias Cuntz, May 2014
      15             : !!   - removed numerical recipes
      16             : !> \author Mathias Cuntz
      17             : !> \date Mar 2011
      18             : !> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
      19             : !! FORCES is released under the LGPLv3+ license \license_note
      20             : MODULE mo_percentile
      21             : 
      22             :   USE mo_kind, ONLY : i4, sp, dp
      23             : 
      24             :   Implicit NONE
      25             : 
      26             :   PUBLIC :: median          ! Median
      27             :   PUBLIC :: n_element       ! The n-th smallest value in an array
      28             :   PUBLIC :: percentile      ! The value below which a certain percent of the input fall
      29             :   PUBLIC :: qmedian         ! Quick median calculation, rearranges input
      30             : 
      31             :   ! ------------------------------------------------------------------
      32             : 
      33             :   !>    \brief Median.
      34             : 
      35             :   !>    \details
      36             :   !!    Returns the median of the values in an array.
      37             :   !!    If size is even, then the mean of the size/2 and size/2+1 element is the median.
      38             :   !!
      39             :   !!    If an optinal mask is given, values only on those locations that correspond
      40             :   !!    to true values in the mask are used.
      41             :   !!
      42             :   !!    \b Example
      43             :   !!
      44             :   !!    \code{.f90}
      45             :   !!    vec = (/ 1.,2.,3.,4.,5.,6.,7.,8.,9.,10. /)
      46             :   !!    ! Returns 5.5
      47             :   !!    out = median(vec)
      48             :   !!    \endcode
      49             :   !!
      50             :   !!    See also example in test directory.
      51             : 
      52             :   !>    \param[in]  "real(sp/dp) :: vec(:)"               1D-array with input numbers
      53             :   !>    \param[in]  "logical, optional     :: mask(:)"    1D-array of logical values with size(vec).
      54             :   !!                                                      If present, only those locations in vec
      55             :   !!                                                      corresponding to the true values in mask are used.
      56             :   !>    \retval     "real(sp/dp) :: out"                  Median of values in input array
      57             : 
      58             :   !>    \author Matthias Cuntz
      59             :   !>    \date Mar 2011
      60             :   !>    \author Juliane Mai
      61             :   !>    \date Jul 2012
      62             :   !!      - uses previous of ksmallest to half execution time
      63             : 
      64             :   INTERFACE median
      65             :     MODULE PROCEDURE median_sp, median_dp
      66             :   END INTERFACE median
      67             : 
      68             :   ! ------------------------------------------------------------------
      69             : 
      70             :   !>    \brief Nth smallest value in array.
      71             : 
      72             :   !>    \details
      73             :   !!    Returns the n-th smallest value in an array.
      74             :   !!
      75             :   !!    If an optinal mask is given, values only on those locations that correspond
      76             :   !!    to true values in the mask are used.
      77             :   !!
      78             :   !!    \b Example
      79             :   !!
      80             :   !!    \code{.f90}
      81             :   !!    vec = (/ 1.,2.,3.,4.,5.,6.,7.,8.,9.,10. /)
      82             :   !!    ! Returns 4
      83             :   !!    out = n_element(vec,4)
      84             :   !!    \endcode
      85             :   !!
      86             :   !!    See also example in test directory.
      87             :   !!
      88             :   !!    \b Literature
      89             :   !!
      90             :   !!    1. Niklaus Wirth. _"Algorithms and Data Structures"_. Prentice-Hall, Inc., 1985. ISBN 0-13-022005-1.
      91             :   !!
      92             :   !>    \param[in]  "real(sp/dp) :: vec(:)"             1D-array with input numbers
      93             :   !>    \param[in]  "integer(i4), optional :: n"        Index of sorted array
      94             :   !>    \param[in]  "logical, optional     :: mask(:)"  1D-array of logical values with size(vec).
      95             :   !!                                                    If present, only those locations in vec
      96             :   !!                                                    corresponding to the true values in mask are used.
      97             :   !>    \param[out]  "real(sp/dp) :: before"            (n-1)-th smallest value in input array, e.g.
      98             :   !!                                                    for median/percentile calculations
      99             :   !>    \param[out]  "real(sp/dp) :: previous"          Same as before
     100             :   !>    \param[out]  "real(sp/dp) :: after"             (n+1)-th smallest value in input array
     101             :   !>    \param[out]  "real(sp/dp) :: next"              Same as after
     102             :   !>    \retval  "real(sp/dp) :: out"           N-th smallest value in input array
     103             : 
     104             :   !>    \author Matthias Cuntz
     105             :   !>    \date May 2014
     106             :   !!        - based on qmedian
     107             : 
     108             : 
     109             :   INTERFACE n_element
     110             :     MODULE PROCEDURE n_element_dp, n_element_sp
     111             :   END INTERFACE n_element
     112             : 
     113             :   ! ------------------------------------------------------------------
     114             : 
     115             :   !>    \brief Percentile.
     116             : 
     117             :   !>    \details
     118             :   !!    Returns the value below which a certain percent of array values fall.
     119             :   !!
     120             :   !!    If an optinal mask is given, values only on those locations that correspond
     121             :   !!    to true values in the mask are used.
     122             :   !!
     123             :   !!    Different definitions can be applied to interpolate the stepwise CDF of the given data.
     124             :   !!    1. Inverse empirical CDF (no interpolation, default MATHEMATICA)
     125             :   !!    2. Linear interpolation (California method)
     126             :   !!    3. Element numbered closest
     127             :   !!    4. Linear interpolation (hydrologist method)
     128             :   !!    5. Mean-based estimate (Weibull method, default IMSL)
     129             :   !!    6. Mode-based estimate
     130             :   !!    7. Median-based estimate
     131             :   !!    8. normal distribution estimate
     132             :   !!
     133             :   !!    See: http://reference.wolfram.com/mathematica/tutorial/BasicStatistics.html
     134             :   !!
     135             :   !!    \b Example
     136             :   !!
     137             :   !!    \code{.f90}
     138             :   !!    vec = (/ 1.,2.,3.,4.,5.,6.,7.,8.,9.,10. /)
     139             :   !!    ! Returns 10.
     140             :   !!    out = percentile(vec,95.)
     141             :   !!    ! Returns (10.,8)
     142             :   !!    out = percentile(vec,(/95.,80./))
     143             :   !!    \endcode
     144             :   !!
     145             :   !!    See also example in test directory
     146             : 
     147             :   !>    \param[in]  "real(sp/dp) :: vec(:)"             1D-array with input numbers
     148             :   !>    \param[in]  "real(sp/dp) :: k[(:)]"             Percentage of percentile, can be 1 dimensional
     149             :   !>    \param[in]  "logical, optional  :: mask(:)"     1D-array of logical values with size(vec).
     150             :   !!                                                    If present, only those locations in vec
     151             :   !!                                                    corresponding to the true values in mask are used.
     152             :   !>    \param[in]  "integer(i4), optional :: mode_in"  Specifies the interpolation scheme applied.\n
     153             :   !!                                                    Default:
     154             :   !!                                                    Inverse empirical CDF (no interpolation, default Mathematica)
     155             :   !!                                                    mode_in = 1_i4
     156             :   !>    \retval     "real(sp/dp) :: out[(size(k))]"     k-th percentile of values in input array, can be
     157             :   !!                                                    1 dimensional corresponding to k
     158             : 
     159             :   !>    \author Matthias Cuntz
     160             :   !>    \date Mar 2011
     161             : 
     162             :   !>    \author Stephan Thober
     163             :   !>    \date Dec 2011
     164             :   !!      - added 1 dimensional version
     165             : 
     166             :   !>    \author Juliane Mai
     167             :   !>    \date Jul 2012
     168             :   !!      - different interpolation schemes
     169             : 
     170             :   !>    \authors Matthias Cuntz, Juliane Mai
     171             :   !>    \date Jul 2012
     172             :   !!      - uses previous of ksmallest to half execution time
     173             : 
     174             :   INTERFACE percentile
     175             :     MODULE PROCEDURE percentile_0d_sp, percentile_0d_dp, percentile_1d_sp, percentile_1d_dp
     176             :   END INTERFACE percentile
     177             : 
     178             :   ! ------------------------------------------------------------------
     179             : 
     180             :   !>    \brief  Quick median calculation
     181             : 
     182             :   !>    \details
     183             :   !!    Quick calculation of the median thereby rearranging the input array.
     184             :   !!
     185             :   !!    \b Example
     186             :   !!
     187             :   !!    \code{.f90}
     188             :   !!    vec = (/ 1.,2.,3.,4.,5.,6.,7.,8.,9.,10. /)
     189             :   !!    ! Returns 5.5
     190             :   !!    out = qmedian(vec)
     191             :   !!    \endcode
     192             :   !!
     193             :   !!    See also example in test directory.
     194             :   !!
     195             :   !!    \b Literature
     196             :   !!    1. Niklaus Wirth. _"Algorithms and Data Structures"_. Prentice-Hall, Inc., 1985. ISBN 0-13-022005-1.
     197             :   !!
     198             :   !>    \param[inout] "real(sp/dp) :: vec(:)"     1D-array with input numbers.
     199             :   !!                                              Will be rearranged on output.
     200             :   !>    \retval       "real(sp/dp) :: out"        Median of values in input array
     201             : 
     202             :   !>    \author Filip Hroch
     203             :   !!      - as part of Munipack: http://munipack.physics.muni.cz
     204             :   !>    \author Matthias Cuntz
     205             :   !>    \date Jul 2012
     206             :   !!      - function, k=n/2+1
     207             :   !!      - real median for even n
     208             : 
     209             :   INTERFACE qmedian
     210             :     MODULE PROCEDURE qmedian_sp, qmedian_dp
     211             :   END INTERFACE qmedian
     212             : 
     213             :   ! ------------------------------------------------------------------
     214             : 
     215             :   PRIVATE
     216             : 
     217             :   ! ------------------------------------------------------------------
     218             : 
     219             : CONTAINS
     220             : 
     221             :   ! ------------------------------------------------------------------
     222             : 
     223           8 :   FUNCTION median_dp(arrin, mask)
     224             : 
     225             :     IMPLICIT NONE
     226             : 
     227             :     REAL(dp), DIMENSION(:), INTENT(IN) :: arrin
     228             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     229             :     REAL(dp) :: median_dp
     230             : 
     231             :     INTEGER(i4) :: n
     232           4 :     REAL(dp), DIMENSION(:), ALLOCATABLE :: arr
     233           4 :     REAL(dp) :: tmp
     234             : 
     235           4 :     if (present(mask)) then
     236          22 :       n = count(mask)
     237           6 :       allocate(arr(n))
     238           2 :       arr = pack(arrin, mask)
     239             : 
     240           2 :       if (n < 2) stop 'median_dp: n < 2'
     241             : 
     242           2 :       if (mod(n, 2) == 0) then ! Even
     243           1 :         median_dp = n_element(arr, n / 2 + 1, previous = tmp)
     244           1 :         median_dp = 0.5_dp * (median_dp + tmp)
     245             :       else ! Odd
     246           1 :         median_dp = n_element(arr, (n + 1) / 2)
     247             :       end if
     248             : 
     249           2 :       deallocate(arr)
     250             :     else
     251           2 :       n = size(arrin)
     252           2 :       if (n < 2) stop 'median_dp: n < 2'
     253             : 
     254           2 :       if (mod(n, 2) == 0) then ! Even
     255           1 :         median_dp = n_element(arrin, n / 2 + 1, previous = tmp)
     256           1 :         median_dp = 0.5_dp * (median_dp + tmp)
     257             :       else ! Odd
     258           1 :         median_dp = n_element(arrin, (n + 1) / 2)
     259             :       end if
     260             :     end if
     261             : 
     262           4 :   END FUNCTION median_dp
     263             : 
     264             : 
     265           8 :   FUNCTION median_sp(arrin, mask)
     266             : 
     267             :     IMPLICIT NONE
     268             : 
     269             :     REAL(sp), DIMENSION(:), INTENT(IN) :: arrin
     270             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     271             :     REAL(sp) :: median_sp
     272             : 
     273             :     INTEGER(i4) :: n
     274           4 :     REAL(sp), DIMENSION(:), ALLOCATABLE :: arr
     275           4 :     REAL(sp) :: tmp
     276             : 
     277           4 :     if (present(mask)) then
     278          22 :       n = count(mask)
     279           6 :       allocate(arr(n))
     280           2 :       arr = pack(arrin, mask)
     281             : 
     282           2 :       if (n < 2) stop 'median_sp: n < 2'
     283             : 
     284           2 :       if (mod(n, 2) == 0) then ! Even
     285           1 :         median_sp = n_element(arr, n / 2 + 1, previous = tmp)
     286           1 :         median_sp = 0.5_sp * (median_sp + tmp)
     287             :       else ! Odd
     288           1 :         median_sp = n_element(arr, (n + 1) / 2)
     289             :       end if
     290             : 
     291           2 :       deallocate(arr)
     292             :     else
     293           2 :       n = size(arrin)
     294           2 :       if (n < 2) stop 'median_sp: n < 2'
     295             : 
     296           2 :       if (mod(n, 2) == 0) then ! Even
     297           1 :         median_sp = n_element(arrin, n / 2 + 1, previous = tmp)
     298           1 :         median_sp = 0.5_sp * (median_sp + tmp)
     299             :       else ! Odd
     300           1 :         median_sp = n_element(arrin, (n + 1) / 2)
     301             :       end if
     302             :     end if
     303             : 
     304           8 :   END FUNCTION median_sp
     305             : 
     306             :   ! ------------------------------------------------------------------
     307             : 
     308        1580 :   function n_element_dp(idat, n, mask, before, after, previous, next)
     309             : 
     310             :     IMPLICIT NONE
     311             : 
     312             :     real(dp), dimension(:), intent(in) :: idat
     313             :     integer(i4), intent(in) :: n
     314             :     logical, dimension(:), optional, intent(in) :: mask
     315             :     real(dp), optional, intent(out) :: before
     316             :     real(dp), optional, intent(out) :: after
     317             :     real(dp), optional, intent(out) :: previous
     318             :     real(dp), optional, intent(out) :: next
     319             :     real(dp) :: n_element_dp
     320             : 
     321         790 :     real(dp), dimension(:), allocatable :: dat
     322         790 :     real(dp) :: w
     323             :     integer(i4) :: nn, k
     324             :     integer(i4) :: l, r, i, j
     325             : 
     326         790 :     if (present(mask)) then
     327          11 :       nn = count(mask)
     328           3 :       allocate(dat(nn))
     329           1 :       dat = pack(idat, mask)
     330             :     else
     331         789 :       nn = size(idat)
     332        2367 :       allocate(dat(nn))
     333     4531583 :       dat = idat
     334             :     end if
     335             : 
     336         790 :     if (n < 1)  stop 'n_element_dp: n < 1'
     337         790 :     if (n > nn) stop 'n_element_dp: n > size(pack(dat,mask))'
     338             : 
     339             :     !dat = idat
     340         790 :     nn = size(dat)
     341         790 :     k = n !nn/2 + 1
     342         790 :     l = 1
     343         790 :     r = nn
     344       10775 :     do while(l < r)
     345        9985 :       n_element_dp = dat(k)
     346        9985 :       i = l
     347        9985 :       j = r
     348             :       do
     349     8735803 :         do while(dat(i) < n_element_dp)
     350     8735803 :           i = i + 1
     351             :         enddo
     352     4659710 :         do while(n_element_dp < dat(j))
     353     2271176 :           j = j - 1
     354             :         enddo
     355     2388534 :         if (i <= j) then
     356     2380140 :           w = dat(i)
     357     2380140 :           dat(i) = dat(j)
     358     2380140 :           dat(j) = w
     359     2380140 :           i = i + 1
     360     2380140 :           j = j - 1
     361             :         end if
     362     2388534 :         if (i > j) exit
     363             :       enddo
     364        9985 :       if (j < k) l = i
     365        9985 :       if (k < i) r = j
     366             :     enddo
     367             :     ! if (mod(nn,2) == 0) then
     368             :     !    n_element_dp = 0.5_dp*(dat(k) + maxval(dat(:k-1)))
     369             :     ! else
     370             :     !    n_element_dp = dat(k)
     371             :     ! end if
     372         790 :     n_element_dp = dat(k)
     373             : 
     374         790 :     if (present(before))   before = maxval(dat(: k - 1))
     375      908379 :     if (present(previous)) previous = maxval(dat(: k - 1))
     376         790 :     if (present(after))    after = minval(dat(k + 1 :))
     377         790 :     if (present(next))     next = minval(dat(k + 1 :))
     378             : 
     379         790 :     deallocate(dat)
     380             : 
     381           4 :   end function n_element_dp
     382             : 
     383          68 :   function n_element_sp(idat, n, mask, before, after, previous, next)
     384             : 
     385             :     IMPLICIT NONE
     386             : 
     387             :     real(sp), dimension(:), intent(in) :: idat
     388             :     integer(i4), intent(in) :: n
     389             :     logical, dimension(:), optional, intent(in) :: mask
     390             :     real(sp), optional, intent(out) :: before
     391             :     real(sp), optional, intent(out) :: after
     392             :     real(sp), optional, intent(out) :: previous
     393             :     real(sp), optional, intent(out) :: next
     394             :     real(sp) :: n_element_sp
     395             : 
     396          34 :     real(sp), dimension(:), allocatable :: dat
     397          34 :     real(sp) :: w
     398             :     integer(i4) :: nn, k
     399             :     integer(i4) :: l, r, i, j
     400             : 
     401          34 :     if (present(mask)) then
     402          11 :       nn = count(mask)
     403           3 :       allocate(dat(nn))
     404           1 :       dat = pack(idat, mask)
     405             :     else
     406          33 :       nn = size(idat)
     407          99 :       allocate(dat(nn))
     408         391 :       dat = idat
     409             :     end if
     410             : 
     411          34 :     if (n < 1)  stop 'n_element_sp: n < 1'
     412          34 :     if (n > nn) stop 'n_element_sp: n > size(pack(dat,mask))'
     413             : 
     414             :     !dat = idat
     415          34 :     nn = size(dat)
     416          34 :     k = n !nn/2 + 1
     417          34 :     l = 1
     418          34 :     r = nn
     419          68 :     do while(l < r)
     420          34 :       n_element_sp = dat(k)
     421          34 :       i = l
     422          34 :       j = r
     423             :       do
     424         237 :         do while(dat(i) < n_element_sp)
     425         237 :           i = i + 1
     426             :         enddo
     427         131 :         do while(n_element_sp < dat(j))
     428          97 :           j = j - 1
     429             :         enddo
     430          34 :         if (i <= j) then
     431          34 :           w = dat(i)
     432          34 :           dat(i) = dat(j)
     433          34 :           dat(j) = w
     434          34 :           i = i + 1
     435          34 :           j = j - 1
     436             :         end if
     437          34 :         if (i > j) exit
     438             :       enddo
     439          34 :       if (j < k) l = i
     440          34 :       if (k < i) r = j
     441             :     enddo
     442             :     ! if (mod(nn,2) == 0) then
     443             :     !    n_element_sp = 0.5_sp*(dat(k) + maxval(dat(:k-1)))
     444             :     ! else
     445             :     !    n_element_sp = dat(k)
     446             :     ! end if
     447          34 :     n_element_sp = dat(k)
     448             : 
     449          34 :     if (present(before))   before = maxval(dat(: k - 1))
     450         178 :     if (present(previous)) previous = maxval(dat(: k - 1))
     451          34 :     if (present(after))    after = minval(dat(k + 1 :))
     452          34 :     if (present(next))     next = minval(dat(k + 1 :))
     453             : 
     454          34 :     deallocate(dat)
     455             : 
     456         790 :   end function n_element_sp
     457             : 
     458             :   ! ------------------------------------------------------------------
     459             : 
     460        1532 :   FUNCTION percentile_0d_dp(arrin, k, mask, mode_in)
     461             : 
     462             :     IMPLICIT NONE
     463             : 
     464             :     REAL(dp), DIMENSION(:), INTENT(IN) :: arrin
     465             :     REAL(dp), INTENT(IN) :: k
     466             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     467             :     INTEGER(i4), OPTIONAL, INTENT(IN) :: mode_in
     468             :     REAL(dp) :: percentile_0d_dp
     469             : 
     470             :     INTEGER(i4) :: n, nn1, nn2
     471             :     INTEGER(i4) :: mode
     472         766 :     REAL(dp) :: kk, ks1, ks2
     473         766 :     REAL(dp), DIMENSION(:), ALLOCATABLE :: arr
     474             : 
     475         766 :     if (present(mask)) then
     476     5497664 :       n = count(mask)
     477             :     else
     478          12 :       n = size(arrin)
     479             :     end if
     480             : 
     481         766 :     if (present(mode_in)) then
     482         764 :       mode = mode_in
     483             :     else
     484             :       ! Default : Inverse empirical CDF
     485             :       mode = 1_i4
     486             :     end if
     487             : 
     488         766 :     if (n < 2) stop 'percentile_0d_dp: n < 2'
     489             : 
     490           3 :     select case (mode)
     491             :       ! Inverse empirical CDF: Mathematica default
     492             :     case(1_i4)
     493           3 :       kk = k / 100._dp * real(n, dp)
     494           3 :       nn1 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     495           3 :       nn2 = nn1
     496             : 
     497             :       ! Linear interpolation (California method)
     498             :     case(2_i4)
     499           1 :       kk = k / 100._dp * real(n, dp)
     500           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     501           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     502             : 
     503             :       ! Element numbered closest
     504             :     case(3_i4)
     505           1 :       kk = 0.5_dp + k / 100._dp * real(n, dp)
     506           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     507           1 :       nn2 = nn1
     508             : 
     509             :       ! Linear interpolation (hydrologist method)
     510             :     case(4_i4)
     511         757 :       kk = 0.5_dp + k / 100._dp * (real(n, dp))
     512         757 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     513         757 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     514             : 
     515             :       ! Mean-based estimate (Weibull method): IMSL default
     516             :     case(5_i4)
     517           1 :       kk = k / 100._dp * (real(n, dp) + 1._dp)
     518           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     519           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     520             : 
     521             :       ! Mode-based estimate
     522             :     case(6_i4)
     523           1 :       kk = 1.0_dp + k / 100._dp * (real(n, dp) - 1._dp)
     524           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     525           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     526             : 
     527             :       ! Median-based estimate
     528             :     case(7_i4)
     529           1 :       kk = 1.0_dp / 3.0_dp + k / 100._dp * (real(n, dp) + 1.0_dp / 3.0_dp)
     530           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     531           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     532             : 
     533             :       ! Normal distribution estimate
     534             :     case(8_i4)
     535           1 :       kk = 3.0_dp / 8.0_dp + k / 100._dp * (real(n, dp) + 1.0_dp / 4.0_dp)
     536           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     537           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     538             : 
     539             :       ! No valid mode
     540             :     case default
     541         766 :       stop 'percentile_0d_dp: mode > 8 not implemented'
     542             : 
     543             :     end select
     544             : 
     545         766 :     if (present(mask)) then
     546        2262 :       allocate(arr(n))
     547         754 :       arr = pack(arrin, mask)
     548         754 :       if (nn1 .eq. nn2) then
     549             :         ! no interpolation
     550           1 :         percentile_0d_dp = n_element(arr, nn1)
     551             :       else
     552             :         ! interpolation
     553         753 :         ks2 = n_element(arr, nn2, previous = ks1)
     554         753 :         percentile_0d_dp = ks1 + (ks2 - ks1) * (kk - real(nn1, dp))
     555             :       end if
     556         754 :       deallocate(arr)
     557             :     else
     558          12 :       if (nn1 .eq. nn2) then
     559             :         ! no interpolation
     560           4 :         percentile_0d_dp = n_element(arrin, nn1)
     561             :       else
     562             :         ! interpolation
     563           8 :         ks2 = n_element(arrin, nn2, previous = ks1)
     564           8 :         percentile_0d_dp = ks1 + (ks2 - ks1) * (kk - real(nn1, dp))
     565             :       end if
     566             :     end if
     567             : 
     568         800 :   END FUNCTION percentile_0d_dp
     569             : 
     570             : 
     571          20 :   FUNCTION percentile_0d_sp(arrin, k, mask, mode_in)
     572             : 
     573             :     IMPLICIT NONE
     574             : 
     575             :     REAL(sp), DIMENSION(:), INTENT(IN) :: arrin
     576             :     REAL(sp), INTENT(IN) :: k
     577             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     578             :     INTEGER(i4), OPTIONAL, INTENT(IN) :: mode_in
     579             :     REAL(sp) :: percentile_0d_sp
     580             : 
     581             :     INTEGER(i4) :: n, nn1, nn2
     582             :     INTEGER(i4) :: mode
     583          10 :     REAL(sp) :: kk, ks1, ks2
     584          10 :     REAL(sp), DIMENSION(:), ALLOCATABLE :: arr
     585             : 
     586          10 :     if (present(mask)) then
     587          11 :       n = count(mask)
     588             :     else
     589           9 :       n = size(arrin)
     590             :     end if
     591             : 
     592          10 :     if (present(mode_in)) then
     593           8 :       mode = mode_in
     594             :     else
     595             :       ! Default : Inverse empirical CDF
     596             :       mode = 1_i4
     597             :     end if
     598             : 
     599          10 :     if (n < 2) stop 'percentile_0d_sp: n < 2'
     600             : 
     601           3 :     select case (mode)
     602             :       ! Inverse empirical CDF: Mathematica default
     603             :     case(1_i4)
     604           3 :       kk = k / 100._sp * real(n, sp)
     605           3 :       nn1 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     606           3 :       nn2 = nn1
     607             : 
     608             :       ! Linear interpolation (California method)
     609             :     case(2_i4)
     610           1 :       kk = k / 100._sp * real(n, sp)
     611           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     612           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     613             : 
     614             :       ! Element numbered closest
     615             :     case(3_i4)
     616           1 :       kk = 0.5_sp + k / 100._sp * real(n, sp)
     617           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     618           1 :       nn2 = nn1
     619             : 
     620             :       ! Linear interpolation (hydrologist method)
     621             :     case(4_i4)
     622           1 :       kk = 0.5_sp + k / 100._sp * (real(n, sp))
     623           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     624           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     625             : 
     626             :       ! Mean-based estimate (Weibull method): IMSL default
     627             :     case(5_i4)
     628           1 :       kk = k / 100._sp * (real(n, sp) + 1._sp)
     629           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     630           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     631             : 
     632             :       ! Mode-based estimate
     633             :     case(6_i4)
     634           1 :       kk = 1.0_sp + k / 100._sp * (real(n, sp) - 1._sp)
     635           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     636           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     637             : 
     638             :       ! Median-based estimate
     639             :     case(7_i4)
     640           1 :       kk = 1.0_sp / 3.0_sp + k / 100._sp * (real(n, sp) + 1.0_sp / 3.0_sp)
     641           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     642           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     643             : 
     644             :       ! Normal distribution estimate
     645             :     case(8_i4)
     646           1 :       kk = 3.0_sp / 8.0_sp + k / 100._sp * (real(n, sp) + 1.0_sp / 4.0_sp)
     647           1 :       nn1 = min(n, max(1_i4, floor(kk, kind = i4)))
     648           1 :       nn2 = min(n, max(1_i4, ceiling(kk, kind = i4)))
     649             : 
     650             :       ! No valid mode
     651             :     case default
     652          10 :       stop 'percentile_0d_sp: mode > 8 not implemented'
     653             : 
     654             :     end select
     655             : 
     656          10 :     if (present(mask)) then
     657           3 :       allocate(arr(n))
     658           1 :       arr = pack(arrin, mask)
     659           1 :       if (nn1 .eq. nn2) then
     660             :         ! no interpolation
     661           1 :         percentile_0d_sp = n_element(arr, nn1)
     662             :       else
     663             :         ! interpolation
     664           0 :         ks2 = n_element(arr, nn2, previous = ks1)
     665           0 :         percentile_0d_sp = ks1 + (ks2 - ks1) * (kk - real(nn1, sp))
     666             :       end if
     667           1 :       deallocate(arr)
     668             :     else
     669           9 :       if (nn1 .eq. nn2) then
     670             :         ! no interpolation
     671           4 :         percentile_0d_sp = n_element(arrin, nn1)
     672             :       else
     673             :         ! interpolation
     674           5 :         ks2 = n_element(arrin, nn2, previous = ks1)
     675           5 :         percentile_0d_sp = ks1 + (ks2 - ks1) * (kk - real(nn1, sp))
     676             :       end if
     677             :     end if
     678             : 
     679         776 :   END FUNCTION percentile_0d_sp
     680             : 
     681             : 
     682          37 :   function percentile_1d_dp(arrin, k, mask, mode_in)
     683             : 
     684             :     IMPLICIT NONE
     685             : 
     686             :     REAL(dp), DIMENSION(:), INTENT(IN) :: arrin
     687             :     REAL(dp), DIMENSION(:), INTENT(IN) :: k
     688             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     689             :     INTEGER(i4), OPTIONAL, INTENT(IN) :: mode_in
     690             : 
     691             :     REAL(dp), DIMENSION(size(k)) :: percentile_1d_dp
     692             : 
     693             :     INTEGER(i4) :: i, n
     694             :     INTEGER(i4) :: mode
     695           9 :     INTEGER(i4), DIMENSION(size(k)) :: nn1, nn2
     696          45 :     REAL(dp), DIMENSION(size(k)) :: kk
     697           9 :     REAL(dp) :: ks1, ks2
     698           9 :     REAL(dp), DIMENSION(:), ALLOCATABLE :: arr
     699             : 
     700           9 :     if (present(mask)) then
     701           0 :       n = count(mask)
     702             :     else
     703           9 :       n = size(arrin)
     704             :     end if
     705             : 
     706           9 :     if (present(mode_in)) then
     707           8 :       mode = mode_in
     708             :     else
     709             :       ! Default : Inverse empirical CDF
     710             :       mode = 1_i4
     711             :     end if
     712             : 
     713             :     ! check consistency
     714             :     !if (size(k) > size(arr)) stop 'percentile_1d_dp: more Quantiles than data: size(k) > size(arr)'
     715           9 :     if (n < 2) stop 'percentile_1d_dp: n < 2'
     716             : 
     717           2 :     select case (mode)
     718             :       ! Inverse empirical CDF: Mathematica default
     719             :     case(1_i4)
     720           6 :       kk(:) = k(:) / 100._dp * real(n, dp)
     721           6 :       nn1(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     722           6 :       nn2 = nn1
     723             : 
     724             :       ! Linear interpolation (California method)
     725             :     case(2_i4)
     726           3 :       kk(:) = k(:) / 100._dp * real(n, dp)
     727           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     728           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     729             : 
     730             :       ! Element numbered closest
     731             :     case(3_i4)
     732           3 :       kk(:) = 0.5_dp + k(:) / 100._dp * real(n, dp)
     733           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     734           3 :       nn2 = nn1
     735             : 
     736             :       ! Linear interpolation (hydrologist method)
     737             :     case(4_i4)
     738           3 :       kk(:) = 0.5_dp + k(:) / 100._dp * (real(n, dp))
     739           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     740           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     741             : 
     742             :       ! Mean-based estimate (Weibull method): IMSL default
     743             :     case(5_i4)
     744           3 :       kk(:) = k(:) / 100._dp * (real(n, dp) + 1._dp)
     745           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     746           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     747             : 
     748             :       ! Mode-based estimate
     749             :     case(6_i4)
     750           3 :       kk(:) = 1.0_dp + k(:) / 100._dp * (real(n, dp) - 1._dp)
     751           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     752           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     753             : 
     754             :       ! Median-based estimate
     755             :     case(7_i4)
     756           3 :       kk(:) = 1.0_dp / 3.0_dp + k(:) / 100._dp * (real(n, dp) + 1.0_dp / 3.0_dp)
     757           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     758           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     759             : 
     760             :       ! Normal distribution estimate
     761             :     case(8_i4)
     762           3 :       kk(:) = 3.0_dp / 8.0_dp + k(:) / 100._dp * (real(n, dp) + 1.0_dp / 4.0_dp)
     763           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     764           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     765             : 
     766             :       ! No valid mode
     767             :     case default
     768           9 :       stop 'percentile_1d_dp: mode > 8 not implemented'
     769             : 
     770             :     end select
     771             : 
     772           9 :     if (present(mask)) then
     773           0 :       allocate(arr(n))
     774           0 :       arr = pack(arrin, mask)
     775           0 :       do i = 1, size(k)
     776           0 :         if (nn1(i) .eq. nn2(i)) then
     777             :           ! no interpolation
     778           0 :           percentile_1d_dp(i) = n_element(arr, nn1(i))
     779             :         else
     780             :           ! interpolation
     781           0 :           ks2 = n_element(arr, nn2(i), previous = ks1)
     782           0 :           percentile_1d_dp(i) = ks1 + (ks2 - ks1) * (kk(i) - real(nn1(i), dp))
     783             :         end if
     784             :       end do
     785           0 :       deallocate(arr)
     786             :     else
     787          27 :       do i = 1, size(k)
     788          27 :         if (nn1(i) .eq. nn2(i)) then
     789             :           ! no interpolation
     790           8 :           percentile_1d_dp(i) = n_element(arrin, nn1(i))
     791             :         else
     792             :           ! interpolation
     793          10 :           ks2 = n_element(arrin, nn2(i), previous = ks1)
     794          10 :           percentile_1d_dp(i) = ks1 + (ks2 - ks1) * (kk(i) - real(nn1(i), dp))
     795             :         end if
     796             :       end do
     797             :     end if
     798             : 
     799           9 :   END function percentile_1d_dp
     800             : 
     801             : 
     802          36 :   function percentile_1d_sp(arrin, k, mask, mode_in)
     803             : 
     804             :     IMPLICIT NONE
     805             : 
     806             :     REAL(sp), DIMENSION(:), INTENT(IN) :: arrin
     807             :     REAL(sp), DIMENSION(:), INTENT(IN) :: k
     808             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     809             :     INTEGER(i4), OPTIONAL, INTENT(IN) :: mode_in
     810             : 
     811             :     REAL(sp), DIMENSION(size(k)) :: percentile_1d_sp
     812             : 
     813             :     INTEGER(i4) :: i, n
     814             :     INTEGER(i4) :: mode
     815           9 :     INTEGER(i4), DIMENSION(size(k)) :: nn1, nn2
     816          45 :     REAL(sp), DIMENSION(size(k)) :: kk
     817           9 :     REAL(sp) :: ks1, ks2
     818           9 :     REAL(sp), DIMENSION(:), ALLOCATABLE :: arr
     819             : 
     820           9 :     if (present(mask)) then
     821           0 :       n = count(mask)
     822             :     else
     823           9 :       n = size(arrin)
     824             :     end if
     825             : 
     826           9 :     if (present(mode_in)) then
     827           8 :       mode = mode_in
     828             :     else
     829             :       ! Default : Inverse empirical CDF
     830             :       mode = 1_i4
     831             :     end if
     832             : 
     833             :     ! check consistency
     834             :     !if (size(k) > size(arr)) stop 'percentile_1d_sp: more Quantiles than data: size(k) > size(arr)'
     835           9 :     if (n < 2) stop 'percentile_1d_sp: n < 2'
     836             : 
     837           2 :     select case (mode)
     838             :       ! Inverse empirical CDF: Mathematica default
     839             :     case(1_i4)
     840           6 :       kk(:) = k(:) / 100._sp * real(n, sp)
     841           6 :       nn1(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     842           6 :       nn2 = nn1
     843             : 
     844             :       ! Linear interpolation (California method)
     845             :     case(2_i4)
     846           3 :       kk(:) = k(:) / 100._sp * real(n, sp)
     847           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     848           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     849             : 
     850             :       ! Element numbered closest
     851             :     case(3_i4)
     852           3 :       kk(:) = 0.5_sp + k(:) / 100._sp * real(n, sp)
     853           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     854           3 :       nn2 = nn1
     855             : 
     856             :       ! Linear interpolation (hydrologist method)
     857             :     case(4_i4)
     858           3 :       kk(:) = 0.5_sp + k(:) / 100._sp * (real(n, sp))
     859           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     860           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     861             : 
     862             :       ! Mean-based estimate (Weibull method): IMSL default
     863             :     case(5_i4)
     864           3 :       kk(:) = k(:) / 100._sp * (real(n, sp) + 1._sp)
     865           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     866           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     867             : 
     868             :       ! Mode-based estimate
     869             :     case(6_i4)
     870           3 :       kk(:) = 1.0_sp + k(:) / 100._sp * (real(n, sp) - 1._sp)
     871           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     872           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     873             : 
     874             :       ! Median-based estimate
     875             :     case(7_i4)
     876           3 :       kk(:) = 1.0_sp / 3.0_sp + k(:) / 100._sp * (real(n, sp) + 1.0_sp / 3.0_sp)
     877           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     878           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     879             : 
     880             :       ! Normal distribution estimate
     881             :     case(8_i4)
     882           3 :       kk(:) = 3.0_sp / 8.0_sp + k(:) / 100._sp * (real(n, sp) + 1.0_sp / 4.0_sp)
     883           3 :       nn1(:) = min(n, max(1_i4, floor(kk(:), kind = i4)))
     884           3 :       nn2(:) = min(n, max(1_i4, ceiling(kk(:), kind = i4)))
     885             : 
     886             :       ! No valid mode
     887             :     case default
     888           9 :       stop 'percentile_1d_sp: mode > 8 not implemented'
     889             : 
     890             :     end select
     891             : 
     892           9 :     if (present(mask)) then
     893           0 :       allocate(arr(n))
     894           0 :       arr = pack(arrin, mask)
     895           0 :       do i = 1, size(k)
     896           0 :         if (nn1(i) .eq. nn2(i)) then
     897             :           ! no interpolation
     898           0 :           percentile_1d_sp(i) = n_element(arr, nn1(i))
     899             :         else
     900             :           ! interpolation
     901           0 :           ks2 = n_element(arr, nn2(i), previous = ks1)
     902           0 :           percentile_1d_sp(i) = ks1 + (ks2 - ks1) * (kk(i) - real(nn1(i), sp))
     903             :         end if
     904             :       end do
     905           0 :       deallocate(arr)
     906             :     else
     907          27 :       do i = 1, size(k)
     908          27 :         if (nn1(i) .eq. nn2(i)) then
     909             :           ! no interpolation
     910           8 :           percentile_1d_sp(i) = n_element(arrin, nn1(i))
     911             :         else
     912             :           ! interpolation
     913          10 :           ks2 = n_element(arrin, nn2(i), previous = ks1)
     914          10 :           percentile_1d_sp(i) = ks1 + (ks2 - ks1) * (kk(i) - real(nn1(i), sp))
     915             :         end if
     916             :       end do
     917             :     end if
     918             : 
     919           9 :   END function percentile_1d_sp
     920             : 
     921             :   ! ------------------------------------------------------------------
     922             : 
     923           2 :   function qmedian_dp(dat)
     924             : 
     925             :     IMPLICIT NONE
     926             : 
     927             :     real(dp), dimension(:), intent(inout) :: dat
     928             :     real(dp) :: qmedian_dp
     929             : 
     930           2 :     real(dp) :: w
     931             :     integer(i4) :: n, k
     932             :     integer(i4) :: l, r, i, j
     933             : 
     934           2 :     n = size(dat)
     935           2 :     k = n / 2 + 1
     936           2 :     l = 1
     937           2 :     r = n
     938           4 :     do while(l < r)
     939           2 :       qmedian_dp = dat(k)
     940           2 :       i = l
     941           2 :       j = r
     942             :       do
     943          11 :         do while(dat(i) < qmedian_dp)
     944          11 :           i = i + 1
     945             :         enddo
     946          10 :         do while(qmedian_dp < dat(j))
     947           8 :           j = j - 1
     948             :         enddo
     949           2 :         if (i <= j) then
     950           2 :           w = dat(i)
     951           2 :           dat(i) = dat(j)
     952           2 :           dat(j) = w
     953           2 :           i = i + 1
     954           2 :           j = j - 1
     955             :         end if
     956           2 :         if (i > j) exit
     957             :       enddo
     958           2 :       if (j < k) l = i
     959           2 :       if (k < i) r = j
     960             :     enddo
     961           2 :     if (mod(n, 2) == 0) then
     962           8 :       qmedian_dp = 0.5_dp * (dat(k) + maxval(dat(: k - 1)))
     963             :     else
     964           1 :       qmedian_dp = dat(k)
     965             :     end if
     966             : 
     967           9 :   end function qmedian_dp
     968             : 
     969             : 
     970           2 :   function qmedian_sp(dat)
     971             : 
     972             :     IMPLICIT NONE
     973             : 
     974             :     real(sp), dimension(:), intent(inout) :: dat
     975             :     real(sp) :: qmedian_sp
     976             : 
     977           2 :     real(sp) :: w
     978             :     integer(i4) :: n, k
     979             :     integer(i4) :: l, r, i, j
     980             : 
     981           2 :     n = size(dat)
     982           2 :     k = n / 2 + 1
     983           2 :     l = 1
     984           2 :     r = n
     985           4 :     do while(l < r)
     986           2 :       qmedian_sp = dat(k)
     987           2 :       i = l
     988           2 :       j = r
     989             :       do
     990          11 :         do while(dat(i) < qmedian_sp)
     991          11 :           i = i + 1
     992             :         enddo
     993          10 :         do while(qmedian_sp < dat(j))
     994           8 :           j = j - 1
     995             :         enddo
     996           2 :         if (i <= j) then
     997           2 :           w = dat(i)
     998           2 :           dat(i) = dat(j)
     999           2 :           dat(j) = w
    1000           2 :           i = i + 1
    1001           2 :           j = j - 1
    1002             :         end if
    1003           2 :         if (i > j) exit
    1004             :       enddo
    1005           2 :       if (j < k) l = i
    1006           2 :       if (k < i) r = j
    1007             :     enddo
    1008           2 :     if (mod(n, 2) == 0) then
    1009           8 :       qmedian_sp = 0.5_sp * (dat(k) + maxval(dat(: k - 1)))
    1010             :     else
    1011           1 :       qmedian_sp = dat(k)
    1012             :     end if
    1013             : 
    1014           2 :   end function qmedian_sp
    1015             : 
    1016             :   ! ------------------------------------------------------------------
    1017             : 
    1018             : END MODULE mo_percentile

Generated by: LCOV version 1.16