Molecular Dynamics Simulation  1.0
ProgressBarInterceptor.cpp
Go to the documentation of this file.
2 
3 #include <spdlog/fmt/chrono.h>
4 #include <sys/ioctl.h>
5 
6 #include <filesystem>
7 #include <iostream>
8 
9 #include "io/logger/Logger.h"
11 #include "utils/FormatTime.h"
12 
13 int displayed_width(const char* p) {
14  int result = 0;
15  for (; *p; ++p) {
16  if (p[0] == '\e' && p[1] == '[')
17  while (*p != 'm')
18  if (*p)
19  ++p;
20  else
21  throw std::runtime_error("string terminates inside ANSI colour sequence");
22  else
23  ++result;
24  }
25  return result;
26 }
27 
28 void printProgress(const std::filesystem::path& input_file_path, size_t percentage, size_t iteration, size_t expected_iterations,
29  int estimated_remaining_seconds = -1, double particle_updates_per_second = -1, bool finished = false) {
30  struct winsize size {};
31  ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
32 
33  auto should_progress_bar_length = std::min(std::max(size.ws_col - 90, 0), 100);
34  auto length_full_progress_bar = static_cast<size_t>(percentage * static_cast<double>(should_progress_bar_length) / 100.0);
35 
36  auto progress_bar = fmt::format("[{}{}]", ansi_blue_bold + std::string(length_full_progress_bar, '#'),
37  std::string(should_progress_bar_length - length_full_progress_bar, ' ') + ansi_end);
38 
39  std::string line = fmt::format("{} {}/{} {:>4} ETA: {} MUP/s: {} [{}]", progress_bar, iteration, expected_iterations,
40  ansi_bright_white_bold + std::to_string(percentage) + "%" + ansi_end,
41  ansi_bright_white_bold + format_seconds_eta(estimated_remaining_seconds) + ansi_end,
42  ansi_bright_white_bold + format_mup_s(particle_updates_per_second) + ansi_end,
43  ansi_bright_white_bold + std::filesystem::path(input_file_path).stem().string() + ansi_end);
44 
45  if (displayed_width(line.c_str()) > size.ws_col) {
46  line = line.substr(0, size.ws_col - 3) + "...";
47  }
48 
49  std::cout << "\33[2K\r" << line << std::flush;
50 
51  if (finished) {
52  std::cout << std::endl;
53  }
54 }
55 
57  t_start = std::chrono::high_resolution_clock::now();
58  t_prev = t_start;
59 
60  expected_iterations = static_cast<size_t>(std::ceil(simulation.params.end_time / simulation.params.delta_t));
61 
62  SimulationInterceptor::every_nth_iteration = std::max(1, static_cast<int>(expected_iterations / 1000.0));
63 
64  const size_t percentage = std::min(100ul, static_cast<size_t>(100.0 * static_cast<double>(simulation.params.start_iteration) /
65  static_cast<double>(expected_iterations)));
66 
67  last_particle_count = simulation.particle_container->size();
69 
72 
73  Logger::logger->flush();
74  printProgress(simulation.params.input_file_path, percentage, simulation.params.start_iteration, expected_iterations, -1, -1);
75 }
76 
77 void ProgressBarInterceptor::operator()(size_t iteration, Simulation& simulation) {
78  // calculate time since last write
79  auto t_now = std::chrono::high_resolution_clock::now();
80  const double seconds_since_last_write = std::chrono::duration<double>(t_now - t_prev).count();
81  t_prev = t_now;
82 
83  // calculate estimated remaining time
84  const int estimated_remaining_seconds = std::floor(seconds_since_last_write * static_cast<double>(expected_iterations - iteration) /
85  static_cast<double>(every_nth_iteration));
86 
87  // calculate percentage
88  const size_t percentage =
89  std::min(100ul, static_cast<size_t>(100.0 * static_cast<double>(iteration) / static_cast<double>(expected_iterations)));
90 
91  // calculate particle updates per second
92  size_t current_particle_count = simulation.particle_container->size();
93  size_t particle_updates = (current_particle_count + last_particle_count) / 2 * (iteration - last_iteration);
94 
95  double particle_updates_per_second = static_cast<double>(particle_updates) / seconds_since_last_write;
96  last_particle_count = current_particle_count;
97  last_iteration = iteration;
98 
99  // Smooth out the estimated remaining time and the updates per second
100  if (last_remaining_seconds < 0) last_remaining_seconds = estimated_remaining_seconds;
101  if (last_particle_updates_per_second < 0) last_particle_updates_per_second = particle_updates_per_second;
102 
103  double smoothed_remaining_seconds = (estimated_remaining_seconds + last_remaining_seconds) / 2;
104  double smoothed_particle_updates_per_second = (particle_updates_per_second + last_particle_updates_per_second) / 2;
105 
106  printProgress(simulation.params.input_file_path, percentage, iteration, expected_iterations, smoothed_remaining_seconds,
107  smoothed_particle_updates_per_second);
108 
109  last_remaining_seconds = smoothed_remaining_seconds;
110  last_particle_updates_per_second = smoothed_particle_updates_per_second;
111 }
112 
113 void ProgressBarInterceptor::onSimulationEnd(size_t iteration, Simulation& simulation) {
115 }
116 
117 void ProgressBarInterceptor::logSummary(int depth) const {
118  std::string indent = std::string(depth * 2, ' ');
119 
120  Logger::logger->info("{}╟┤{}ProgressBar: {}", indent, ansi_orange_bold, ansi_end);
121  Logger::logger->info("{}║ ├Enabled", indent);
122 }
123 
124 ProgressBarInterceptor::operator std::string() const { return ""; }
std::string format_seconds_eta(int total_seconds)
Formats the given seconds into a string of the form "HH:MM:SS".
Definition: FormatTime.cpp:5
std::string format_mup_s(double mup_s)
Formats the given mup/s into a string.
Definition: FormatTime.cpp:17
const std::string ansi_bright_white_bold
Definition: Logger.h:12
const std::string ansi_end
Definition: Logger.h:13
const std::string ansi_orange_bold
Definition: Logger.h:10
const std::string ansi_blue_bold
Definition: Logger.h:9
int displayed_width(const char *p)
void printProgress(const std::filesystem::path &input_file_path, size_t percentage, size_t iteration, size_t expected_iterations, int estimated_remaining_seconds=-1, double particle_updates_per_second=-1, bool finished=false)
static std::shared_ptr< spdlog::logger > logger
Publically accessible shared pointer to the logger.
Definition: Logger.h:35
void logSummary(int depth) const override
Logs the summary of the progress bar.
void onSimulationEnd(size_t iteration, Simulation &simulation) override
This function is empty as the progress bar doesnt need to do anything at the end of the simulation.
void operator()(size_t iteration, Simulation &simulation) override
This function is called on every nth iteration. It prints a progress bar to the console and updates t...
std::chrono::high_resolution_clock::time_point t_start
std::chrono::high_resolution_clock::time_point t_prev
void onSimulationStart(Simulation &simulation) override
This function initalized the start time of the simulation and the previous time point.
double delta_t
Time step of a single simulation iteration.
std::filesystem::path input_file_path
Path to the input file of the simulation.
size_t start_iteration
Start iteration of the simulation.
double end_time
End time of the simulation.
Class to run a simulation.
Definition: Simulation.h:20
std::unique_ptr< ParticleContainer > particle_container
Reference to the ParticleContainer on whose content the simulation is performed.
Definition: Simulation.h:50
const SimulationParams & params
Reference to the simulation parameters object.
Definition: Simulation.h:45
std::string to_string(const Container &container, const std::string &delimiter=", ", const std::array< std::string, 2 > &surround={"[", "]"})
Definition: ArrayUtils.h:97