From 446ef213fc9a3781f8cb70af609705884ff2d0b9 Mon Sep 17 00:00:00 2001
From: Philippe WAUTELET <philippe.wautelet@aero.obs-mip.fr>
Date: Tue, 22 Mar 2022 13:52:16 +0100
Subject: [PATCH] Philippe 22/03/2022: LES budgets: LES averaging periods are
 more reliable (compute with integers instead of reals)

(cherry picked from commit 1ca4e62cf481d02e29ecf61f39173e05d5a70cec)
---
 src/MNH/ini_lesn.f90         | 41 ++++++++++++++++++++++++++
 src/MNH/modd_lesn.f90        | 15 +++++++++-
 src/MNH/mode_les_diachro.f90 | 57 ++++++++++--------------------------
 3 files changed, 70 insertions(+), 43 deletions(-)

diff --git a/src/MNH/ini_lesn.f90 b/src/MNH/ini_lesn.f90
index 05a30c423..84f90dba5 100644
--- a/src/MNH/ini_lesn.f90
+++ b/src/MNH/ini_lesn.f90
@@ -40,6 +40,7 @@
 !  P. Wautelet 04/01/2021: bugfix: nles_k was used instead of nspectra_k for a loop index
 !  P. Wautelet 30/03/2021: budgets: LES cartesian subdomain limits are defined in the physical domain
 !  P. Wautelet 09/07/2021: bugfix: altitude levels are on the correct grid position (mass point)
+!  P. Wautelet 22/03/2022: LES averaging periods are more reliable (compute with integers instead of reals)
 ! --------------------------------------------------------------------------
 !
 !*      0. DECLARATIONS
@@ -342,6 +343,46 @@ IF (NLES_TIMES==0) THEN
   RETURN
 END IF
 !
+!*     3.8  Averaging
+!           ---------
+IF (     XLES_TEMP_MEAN_END   == XUNDEF &
+    .OR. XLES_TEMP_MEAN_START == XUNDEF &
+    .OR. XLES_TEMP_MEAN_STEP  == XUNDEF ) THEN
+  !No LES temporal averaging
+  NLES_MEAN_TIMES = 0
+  NLES_MEAN_STEP  = NNEGUNDEF
+  NLES_MEAN_START = NNEGUNDEF
+  NLES_MEAN_END   = NNEGUNDEF
+ELSE
+  !LES temporal averaging is enabled
+  !Ensure that XLES_TEMP_MEAN_END is not after segment end
+  XLES_TEMP_MEAN_END = MIN( XLES_TEMP_MEAN_END, XSEGLEN - DYN_MODEL(1)%XTSTEP )
+
+  NLES_MEAN_START = NINT( XLES_TEMP_MEAN_START / XTSTEP )
+
+  IF ( MODULO( NLES_MEAN_START, NLES_DTCOUNT ) /= 0 ) THEN
+    CMNHMSG(1) = 'XLES_TEMP_MEAN_START is not a multiple of XLES_TEMP_SAMPLING'
+    CMNHMSG(2) = 'LES averaging periods could be wrong'
+    CALL Print_msg( NVERB_WARNING, 'IO', 'INI_LES_n' )
+  END IF
+
+  NLES_MEAN_END = NINT( XLES_TEMP_MEAN_END / XTSTEP )
+
+  NLES_MEAN_STEP = NINT( XLES_TEMP_MEAN_STEP / XTSTEP )
+
+  IF ( NLES_MEAN_STEP < NLES_DTCOUNT ) &
+    CALL Print_msg( NVERB_ERROR, 'IO', 'INI_LES_n', 'XLES_TEMP_MEAN_STEP < XLES_TEMP_SAMPLING not allowed' )
+
+  IF ( MODULO( NLES_MEAN_STEP, NLES_DTCOUNT ) /= 0 ) THEN
+    CMNHMSG(1) = 'XLES_TEMP_MEAN_STEP is not a multiple of XLES_TEMP_SAMPLING'
+    CMNHMSG(2) = 'LES averaging periods could be wrong'
+    CALL Print_msg( NVERB_WARNING, 'IO', 'INI_LES_n' )
+  END IF
+
+  NLES_MEAN_TIMES = ( NLES_MEAN_END - NLES_MEAN_START ) / NLES_MEAN_STEP
+  !Add 1 averaging period if the last one is incomplete (for example: start=0., end=10., step=3.)
+  IF ( MODULO( NLES_MEAN_END - NLES_MEAN_START, NLES_MEAN_STEP ) > 0 ) NLES_MEAN_TIMES = NLES_MEAN_TIMES + 1
+END IF
 !-------------------------------------------------------------------------------
 !
 !*      4.   Number of vertical levels for local diagnostics
diff --git a/src/MNH/modd_lesn.f90 b/src/MNH/modd_lesn.f90
index 28db43c4d..c7b54dd8d 100644
--- a/src/MNH/modd_lesn.f90
+++ b/src/MNH/modd_lesn.f90
@@ -1,4 +1,4 @@
-!MNH_LIC Copyright 1995-2020 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC Copyright 1995-2022 CNRS, Meteo-France and Universite Paul Sabatier
 !MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
 !MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
 !MNH_LIC for details. version 1.
@@ -42,6 +42,7 @@
 !  P. Wautelet 08/02/2019: add missing NULL association for pointers
 !  C. Lac         02/2019: add rain fraction as a LES diagnostic
 !  P. Wautelet 13/09/2019: budget: simplify and modernize date/time management
+!  P. Wautelet 22/03/2022: LES averaging periods are more reliable (compute with integers instead of reals)
 !-------------------------------------------------------------------------------
 !
 !*       0.   DECLARATIONS
@@ -61,6 +62,10 @@ TYPE LES_t
   INTEGER :: NLES_TIMES         ! number of LES computations in time
   INTEGER :: NLES_DTCOUNT       ! number of time steps between two LES comp.
   INTEGER :: NLES_TCOUNT        ! current time counter for LES comp.
+  INTEGER :: NLES_MEAN_TIMES    ! Number of LES averaging periods
+  INTEGER :: NLES_MEAN_STEP     ! number of time steps between two LES average comp.
+  INTEGER :: NLES_MEAN_START    ! First time step number taken into account for LES averaging
+  INTEGER :: NLES_MEAN_END      ! Last  time step number taken into account for LES averaging
   INTEGER :: NSPECTRA_NI        ! number of wave lengths in I direction
   INTEGER :: NSPECTRA_NJ        ! number of wave lengths in J direction
 !
@@ -660,6 +665,10 @@ TYPE(LES_t), DIMENSION(JPMODELMAX), TARGET, SAVE :: LES_MODEL
 INTEGER, POINTER :: NLES_TIMES=>NULL()
 INTEGER, POINTER :: NLES_DTCOUNT=>NULL()
 INTEGER, POINTER :: NLES_TCOUNT=>NULL()
+INTEGER, POINTER :: NLES_MEAN_TIMES => NULL()
+INTEGER, POINTER :: NLES_MEAN_STEP  => NULL()
+INTEGER, POINTER :: NLES_MEAN_START => NULL()
+INTEGER, POINTER :: NLES_MEAN_END   => NULL()
 INTEGER, POINTER :: NSPECTRA_NI=>NULL()
 INTEGER, POINTER :: NSPECTRA_NJ=>NULL()
 type(date_time), dimension(:), pointer :: tles_dates => null()
@@ -1509,6 +1518,10 @@ LES_MODEL(KFROM)%XLES_RADEFF=>XLES_RADEFF
 NLES_TIMES=>LES_MODEL(KTO)%NLES_TIMES
 NLES_DTCOUNT=>LES_MODEL(KTO)%NLES_DTCOUNT
 NLES_TCOUNT=>LES_MODEL(KTO)%NLES_TCOUNT
+NLES_MEAN_TIMES => LES_MODEL(KTO)%NLES_MEAN_TIMES
+NLES_MEAN_STEP  => LES_MODEL(KTO)%NLES_MEAN_STEP
+NLES_MEAN_START => LES_MODEL(KTO)%NLES_MEAN_START
+NLES_MEAN_END   => LES_MODEL(KTO)%NLES_MEAN_END
 NSPECTRA_NI=>LES_MODEL(KTO)%NSPECTRA_NI
 NSPECTRA_NJ=>LES_MODEL(KTO)%NSPECTRA_NJ
 tles_dates=>les_model(kto)%tles_dates
diff --git a/src/MNH/mode_les_diachro.f90 b/src/MNH/mode_les_diachro.f90
index f56b2ce0f..7d8d69872 100644
--- a/src/MNH/mode_les_diachro.f90
+++ b/src/MNH/mode_les_diachro.f90
@@ -1,4 +1,4 @@
-!MNH_LIC Copyright 1994-2021 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC Copyright 1994-2022 CNRS, Meteo-France and Universite Paul Sabatier
 !MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
 !MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
 !MNH_LIC for details. version 1.
@@ -12,6 +12,7 @@
 !  P. Wautelet    10/2020: restructure subroutines to use tfield_metadata_base type
 !  P. Wautelet 03/03/2021: budgets: add tbudiachrometadata type (useful to pass more information to Write_diachro)
 !  P. Wautelet 11/03/2021: budgets: remove ptrajx/y/z optional dummy arguments of Write_diachro
+!  P. Wautelet 22/03/2022: LES averaging periods are more reliable (compute with integers instead of reals)
 !-----------------------------------------------------------------
 !#######################
 MODULE MODE_LES_DIACHRO
@@ -524,8 +525,7 @@ END SUBROUTINE LES_TIME_AVG
 subroutine Les_time_avg_4D( pwork4, tpdates, kresp )
 !########################################################
 
-use modd_les,        only: nles_current_times, xles_temp_mean_start, xles_temp_mean_end, xles_temp_mean_step
-use modd_parameters, only: XUNDEF
+use modd_les_n,      only: nles_dtcount, nles_mean_start, nles_mean_end, nles_mean_step, nles_mean_times, nles_times
 use modd_time,       only: tdtseg
 use modd_type_date,  only: date_time
 
@@ -537,60 +537,33 @@ real,            dimension(:,:,:,:), allocatable, intent(inout) :: pwork4 ! cont
 type(date_time), dimension(:),       allocatable, intent(inout) :: tpdates
 integer,                                          intent(out)   :: kresp  ! return code (0 is ok)
 !------------------------------------------------------------------------------
-integer                               :: jt                   ! time counter
-integer                               :: itime                ! nb of avg. points
-integer                               :: iavg                 ! nb of avg. periods
 integer                               :: javg                 ! loop counter on avg. periods
 integer                               :: jk                   ! vertical loop counter
 integer                               :: jp                   ! process loop counter
 integer                               :: jsv                  ! scalar loop counter
-integer                               :: jx                   ! first  spatial or spectral coordinate loop counter
-integer                               :: jy                   ! second spatial or spectral coordinate loop counter
 integer                               :: jtb, jte
-real                                  :: zles_temp_mean_start ! initial and end times
-real                                  :: zles_temp_mean_end   ! of one avergaing preiod
 real, dimension(:,:,:,:), allocatable :: zwork4               ! contains averaged physical field
 !------------------------------------------------------------------------------
 
-if (     xles_temp_mean_end   == XUNDEF &
-    .or. xles_temp_mean_start == XUNDEF &
-    .or. xles_temp_mean_step  == XUNDEF ) then
-  kresp = -1
-  return
-end if
-
-iavg = Int( xles_temp_mean_end - 1.e-10 - xles_temp_mean_start ) / xles_temp_mean_step + 1
-if ( iavg <= 0 ) then
+if ( nles_mean_times == 0 ) then
   kresp = -1
   return
 end if
 
 Deallocate( tpdates )
 
-Allocate( tpdates(iavg) )
-Allocate( zwork4(Size( pwork4, 1 ), iavg, Size( pwork4, 3 ), Size( pwork4, 4 )) )
+Allocate( tpdates(nles_mean_times) )
+Allocate( zwork4(Size( pwork4, 1 ), nles_mean_times, Size( pwork4, 3 ), Size( pwork4, 4 )) )
 
 zwork4(:, :, :, :) = 0.
 
-do javg = 1, iavg
-  zles_temp_mean_start = xles_temp_mean_start + (javg - 1) * xles_temp_mean_step
-  zles_temp_mean_end   = Min( xles_temp_mean_end, zles_temp_mean_start + xles_temp_mean_step )
-
-  jtb = -1
-  jte = -2
-  do jt = 1, nles_current_times
-    if ( xles_times(jt) >= zles_temp_mean_start ) then
-      jtb = jt
-      exit
-    end if
-  end do
-  do jt = jtb, nles_current_times
-    if ( xles_times(jt) <= zles_temp_mean_end ) then
-      jte = jt
-    else
-      exit
-    end if
-  end do
+do javg = 1, nles_mean_times
+  jtb = ( nles_mean_start + ( javg - 1 ) * nles_mean_step ) / nles_dtcount
+  jte = MIN( jtb + nles_mean_step / nles_dtcount, nles_mean_end / nles_dtcount, nles_times )
+  ! jtb could be 0 if nles_mean_start is smaller than the first LES measurement
+  ! For example, it occurs if xles_temp_mean_start is smaller than xles_temp_sampling (if xles_temp_mean_start=0.)
+  ! Do this correction only after computation of jte
+  if ( jtb < 1 ) jtb = 1
 
   do jp = 1, Size( pwork4, 4 )
     do jsv = 1, Size( pwork4, 3 )
@@ -603,12 +576,12 @@ do javg = 1, iavg
   tpdates(javg)%nyear  = tdtseg%nyear
   tpdates(javg)%nmonth = tdtseg%nmonth
   tpdates(javg)%nday   = tdtseg%nday
-  tpdates(javg)%xtime  = tdtseg%xtime + ( zles_temp_mean_start + zles_temp_mean_end ) / 2.
+  tpdates(javg)%xtime  = tdtseg%xtime + ( xles_times(jtb) + xles_times(jte) ) / 2.
   call Datetime_correctdate( tpdates(javg) )
 end do
 
 Deallocate( pwork4 )
-Allocate( pwork4(Size( zwork4, 1 ), iavg, Size( zwork4, 3 ), Size( zwork4, 4 )) )
+Allocate( pwork4(Size( zwork4, 1 ), nles_mean_times, Size( zwork4, 3 ), Size( zwork4, 4 )) )
 
 pwork4 = zwork4
 
-- 
GitLab