1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// *****************************************************************************
/*!
  \file      src/Base/Timer.cpp
  \copyright 2012-2015 J. Bakosi,
             2016-2018 Los Alamos National Security, LLC.,
             2019-2021 Triad National Security, LLC.,
             2022-2025 J. Bakosi
             All rights reserved. See the LICENSE file for details.
  \brief     Timer definition
  \details   Timer definition. Timer is a simple class to do timing various
    parts of the code in a portable way. The functionality is intended to be
    very minimal and simple, but still convenient to use, with as little state
    as possible. For an example client code, see Main.
*/
// *****************************************************************************

#include <algorithm><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <ratio><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <cmath><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include "Timer.hpp"
#include "Exception.hpp"

using tk::Timer;

tk::Timer::Watch
Timer::hms() const
// *****************************************************************************
//  Return time elapsed between start and stop for timer as hours, minutes, and
//  seconds.
//! \return Time elapsed between start and stop as hours, minutes, and seconds,
//!   as a Watch struct.
// *****************************************************************************
{
  using std::chrono::duration_cast;

  // Compute time difference between start and now in seconds
  Dsec elapsed = clock::now() - m_start;

  // Put elapsed time in watch as hours:minutes:seconds
  Watch watch( duration_cast< hours >( elapsed ),
               duration_cast< minutes >( elapsed ) % hours(1),
               duration_cast< seconds >( elapsed ) % minutes(1) );
  return watch;
}

void
Timer::eta( tk::real term, tk::real time, uint64_t nstep, uint64_t it,
            tk::real res0, tk::real res, tk::real rest,
            Watch& elapsedWatch, Watch& estimatedWatch )
// *****************************************************************************
//  Estimate time for accomplishment
//! \param[in] term Time at which to terminate time stepping
//! \param[in] time Current time
//! \param[in] nstep Max number of time steps to take
//! \param[in] it Current iteration count
//! \param[in] res0 Residual at previous call (during convergence to steady
//!   state)
//! \param[in] res Current residual (during convergence to steady state)
//! \param[in] rest Target residual (during convergence to steady state)
//! \param[out] elapsedWatch Elapsed time in h:m:s
//! \param[out] estimatedWatch Estimated time for accomplishmet in h:m:s
// *****************************************************************************
{
  using std::chrono::duration_cast;

  Dsec elapsed, estimated{};

  Assert( it > 0, "it == 0" );

  tk::real eps = std::numeric_limits< real >::epsilon();

  // Compute time difference between start and now in seconds
  elapsed = clock::now() - m_start;

  if (rest > eps) {

    if (res0 > eps && res > eps) {
      // Estimate time until convergence to steady state (assume log-lin fn)
      using std::log;
      auto d = log(res0/res);
      Dsec recent_elapsed = clock::now() - m_prev;
      Dsec est_res = std::abs(d) > eps ?
                     recent_elapsed * log(res/rest) / d :
                     Dsec(0);

      // Ignore negative estimates (temporarily non-decreasing residual)
      estimated = std::max( Dsec(0), est_res );
      m_prev = clock::now();
    }


  } else {

    // Estimate time until nstep in seconds (assume lin-lin fn)
    Dsec est_nstep = elapsed * static_cast<tk::real>(nstep-it) / it;
    // Estimate time until term in seconds (assume lin-lin fn)
    tk::real large = std::numeric_limits< real >::max() - 1;
    Dsec est_term = std::abs(time) > eps && term < large ?
                    elapsed * (term-time) / time :
                    est_nstep;

    // Time stepping will stop at term or nstep, whichever is sooner
    estimated = std::min( est_term, est_nstep );
  }

  // Put elapsed time in watch as hours:minutes:seconds
  elapsedWatch.hrs = duration_cast< hours >( elapsed );
  elapsedWatch.min = duration_cast< minutes >( elapsed ) % hours(1);
  elapsedWatch.sec = duration_cast< seconds >( elapsed ) % minutes(1);
  // Put estimated time in watch as hours:minutes:seconds
  estimatedWatch.hrs = duration_cast< hours >( estimated );
  estimatedWatch.min = duration_cast< minutes >( estimated ) % hours(1);
  estimatedWatch.sec = duration_cast< seconds >( estimated ) % minutes(1);
}

Timer::Watch
tk::hms( tk::real stamp )
// *****************************************************************************
//! Convert existing time stamp as a real to Watch (global-scope)
//! \param[in] stamp Time stamp as a real number
//! \return Time as hours, minutes, and seconds, as a Watch struct.
// *****************************************************************************
{
  using std::chrono::duration_cast;
  const auto d = Timer::Dsec( stamp );
  return
    Timer::Watch( duration_cast< Timer::hours >( d ),
                  duration_cast< Timer::minutes >( d ) % Timer::hours(1),
                  duration_cast< Timer::seconds >( d ) % Timer::minutes(1) );
}