DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
CsvLog.hpp
Go to the documentation of this file.
1#pragma once
2/// @file CsvLog.hpp
3/// @brief Streaming CSV writer with auto-rotation and a dual int-or-double value type.
4
5#include <iostream>
6#include <iomanip>
7#include <fstream>
8
9#include "Defines.hpp"
10
11namespace DNDS
12{
13
14 /**
15 * @brief Storage-agnostic "either int or double" value with CSV-friendly streaming.
16 *
17 * @details Each instance holds either an integer (`i`) or a double (`d`);
18 * the unused field is set to the @ref UnInitIndex / @ref UnInitReal sentinel. The
19 * assignment operator dispatches on the source type, and `operator<<`
20 * prints whichever field is live. Designed for columns where some rows
21 * are integer counts and others are floating residuals.
22 */
24 {
25 int64_t i{UnInitIndex}; // UnInitIndex for double
26 double d{0};
27
28 template <class T>
29 std::enable_if_t<std::is_integral_v<T>, LogSimpleDIValue &> operator=(T v)
30 {
31 i = v;
32 if (i == UnInitIndex)
33 d = UnInitReal;
34 return *this;
35 }
36
37 template <class T>
38 std::enable_if_t<!std::is_integral_v<T>, LogSimpleDIValue &> operator=(T v)
39 {
40 d = v;
41 i = UnInitIndex;
42 return *this;
43 }
44
45 friend std::ostream &operator<<(std::ostream &o, const LogSimpleDIValue &v)
46 {
47 if (v.i == UnInitIndex)
48 o << v.d;
49 else
50 o << v.i;
51 return o;
52 }
53 };
54
55 /**
56 * @brief Append-only CSV logger with automatic file rotation after a line-count limit.
57 *
58 * @details One instance writes rows to a file, using a caller-provided
59 * ordered list of column titles. After `n_line_max` rows the output is
60 * rotated to `<bare>_<block>.suffix` to keep any single file size bounded.
61 *
62 * Typical use: one @ref DNDS::CsvLog "CsvLog" per solver per rank-0 process, recording
63 * per-iteration diagnostics with @ref DNDS::LogSimpleDIValue "LogSimpleDIValue" entries keyed by title.
64 */
65 class CsvLog
66 {
67 std::vector<std::string> titles;
68 std::unique_ptr<std::ostream> pOs;
69 int64_t n_line{0};
70 std::string log_name_bare;
71 std::string log_name_suffix;
72
73 std::string delim = ",";
74 int iBlock = 0;
75 int64_t n_line_max = INT64_MAX;
76 void update_ofstream(const std::string &fname)
77 {
78 std::filesystem::path outFile{fname};
79 std::filesystem::create_directories(outFile.parent_path() / ".");
80 pOs = std::make_unique<std::ofstream>(fname);
81 DNDS_check_throw_info(*pOs, "csv file [" + fname + "] did not open");
82 }
83
84 public:
85 /// @brief Construct a logger with externally-provided titles and output stream.
86 template <class T_titles>
87 CsvLog(T_titles &&n_titles, std::unique_ptr<std::ostream> n_pOs)
88 : titles(std::forward<T_titles>(n_titles)), pOs(std::move(n_pOs)) {}
89
90 /// @brief Construct a logger that creates / manages its own output files.
91 /// @param n_titles Column titles (ordered).
92 /// @param n_log_name_bare Base path without suffix, e.g. "out/run".
93 /// @param n_log_name_suffix Filename suffix including dot (default ".csv").
94 /// @param n_n_line_max Rotate to a new file every this many lines.
95 template <class T_titles>
96 CsvLog(T_titles &&n_titles,
97 const std::string &n_log_name_bare,
98 const std::string &n_log_name_suffix = ".csv",
99 int64_t n_n_line_max = 10000)
100 : titles(std::forward<T_titles>(n_titles)),
101 log_name_bare(n_log_name_bare),
102 log_name_suffix(n_log_name_suffix),
103 n_line_max(n_n_line_max)
104 {
105 update_ofstream(log_name_bare + n_log_name_suffix);
106 }
107
108 /// @brief Append one CSV row by looking up each column in `title_to_value`.
109 /// @tparam TMap Map-like supporting `operator[](std::string)` returning
110 /// something streamable.
111 /// @param nPrecision Decimal digits used for floating-point output.
112 template <class TMap>
113 void WriteLine(TMap &&title_to_value, int nPrecision)
114 {
115 if (n_line == 0)
116 WriteTitle();
117 (*pOs) << std::setprecision(nPrecision) << std::scientific;
118 for (size_t i = 0; i < titles.size(); i++)
119 (*pOs) << title_to_value[titles[i]] << ((i == (titles.size() - 1)) ? "" : ",");
120 (*pOs) << std::endl;
121 n_line++;
122 if (n_line >= n_line_max)
123 {
124 n_line = 0;
125 iBlock++;
126 DNDS_check_throw_info(log_name_bare.length(), "need to give a log name");
127 update_ofstream(log_name_bare + "_" + std::to_string(iBlock) + log_name_suffix);
128 }
129 }
130
131 /// @brief Emit the title row (called automatically on the first @ref WriteLine).
133 {
134 for (size_t i = 0; i < titles.size(); i++)
135 (*pOs) << titles[i] << ((i == (titles.size() - 1)) ? "" : ",");
136 (*pOs) << std::endl;
137 }
138 };
139
140 /// @brief Convenience alias: the `title -> value` map type passed to @ref DNDS::CsvLog "CsvLog"::WriteLine.
141 using tLogSimpleDIValueMap = std::map<std::string, LogSimpleDIValue>;
142}
Core type aliases, constants, and metaprogramming utilities for the DNDS framework.
#define DNDS_check_throw_info(expr, info)
Same as DNDS_check_throw but attaches a user-supplied info message to the thrown std::runtime_error.
Definition Errors.hpp:96
Append-only CSV logger with automatic file rotation after a line-count limit.
Definition CsvLog.hpp:66
void WriteLine(TMap &&title_to_value, int nPrecision)
Append one CSV row by looking up each column in title_to_value.
Definition CsvLog.hpp:113
void WriteTitle()
Emit the title row (called automatically on the first WriteLine).
Definition CsvLog.hpp:132
CsvLog(T_titles &&n_titles, std::unique_ptr< std::ostream > n_pOs)
Construct a logger with externally-provided titles and output stream.
Definition CsvLog.hpp:87
CsvLog(T_titles &&n_titles, const std::string &n_log_name_bare, const std::string &n_log_name_suffix=".csv", int64_t n_n_line_max=10000)
Construct a logger that creates / manages its own output files.
Definition CsvLog.hpp:96
the host side operators are provided as implemented
DNDS_CONSTANT const index UnInitIndex
Sentinel "not initialised" index value (= INT64_MIN).
Definition Defines.hpp:176
std::map< std::string, LogSimpleDIValue > tLogSimpleDIValueMap
Convenience alias: the title -> value map type passed to CsvLog::WriteLine.
Definition CsvLog.hpp:141
DNDS_CONSTANT const real UnInitReal
Sentinel "not initialised" real value (NaN). Cheap to detect with std::isnan or IsUnInitReal; survive...
Definition Defines.hpp:174
Storage-agnostic "either int or double" value with CSV-friendly streaming.
Definition CsvLog.hpp:24
std::enable_if_t< std::is_integral_v< T >, LogSimpleDIValue & > operator=(T v)
Definition CsvLog.hpp:29
friend std::ostream & operator<<(std::ostream &o, const LogSimpleDIValue &v)
Definition CsvLog.hpp:45
std::enable_if_t<!std::is_integral_v< T >, LogSimpleDIValue & > operator=(T v)
Definition CsvLog.hpp:38
Eigen::Matrix< real, 5, 1 > v