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

          Line data    Source code
       1             : !> \file mo_corr.f90
       2             : !> \brief \copybrief mo_corr
       3             : !> \details \copydetails mo_corr
       4             : 
       5             : !> \brief Provides autocorrelation function calculations.
       6             : !> \author Sebastian Mueller
       7             : !> \date Dec 2019
       8             : !> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
       9             : !! FORCES is released under the LGPLv3+ license \license_note
      10             : MODULE mo_corr
      11             : 
      12             :   USE mo_kind, ONLY : i4, sp, dp
      13             : 
      14             :   Implicit NONE
      15             : 
      16             :   PUBLIC :: autocorr     ! Autocorrelation coefficient at lag k = autocoeffk(k)/autocoeffk(0)
      17             : 
      18             :   ! ------------------------------------------------------------------
      19             : 
      20             :   !>        \brief Autocorrelation function with lag k.
      21             : 
      22             :   !>        \details Element at lag k of autocorrelation function
      23             :   !!             \f[ ACF(x,k) = \frac{s_{x,k}}{s_{x,0}} \f]
      24             :   !!         where \f$ s_{x,k} \f$ is the autocorrelation coefficient
      25             :   !!             \f[ s_{x,k} = \langle (x_i-\bar{x})(x_{i+k}-\bar{x})\rangle \f]
      26             :   !!
      27             :   !!         If an optional mask is given, the calculations are only over those locations that correspond
      28             :   !!         to true values in the mask.\n
      29             :   !!         \f$ x \f$ can be single or double precision. The result will have the same numerical precision.
      30             :   !!
      31             :   !!         \b Example
      32             :   !!
      33             :   !!         Autocorrelation of 0 time steps
      34             :   !!         \code{.f90}
      35             :   !!         ak = autocorr(x, 0, mask=mask)
      36             :   !!         ---> ak = 1
      37             :   !!         \endcode
      38             : 
      39             :   !>        \param[in]  "real(sp/dp) :: x(:)"                 Time series.
      40             :   !>        \param[in]  "integer(i4) :: k[(:)]"               Lag for autocorrelation.
      41             :   !>        \param[in]  "optional, logical     :: mask(:)"    1D-array of logical values with `size(vec)`.
      42             :   !!                                                          If present, only those locations in vec corresponding
      43             :   !!                                                          to the true values in mask are used.
      44             :   !>        \retval    "real(sp/dp) :: ak[(:)]"               Coefficient of autocorrelation function at lag k.
      45             : 
      46             :   !>        \author Matthias Cuntz
      47             :   !>        \date Nov 2011
      48             : 
      49             :   !>        \author Stephan Thober
      50             :   !>        \date Nov 2012
      51             :   !!          - added 1d version
      52             : 
      53             :   !>        \author Sebastion Mueller
      54             :   !>        \date Dec 2019
      55             :   !!          - rewritten
      56             : 
      57             :   INTERFACE autocorr
      58             :     MODULE PROCEDURE autocorr_sp, autocorr_dp, autocorr_1d_sp, autocorr_1d_dp
      59             :   END INTERFACE autocorr
      60             : 
      61             :   ! ------------------------------------------------------------------
      62             : 
      63             : CONTAINS
      64             : 
      65             :   ! ------------------------------------------------------------------
      66             : 
      67          10 :   FUNCTION autocorr_dp(x, k, mask) result(acf)
      68             : 
      69             :     USE mo_moment, ONLY: moment
      70             : 
      71             :     IMPLICIT NONE
      72             : 
      73             :     REAL(dp), DIMENSION(:), INTENT(IN) :: x
      74             :     INTEGER(i4), INTENT(IN) :: k
      75             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
      76             :     REAL(dp) :: acf
      77             : 
      78             :     INTEGER(i4) :: kk  ! absolute value of lag k
      79             :     INTEGER(i4) :: nn  ! number of true values in mask
      80           5 :     REAL(dp) :: n   ! real of nn
      81           5 :     REAL(dp) :: mean, var  ! moments
      82        7505 :     REAL(dp), DIMENSION(size(x)) :: x_shift
      83           5 :     LOGICAL, DIMENSION(size(x)) :: maske
      84             : 
      85        7505 :     maske(:) = .true.
      86           5 :     if (present(mask)) then
      87           3 :       if (size(mask) /= size(x)) stop 'Error autocorr_dp: size(mask) /= size(x)'
      88        4506 :       maske = mask
      89             :     end if
      90             : 
      91             :     ! calculate mean and population variance of x
      92           5 :     call moment(x, mean=mean, variance=var, mask=maske, sample=.false.)
      93             :     ! shift x to 0 mean
      94        7505 :     x_shift = x - mean
      95             :     ! use absolute value of k
      96           5 :     kk = abs(k)
      97           5 :     nn = size(x)
      98        7495 :     n = real(count(maske(1 : nn - kk).and.maske(1 + kk : nn)), dp)
      99             :     ! calculate the auto-correlation function
     100        7495 :     acf = sum(x_shift(1 : nn - kk) * x_shift(1 + kk : nn), mask = (maske(1 : nn - kk) .and. maske(1 + kk : nn))) / n / var
     101             : 
     102           5 :   END FUNCTION autocorr_dp
     103             : 
     104          10 :   FUNCTION autocorr_sp(x, k, mask) result(acf)
     105             : 
     106           5 :     USE mo_moment, ONLY: moment
     107             : 
     108             :     IMPLICIT NONE
     109             : 
     110             :     REAL(sp), DIMENSION(:), INTENT(IN) :: x
     111             :     INTEGER(i4), INTENT(IN) :: k
     112             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     113             :     REAL(sp) :: acf
     114             : 
     115             :     INTEGER(i4) :: kk  ! absolute value of lag k
     116             :     INTEGER(i4) :: nn  ! number of true values in mask
     117           5 :     REAL(sp) :: n   ! real of nn
     118           5 :     REAL(sp) :: mean, var  ! moments
     119        7505 :     REAL(sp), DIMENSION(size(x)) :: x_shift
     120           5 :     LOGICAL, DIMENSION(size(x)) :: maske
     121             : 
     122        7505 :     maske(:) = .true.
     123           5 :     if (present(mask)) then
     124           3 :       if (size(mask) /= size(x)) stop 'Error autocorr_sp: size(mask) /= size(x)'
     125        4506 :       maske = mask
     126             :     end if
     127             : 
     128             :     ! calculate mean and population variance of x
     129           5 :     call moment(x, mean=mean, variance=var, mask=maske, sample=.false.)
     130             :     ! shift x to 0 mean
     131        7505 :     x_shift = x - mean
     132             :     ! use absolute value of k
     133           5 :     kk = abs(k)
     134           5 :     nn = size(x)
     135        7495 :     n = real(count(maske(1 : nn - kk).and.maske(1 + kk : nn)), sp)
     136             :     ! calculate the auto-correlation function
     137        7495 :     acf = sum(x_shift(1 : nn - kk) * x_shift(1 + kk : nn), mask = (maske(1 : nn - kk) .and. maske(1 + kk : nn))) / n / var
     138             : 
     139           5 :   END FUNCTION autocorr_sp
     140             : 
     141          10 :   FUNCTION autocorr_1d_dp(x, k, mask) result(acf)
     142             : 
     143             :     IMPLICIT NONE
     144             : 
     145             :     REAL(dp), DIMENSION(:), INTENT(IN) :: x
     146             :     INTEGER(i4), DIMENSION(:), INTENT(IN) :: k
     147             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     148             :     INTEGER(i4) :: i
     149             :     REAL(dp), DIMENSION(size(k)) :: acf
     150             : 
     151           2 :     if (present(mask)) then
     152           3 :       do i = 1, size(k)
     153           3 :         acf(i) = autocorr(x, k(i), mask)
     154             :       end do
     155             :     else
     156           3 :       do i = 1, size(k)
     157           3 :         acf(i) = autocorr(x, k(i))
     158             :       end do
     159             :     end if
     160             : 
     161             : 
     162           7 :   END FUNCTION autocorr_1d_dp
     163             : 
     164           8 :   FUNCTION autocorr_1d_sp(x, k, mask) result(acf)
     165             : 
     166             :     IMPLICIT NONE
     167             : 
     168             :     REAL(sp), DIMENSION(:), INTENT(IN) :: x
     169             :     INTEGER(i4), DIMENSION(:), INTENT(IN) :: k
     170             :     LOGICAL, DIMENSION(:), OPTIONAL, INTENT(IN) :: mask
     171             :     INTEGER(i4) :: i
     172             :     REAL(sp), DIMENSION(size(k)) :: acf
     173             : 
     174           2 :     if (present(mask)) then
     175           3 :       do i = 1, size(k)
     176           3 :         acf(i) = autocorr(x, k(i), mask)
     177             :       end do
     178             :     else
     179           3 :       do i = 1, size(k)
     180           3 :         acf(i) = autocorr(x, k(i))
     181             :       end do
     182             :     end if
     183             : 
     184           4 :   END FUNCTION autocorr_1d_sp
     185             : 
     186             : END MODULE mo_corr

Generated by: LCOV version 1.16