LCOV - code coverage report
Current view: top level - src - mo_edk_setvario.f90 (source / functions) Hit Total Coverage
Test: edk coverage Lines: 164 187 87.7 %
Date: 2024-03-11 14:23:05 Functions: 6 6 100.0 %

          Line data    Source code
       1             : !> \file    mo_edk_setvario.f90
       2             : !> \brief   \copybrief mo_edk_setvario
       3             : !> \details \copydetails mo_edk_setvario
       4             : 
       5             : !> \brief   VARIOGRAM: Seting or estimating and fitting
       6             : !> \details PURPOSE:
       7             : !!          1) Set variagram from DB for a block, or
       8             : !!          2.1) Estimate an empirical semi variogram for daily met. values
       9             : !!          2.2) Fitting a teoretical variogram
      10             : !!          2.3) Set variogram for a block
      11             : !> \author  Luis Samaniego
      12             : !> \date    19.02.2004
      13             : !!          - main structure
      14             : !> \date    12.04.2006
      15             : !> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
      16             : !! EDK is released under the LGPLv3+ license \license_note
      17             : module mo_edk_setvario
      18             :   use mo_kind, only: i4, dp
      19             :   implicit none
      20             : 
      21             :   private
      22             : 
      23             :   public :: setVario
      24             :   public :: dMatrix
      25             :   public :: tVar
      26             : 
      27             : contains
      28             : 
      29             :   !> \brief   find optimal variogram parameters, if wanted
      30           2 :   subroutine setVario(param)
      31             :     use runControl
      32             :     use VarFit
      33             :     use mainVar
      34             :     use mo_edk_empvar, only: EmpVar
      35             :     implicit none
      36             :     real(dp), intent(out) :: param(3) !< parameters (nugget, sill, range)
      37             :     integer(i4) :: jd, y, y0
      38             :     !
      39             :     ! Estimation
      40           2 :     if (flagVario) then
      41             :       ! Initialize
      42           1 :       nobs=0 ; m0=0.0_dp ;  v0=0.0_dp
      43           1 :       y0 = 0
      44             :       !
      45         366 :       do jd= jStart, jEnd
      46         365 :           y = floor(float(jd-jStart)/365.)
      47         365 :           if (y > y0 ) then
      48           0 :             y0 = y
      49           0 :             print*, 'VarFit. Processing ', yStart+y0-1 , '...'
      50             :           end if
      51             :           ! update Variogram bins daily
      52         366 :           call EmpVar(jd, .true.)
      53             :       end do
      54             :       !
      55             :       ! variance
      56           1 :       v0 = v0 / real(nobs, dp)
      57             :       ! optimize parameters
      58             :       ! open(UNIT = 6,FILE = 'Report_OPT.sol', STATUS='REPLACE')
      59             : 
      60           1 :       print *, "ST: replace old GRG2 opti with something better"
      61           1 :       call opti(param)
      62             :     else
      63           1 :       print *, "   ... no variogram estimation, parameters given."
      64             :     end if
      65           2 :   end subroutine setVario
      66             : 
      67             :   !> \brief   Function to calulate variogram at given distance
      68             :   !> \return  variogram value
      69      651348 :   real(dp) function tVar(h,c0,c,a)
      70           2 :     use VarFit,  only      : vType
      71             :     use mo_utils, only: eq
      72             :     real(dp), intent(in)  :: h                !< distance
      73             :     real(dp), intent(in)  :: c0               !< nugget = beta(1) = XU(1)
      74             :     real(dp), intent(in)  :: c                !< sill   = beta(2) = XU(2)
      75             :     real(dp), intent(in)  :: a                !< range  = beta(3) = XU(3)
      76      651348 :     real(dp)              :: r
      77             :     !
      78      651348 :     if ( a > 0.0_dp ) then
      79      651348 :       r = h/a
      80             :     else
      81             :       r = 0.0_dp
      82             :     end if
      83      328500 :     select case (vType)
      84             :       !
      85             :       case (1)
      86             :         ! composed:   nugget + spherical + sill
      87      328500 :         if ( eq(h, 0.0_dp) ) then
      88       33984 :           tVar = c0 ! 0.0_dp
      89      294516 :         elseif ( h < a ) then
      90      240642 :           tVar = c0 + c * (1.5_dp * r - 0.5_dp * r**3)
      91             :         else
      92       53874 :           tVar = c0 + c
      93             :         end if
      94             :         !
      95             :       case (2)
      96             :         ! composed:   nugget + exponential + sill
      97      651348 :         if ( eq(h, 0.0_dp) ) then
      98       33984 :           tVar = c0 ! 0.0_dp
      99      288864 :         elseif ( a > 0 ) then
     100      288864 :           tVar = c0 + c * (1.0_dp - exp(-r))
     101             :         else
     102           0 :           tVar = c0 + c
     103             :         end if
     104             :       end select
     105             :     !
     106      651348 :   end function tVar
     107             : 
     108             :   !> \brief   DMATRIX:: To calculate distance between pairs.
     109           2 :   subroutine dMatrix
     110      651348 :     use mainVar
     111             :     use kriging
     112             :     use runControl
     113             : 
     114             :     implicit none
     115             :     integer(i4)                     :: i, j, k
     116             :     integer(i4)                     :: r, c, ii, jj
     117             :     integer(i4)                     :: delta, nTcell
     118           2 :     real(dp)                        :: xc, yc
     119           2 :     integer(i4), allocatable        :: list(:)
     120             :     !
     121             :     ! Initialize variables
     122           0 :     if ( allocated(cell)) deallocate (cell)
     123             :     !
     124           2 :     print*, nCell, "cells", nSta, "stations"
     125           2 :     edk_dist%ncell = nCell
     126           6 :     allocate(edk_dist%cell_pos(nCell, 2))
     127         126 :     allocate ( cell(nCell)     )
     128           6 :     allocate ( list(nSta)      )
     129             : 
     130          38 :     do i=1,nSta-1
     131             :       ! distance matrix between stations:            checked OK
     132         380 :       do j=i+1, nSta
     133         342 :         if (edk_dist%getSS(i,j) == 0.0_dp) then
     134             :           ! check if stations are closer than 5 meter
     135           0 :           print* , '--------------------------------------------------------------------------'
     136           0 :           print* , '!!! Warning: '
     137           0 :           print* , '!!! Stations: ', MetSta(i)%Id, ' and ', MetSta(j)%Id
     138           0 :           print* , '!!! have the same coordinates or are repeated. Check LUT. '
     139           0 :           print* , '!!! Rounded artefacts can be generated when stations have same coordinates'
     140           0 :           print* , '!!! and data at the time.'
     141           0 :           print* , '--------------------------------------------------------------------------'
     142             :           !stop
     143             :         end if
     144         378 :         if (edk_dist%getSS(i,j) > 0.0_dp .and. edk_dist%getSS(i,j) < 5.0_dp) then
     145           0 :           print* , '--------------------------------------------------------------------------'
     146           0 :           print* , '!!! Warning: '
     147           0 :           print* , '!!! Stations: ', MetSta(i)%Id, ' and ', MetSta(j)%Id
     148           0 :           print* , '!!!  are closer than 5 meter distance. '
     149           0 :           print* , '--------------------------------------------------------------------------'
     150             :         end if
     151             :       end do
     152             :     end do
     153             : 
     154             :     ! cell coordinates and elevation : checked OK
     155             :     ! ***************************************
     156             :     ! cell numbering convention (1DIM first)
     157             :     ! c->1     2                  ncol
     158             :     ! r
     159             :     ! ---+-----+------...+...-----+
     160             :     !    1     nr+1
     161             :     !    2
     162             :     !    ...             k
     163             :     !    nr    2nr                nCell
     164             :     ! ***************************************
     165             :     !    ii         column in finer grid
     166             :     !    yy         row    in finer grid
     167             :     !    (xc,yc)    coordinates of meteogrid
     168             :     ! ***************************************
     169             :     !
     170           2 :     r=1
     171           2 :     c=0
     172           2 :     if (DEMNcFlag /= 1) xc = gridMeteo%xllcorner + dble(gridMeteo%cellsize) * 0.5_dp
     173           2 :     delta = cellFactor / 2
     174           2 :     jj = delta
     175         122 :     do k=1,nCell
     176             :       ! advancing the counters
     177         120 :       if (r == 1) then
     178          12 :           c = c + 1
     179          12 :           if (c > 1) then
     180          10 :             jj = jj + cellFactor
     181             :           end if
     182             :           ii = delta
     183             :       else
     184         108 :           ii = ii + cellFactor
     185             :       end if
     186             : 
     187         120 :       if (DEMNcFlag == 1) then
     188           0 :           cell(k)%x = gridMeteo%easting(r,c)
     189           0 :           cell(k)%y = gridMeteo%northing(r,c)
     190             :       else
     191         120 :           if (r == 1) then
     192          12 :             if (c > 1) then
     193          10 :                 xc = xc + dble(gridMeteo%cellsize)
     194             :             end if
     195          12 :             yc = gridMeteo%yllcorner + dble(gridMeteo%cellsize) * (dble(gridMeteo%nrows) - 0.5_dp)
     196             :           else
     197         108 :             yc = yc - dble(gridMeteo%cellsize)
     198             :           end if
     199         120 :           cell(k)%x = xc
     200         120 :           cell(k)%y = yc
     201             :         end if
     202         360 :         edk_dist%cell_pos(k,:) = [cell(k)%x, cell(k)%y]
     203             : 
     204             :       ! average of only four DEM cells around centre cell (from lower grid scale upto higher grid cell)
     205             :       !cell(k)%h = 0.25_dp*(G(ii,jj)%h + G(ii,jj+1)%h + G(ii+1,jj)%h + G(ii+1,jj+1)%h)
     206             :       !
     207             :       ! average of all DEM cells (from lower grid scale upto higher grid cell)
     208         120 :       if (cellFactor == 1) then
     209           0 :           cell(k)%h = G(ii+1,jj+1)%h
     210             :       else
     211      196920 :           nTcell =  count(G( (ii-delta+1):(ii+delta) , (jj-delta+1):(jj+delta) )%h  > grid%nodata_value )
     212         120 :           if (nTcell == 0) then
     213          48 :             cell(k)%h = gridMeteo%nodata_value
     214             :           else
     215           0 :             cell(k)%h  = sum(G( (ii-delta+1):(ii+delta) , (jj-delta+1):(jj+delta) )%h, &
     216      118152 :                   G( (ii-delta+1):(ii+delta) , (jj-delta+1):(jj+delta) )%h /= gridMeteo%nodata_value ) / dble(nTcell)
     217             :           end if
     218             :       end if
     219             : 
     220             :       ! advance the counters
     221         120 :       r=r+1
     222         122 :       if (r > gridMeteo%nrows) r = 1
     223             :     end do
     224             : 
     225           2 :     print*, "   ... find neighborhoods"
     226             : 
     227             :     ! find the closest stations to cell i (any order): checked  OK
     228         122 :     do i=1,nCell
     229         120 :       if ( modulo(i,100000) == 0 ) print*, "      ... cells ready", i, "of", nCell
     230        2400 :       list = -9
     231        2400 :       do j=1,nSta
     232        2400 :         if (edk_dist%getCS(i,j) <= maxDist) list(j) = j
     233             :       end do
     234        2400 :       cell(i)%nNS = count(list > -9)
     235         360 :       allocate ( cell(i)%listNS( cell(i)%nNS ) )
     236        4802 :       cell(i)%listNS = pack(list, MASK = list >-9)
     237             :     end do
     238             :     !
     239           2 :     deallocate (list)
     240             : 
     241           2 :   end subroutine dMatrix
     242             : 
     243             :   !> \brief   Optimization routine for variograms.
     244             :   !> \details Initialization of the Nonlinear Optimization Subroutine GRG2
     245             :   !!          The function to be optimized is suplied in subroutine GCOMP
     246             :   !> \author  Luis Samaniego
     247             :   !> \date    28.05.1999
     248           1 :   subroutine OPTI(pmin)
     249           2 :     use VarFit
     250             :     use mo_nelmin, only: nelminrange
     251             : 
     252             :     ! parameters for Nelder-Mead algorithm
     253             :     real(dp), intent(out) :: pmin(3) !< optimized parameter set
     254           4 :     real(dp) :: pstart(3) ! Starting point for the iteration.
     255           9 :     real(dp) :: prange(3, 2) ! Range of parameters (upper and lower bound).
     256           1 :     real(dp) :: varmin ! the terminating limit for the variance of the function values. varmin>0 is required
     257           4 :     real(dp) :: step(3) ! determines the size and shape of the initial simplex. The relative magnitudes of its elements should reflect the units of the variables. size(step)=size(start)
     258             :     integer(i4) :: konvge ! the convergence check is carried out every konvge iterations
     259             :     integer(i4) :: maxeval ! the maximum number of function evaluations. default: 1000
     260           1 :     real(dp) :: funcmin
     261             :     integer(i4) :: neval ! the number of function evaluations used.
     262             :     integer(i4) :: numrestart ! the number of restarts.
     263             :     integer(i4) :: ierror ! error indicator.
     264             :                           ! 0: no errors detected.
     265             :                           ! 1: varmin or konvge have an illegal value.
     266             :                           ! 2: iteration terminated because maxeval was exceeded without convergence.
     267           1 :     real(dp), allocatable :: history(:)
     268             : 
     269             : 
     270             :     ! ! inputs for GRG2
     271             :     ! IMPLICIT  DOUBLE PRECISION(A-H,O-Z), INTEGER(I,J,L,M,N)
     272             :     ! INTEGER*4 NCORE,NNVARS,NFUN,MAXBAS,MAXHES,LASTZ
     273             :     ! INTEGER*4 M,N,MP1,NPMP1,NBMAX,NNBMAX,NPNBMX,MPNBMX,NRTOT
     274             :     ! LOGICAL   MAXIM,INPRNT,OTPRNT
     275             :     ! DIMENSION BLVAR(100),BUVAR(100),BLCON(10),BUCON(10)
     276             :     ! DIMENSION RAMCON(10),RAMVAR(10),INBIND(10),Z(5000)
     277             :     ! DIMENSION NONBAS(10),REDGR(10),DEFAUL(20),TITLE(19)
     278             :     ! DIMENSION XX(100),FCNS(10),RMULTS(10)
     279             :     ! DATA      BIG/1.D31/
     280             : 
     281             :     ! Initialization of Nelder-Mead
     282           1 :     pstart = (/0.0, 1., 0.5/) ! Starting point for the iteration.
     283           4 :     prange(:, 1) = (/0., 0., 0./) ! Range of parameters (lower bound).
     284           4 :     prange(:, 2) = (/0.3, 5., 2./) ! Range of parameters (upper bound).
     285           1 :     varmin = 0.001 ! the terminating limit for the variance of the function values. varmin>0 is required
     286           1 :     step = (/0.15, 2.5, 1./) ! determines the size and shape of the initial simplex. The relative magnitudes of its elements should reflect the units of the variables. size(step)=size(start)
     287           1 :     konvge = 100 ! the convergence check is carried out every konvge iterations
     288           1 :     maxeval = 2000 ! the maximum number of function evaluations. default: 1000
     289             : 
     290             :     ! Call Nelder-Mead optimizer to reduce GCOMP
     291             :     ! pmin = nelmin(obj_func, pstart, varmin, step, konvge, maxeval, &
     292             :     !               funcmin, neval, numrestart, ierror, history)
     293             :     pmin = nelminrange(obj_func, pstart, prange, varmin, step, konvge, maxeval, &
     294           1 :                       funcmin, neval, numrestart, ierror)
     295             : 
     296             :     ! scale up distance h
     297         151 :     where (gamma(:,1) > 0._dp) gamma(:,1) = gamma(:,1) * gmax(1)
     298             : 
     299             :     ! scale back parameters (only for range a)
     300           1 :     pmin(3)=pmin(3)*gmax(1)
     301           5 :     beta = pmin
     302             : 
     303           1 :     print *, '=============================='
     304           1 :     print *, ' Results of Nelder-Mead optimization '
     305           1 :     print *, neval, ' of ', maxeval
     306           1 :     print *, "funcmin: ", funcmin
     307           1 :     print *, "p_obj:   ", pmin
     308           1 :     print *, 'error: ', ierror
     309           1 :     print *, 'varmin: ', varmin
     310             :     if (allocated(history)) print *, 'history: ', history(1), history(size(history))
     311           1 :     print *, 'gmax: ', gmax(1)
     312             : 
     313             : 
     314             :     ! estimate statistics
     315           1 :     call stats
     316             :     !
     317             :     ! scale up distance h
     318         151 :     where (gamma(:,1) > 0._dp) gamma(:,1) = gamma(:,1) * gmax(1)
     319             : 
     320           1 :   end subroutine OPTI
     321             : 
     322             :   !> \brief   Function to be minimised for the nelder mead algorithm
     323             :   !> \return  Target function value for given parameter set.
     324         193 :   function obj_func(p)
     325           1 :     use varfit, only      : nbins, gamma, nh
     326             :     implicit none
     327             :     real(dp), dimension(:), intent(in) :: p
     328             :     real(dp) :: obj_func
     329         193 :     real(dp) :: gcal
     330             :     integer(i4) :: k
     331             :     !
     332         193 :     obj_func = 0.0_dp
     333             :     !
     334       29143 :     do k=1,nbins
     335       29143 :       if (gamma(k,1) > 0.0_dp) then
     336             :         ! gcal = tvar (gamma(k,1), xu(1), xu(2), xu(3))
     337        5597 :         gcal = tvar(gamma(k,1), p(1), p(2), p(3))
     338             :         !
     339             :         ! estimator l1 weighted
     340        5597 :         if (gamma(k,1) <= 1.0_dp ) obj_func = obj_func + dabs(gamma(k,2) - gcal) * dble(Nh(k))
     341             :       end if
     342             :     end do
     343         193 :   end function obj_func
     344             : 
     345             :   !> \brief   statistics
     346           1 :   subroutine stats
     347         193 :     use varFit, only                     : E, beta, gamma
     348             :     implicit none
     349             :     integer(i4), parameter               :: incx = 1
     350             :     integer(i4)                          :: k
     351             :     integer(i4)                          :: ne
     352           1 :     real(dp)                             :: SSE
     353           1 :     real(dp)                             :: zObsMean, zCalMean
     354           1 :     real(dp)                             :: zObsVar,  zCalVar, sumP, NSE_denom
     355           1 :     real(dp), dimension(:), allocatable  :: error, denom
     356           1 :     real(dp), dimension(:), allocatable  :: zCal, zObs
     357             :     real(dp), parameter                  :: small = -9.999d3
     358             : 
     359             :     !
     360             :     !Initialize
     361         151 :     ne = count(gamma(:,1) > 0.0_dp)
     362           6 :     allocate (error(ne), denom(ne), zCal(ne), zObs(ne))
     363          31 :     zObs = gamma(1:ne,2)
     364          30 :     zCal = 0.0_dp
     365          30 :     do k=1,ne
     366          30 :       if (gamma(k,1) > 0._dp)  zCal(k) = tvar(gamma(k,1),beta(1),beta(2),beta(3))
     367             :     end do
     368             :     !
     369          31 :     error = zObs-zCal
     370           1 :     if ( ne > 1 ) then
     371          30 :       zObsMean  = sum(zObs)/real(ne, dp)
     372          30 :       zCalMean  = sum(zCal)/real(ne, dp)
     373          30 :       sumP      = dot_product(zObs,zCal)
     374          30 :       zObsVar   = dot_product(zObs,zObs) - real(ne, dp) * zObsMean * zObsMean
     375          30 :       zCalVar   = dot_product(zCal,zCal) - real(ne, dp) * zCalMean * zCalMean
     376          30 :       SSE       = dot_product(error,error)
     377          31 :       denom     = zObs - zObsMean
     378          30 :       NSE_denom = dot_product(denom,denom)
     379             :     else
     380             :     zObsMean = small
     381             :     zCalMean = small
     382             :     zObsVar  = small
     383             :     zCalVar  = small
     384             :     end if
     385             :     !   ****************
     386             :     !   Quality measures
     387             :     !   ****************
     388           1 :     if ( ne > 0 ) then
     389             :       !
     390             :       ! BIAS
     391           1 :       E(1) = zCalMean - zObsMean
     392           1 :       print *, 'BIAS: ', E(1)
     393             :       !
     394             :       ! MSE
     395           1 :       E(2) = SSE/real(ne, dp)
     396           1 :       print *, 'MSE:  ', E(2)
     397             :       !
     398             :       ! RMSE
     399           1 :       if ( E(2) > 0.0_dp ) then
     400           1 :         E(3) = dsqrt(E(2))
     401             :       else
     402           0 :         E(3) = small
     403             :       end if
     404           1 :       print *, 'RMSE: ', E(3)
     405             :       !
     406             :       ! RRMSE
     407           1 :       if ( E(3) > 0.0_dp ) then
     408           1 :         E(4)=E(3)/zObsMean
     409             :       else
     410           0 :         E(4)= small
     411             :       end if
     412           1 :       print *, 'PRMSE:', E(4)
     413             :       !
     414             :       ! MAE
     415          30 :       E(5)= sum(abs(error))
     416           1 :       E(5)= E(5)/real(ne, dp)
     417           1 :       print *, 'MAE:  ', E(5)
     418             :       !
     419             :       ! RMAE
     420           1 :       E(6)=E(5)/zObsMean
     421           1 :       print *, 'RMAE: ', E(6)
     422             :       !
     423             :       ! r
     424           1 :       E(7)= (sumP-real(ne, dp) * zCalMean * zObsMean) / dsqrt(zCalVar * zObsVar)
     425           1 :       print *, 'r:    ', E(7)
     426             :       !
     427             :       ! NSE
     428           1 :       E(8)= 1.0_dp - (SSE/NSE_denom)
     429           1 :       print *, 'NSE:  ', E(8)
     430             :     else
     431           0 :       E = small
     432             :     end if
     433           1 :     deallocate (error, denom, zCal, zObs)
     434           1 :   end subroutine stats
     435             : 
     436             : end module mo_edk_setvario

Generated by: LCOV version 1.16