From 8b621c99e774d0824b19590a2db5cdcd761bc2d4 Mon Sep 17 00:00:00 2001
From: Remy Prechelt <prechelt@hawaii.edu>
Date: Sat, 6 Feb 2021 23:38:32 -1000
Subject: [PATCH] Write a top level summary file with time info.

---
 corsika/detail/output/OutputManager.inl | 70 ++++++++++++++++---------
 corsika/output/OutputManager.hpp        |  9 ++--
 2 files changed, 50 insertions(+), 29 deletions(-)

diff --git a/corsika/detail/output/OutputManager.inl b/corsika/detail/output/OutputManager.inl
index 218ca6462..e839c1daf 100644
--- a/corsika/detail/output/OutputManager.inl
+++ b/corsika/detail/output/OutputManager.inl
@@ -11,28 +11,15 @@
 #include <fstream>
 #include <functional>
 
-#include <iostream>
 #include <iomanip>
 #include <ctime>
 #include <sstream>
 
-namespace corsika {
-
-  std::string OutputManager::getCurrentTime() const {
-
-    // the format for our date string
-    auto fmt{"%d/%m/%Y %H:%M:%S %Z"};
+#include <fmt/core.h>
+#include <fmt/chrono.h>
 
-    // get the current time
-    auto t = std::time(nullptr);
-    auto current = *std::localtime(&t);
-
-    // create the string and push the time onto it
-    std::ostringstream oss;
-    oss << std::put_time(&current, fmt);
+namespace corsika {
 
-    return oss.str();
-  }
 
   void OutputManager::writeNode(YAML::Node const& node,
                                 std::filesystem::path const& path) const {
@@ -58,24 +45,49 @@ namespace corsika {
     config["name"] = name_;               // the simulation name
     config["creator"] = "CORSIKA8";       // a tag to identify C8 libraries
     config["version"] = "8.0.0-prealpha"; // the current version
-    config["start time"] = getCurrentTime();
 
     // write the node to a file
     writeNode(config, root_ / ("config.yaml"));
   }
 
-  // void OutputManager::writeTopLevelSummary() const {
+  void OutputManager::writeTopLevelSummary() const {
+
+    YAML::Node config;
+
+    // the total number of showers contained in the library
+    config["showers"] = count_;
+
+    // this next section handles writing some time and duration information
 
-  //   YAML::Node config;
+    // create a quick lambda function to convert a time-instance to a string
+    auto timeToString = [&](auto const time) -> std::string {
 
-  //   // some basic info
-  //   config["start time"] = getCurrentTime(); // TODO:
-  //   config["end time"] = getCurrentTime();
-  //   // config["showers"] = 0; // TODO
+      // the format for our date string
+      auto format{"%d/%m/%Y %H:%M:%S %Z"};
 
-  //   // write the node to a file
-  //   writeNode(config, root_ / ("summary.yaml"));
-  // }
+      // convert the clock to a time_t
+      auto time_tc{std::chrono::system_clock::to_time_t(time)};
+
+      // create the string and push the time onto it
+      std::ostringstream oss;
+      oss << std::put_time(std::localtime(&time_tc), format);
+
+      return oss.str();
+    };
+
+    auto end_time{std::chrono::system_clock::now()};
+
+    // now let's construct an estimate of the runtime
+    auto runtime{end_time - start_time};
+
+    // add the time and duration info
+    config["start time"] = timeToString(start_time);
+    config["end time"] = timeToString(end_time);
+    config["runtime"] = fmt::format("{:%H:%M:%S}", runtime);
+
+    // write the node to a file
+    writeNode(config, root_ / ("summary.yaml"));
+  }
 
   void OutputManager::initOutput(std::string const& name) const {
     // construct the path to this directory
@@ -126,6 +138,9 @@ namespace corsika {
       endOfShower();
     }
 
+    // write the top level summary file (summary.yaml)
+    writeTopLevelSummary();
+
     // if we are being destructed but EndOfLibrary() has not been called,
     // make sure that we gracefully close all the outputs. This is a supported
     // method of operation so we don't issue a warning here
@@ -183,6 +198,9 @@ namespace corsika {
     // now start the event for all the outputs
     for (auto& [name, output] : outputs_) { output.get().startOfShower(); }
 
+    // increment our shower count
+    ++count_;
+
     // and transition to the in progress state
     state_ = OutputState::ShowerInProgress;
   }
diff --git a/corsika/output/OutputManager.hpp b/corsika/output/OutputManager.hpp
index 29b7880e7..76105f2b6 100644
--- a/corsika/output/OutputManager.hpp
+++ b/corsika/output/OutputManager.hpp
@@ -7,6 +7,7 @@
  */
 #pragma once
 
+#include <chrono>
 #include <string>
 #include <filesystem>
 #include <corsika/output/BaseOutput.hpp>
@@ -32,8 +33,10 @@ namespace corsika {
     OutputState state_{OutputState::NoInit}; ///< The current state of this manager.
     std::string const name_;                 ///< The name of this simulation file.
     std::filesystem::path const root_;       ///< The top-level directory for the output.
+    int count_{0};                           ///< The current ID of this shower.
+    std::chrono::time_point<std::chrono::system_clock> const start_time{
+        std::chrono::system_clock::now()};           ///< The time the manager is created.
     inline static auto logger{get_logger("output")}; ///< A custom logger.
-
     /**
      * The outputs that have been registered with us.
      */
@@ -55,9 +58,9 @@ namespace corsika {
     void initOutput(std::string const& name) const;
 
     /**
-     * Get the current local time as a string.
+     * Write the top-level summary of this library.
      */
-    std::string getCurrentTime() const;
+    void writeTopLevelSummary() const;
 
   public:
     /**
-- 
GitLab