ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_RadiationDiagnostics.H
Go to the documentation of this file.
1 #ifndef ERF_RADIATION_DIAGNOSTICS_H_
2 #define ERF_RADIATION_DIAGNOSTICS_H_
3 
4 #include <string>
5 #include <fstream>
6 #include <limits>
7 #include <AMReX.H>
8 #include <AMReX_REAL.H>
9 
10 /**
11  * @file ERF_RadiationDiagnostics.H
12  * @brief Radiation module diagnostic output and CSV logging.
13  *
14  * Follows the debug-print and diagnostic-output conventions established in
15  * the ERF-SLUCM branch (see Source/UrbanCanopy/ERF_UCMDiagnostics.H for
16  * reference pattern).
17  *
18  * TAGGED DEBUG FORMAT:
19  * -------------------
20  * All debug prints use the bracketed-tag prefix format:
21  * [RAD][ClassName::function] step={nstep} time={time} ...
22  *
23  * Tags:
24  * - [RAD] — module tag (parallel to [UCM])
25  * - [ClassName::function] — call-site tag for grepability
26  *
27  * VERBOSITY CONTROL:
28  * ------------------
29  * Debug prints only emit when erf.radiation.v >= 1 (default 0).
30  * However, RADIATION_DIAG: lines always print (required for RegTest scripts).
31  *
32  * MPI SAFETY:
33  * -----------
34  * All host-side debug output is guarded by amrex::ParallelDescriptor::IOProcessor(),
35  * matching the UCMDiagnostics pattern.
36  *
37  * CSV OUTPUT:
38  * -----------
39  * The RadiationDiagnostics class appends rows to a CSV file containing
40  * simulation-level radiation quantities (e.g., surface SW/LW, TOA fluxes).
41  * RegTest check scripts parse the RADIATION_DIAG: prefix to extract values.
42  */
43 
44 /**
45  * @class RadiationDiagnostics
46  * @brief CSV logger and debug-print manager for radiation module.
47  *
48  * Manages output of radiation diagnostics including:
49  * - Tagged debug prints (when verbosity >= 1)
50  * - CSV rows for flux/heating diagnostics
51  * - RADIATION_DIAG: lines for RegTest parsing
52  *
53  * **Dedup Contract:**
54  *
55  * Each AMR level owns its own RadiationDiagnostics, so the identity below is
56  * implicitly per level: two levels reporting the same step, call_site and time
57  * are distinct instances and neither suppresses the other. All instances append
58  * to the same CSV, which carries a `level` column to tell the rows apart.
59  *
60  * Duplicate detection uses a 3-tuple identity (step, call_site, time):
61  * - step: timestep number (int)
62  * - call_site: diagnostic call-site label (e.g., "pre_dycore", "post_dycore")
63  * - time: simulation time with tolerance m_diag_dedup_tol
64  *
65  * This ensures:
66  * 1. Accidental repeated calls at the same (step, call_site, time) are suppressed.
67  * 2. Legitimate pre_dycore + post_dycore entries at the same step are both retained
68  * (they have different call_site values, so dedup identity differs).
69  * 3. Mode filtering (pre_only, post_only, both) preserves this contract by checking
70  * whether to emit BEFORE the dedup guard runs.
71  *
72  * Follows the duplicate-write-guard pattern from UCMDiagnostics.
73  */
75 {
76 public:
77  /**
78  * @brief Constructor.
79  *
80  * @param[in] verbosity Debug verbosity level (0=off, 1+=print).
81  * @param[in] diag_file Output CSV file path (relative to working directory).
82  * @param[in] amr_level AMR level this instance reports for. Written as the
83  * `level` CSV column and tagged onto the stdout lines. One
84  * instance per level, so the duplicate guard below is per level
85  * and a fine level's row is never mistaken for a coarse one.
86  * @param[in] diag_enable Master switch for all diagnostics.
87  * @param[in] diag_stdout_enable Enable human-readable stdout block.
88  * @param[in] diag_tagged_enable Enable tagged debug lines.
89  * @param[in] diag_regtest_line_enable Enable RADIATION_DIAG: lines.
90  * @param[in] diag_csv_enable Enable CSV file writes.
91  * @param[in] diag_callsite_mode Call-site filter: "both", "pre_only", "post_only".
92  * @param[in] diag_dedup_tol Tolerance for time equality in duplicate guard.
93  */
94  RadiationDiagnostics (int verbosity, const std::string& diag_file, int amr_level,
95  bool diag_enable = true, bool diag_stdout_enable = true,
96  bool diag_tagged_enable = true, bool diag_regtest_line_enable = true,
97  bool diag_csv_enable = true, const std::string& diag_callsite_mode = "both",
98  amrex::Real diag_dedup_tol = 1.0e-12);
99 
100  /**
101  * @brief Destructor.
102  */
104 
105  /**
106  * @brief Append a diagnostic row to the CSV file.
107  *
108  * Records a row of radiation diagnostics for the current timestep:
109  *
110  * CSV columns (order):
111  * step, time, call_site, SW_surface, SW_TOA, SW_up_TOA, LW_net_surface, LW_up_TOA, heating_rate_max
112  * [optional]: SEB_residual_mean, SEB_residual_max (only if seb_diagnostic_enable=true)
113  * [optional]: T_s_mean, T_s_max, q_s_mean, q_s_max
114  * level -- appended last, following this file's rule that new columns go
115  * at the end so existing header-name parsers keep working.
116  *
117  * Also prints tagged debug output and RADIATION_DIAG: line for RegTest parsing.
118  *
119  * Guards against duplicate writes (uses m_last_write_step).
120  *
121  * @param[in] step Current timestep number.
122  * @param[in] time Current simulation time [s].
123  * @param[in] call_site Diagnostic call-site label (e.g., "pre_dycore", "post_dycore").
124  * @param[in] SW_surface SW absorbed by the surface, (1 - albedo) * incident [W/m^2].
125  * @param[in] SW_TOA Incident SW at the top of the atmosphere [W/m^2].
126  * @param[in] SW_up_TOA Reflected SW leaving the top of the atmosphere [W/m^2].
127  * @param[in] LW_net_surface Net LW (up - down) at the surface [W/m^2].
128  * @param[in] LW_up_TOA Outgoing LW at the top of the atmosphere [W/m^2].
129  * @param[in] heating_rate_max Maximum heating rate magnitude [K/s].
130  * @param[in] seb_residual_mean [optional] Mean SEB residual [W/m^2]; if non-finite, not written.
131  * @param[in] seb_residual_max [optional] Max SEB residual [W/m^2]; if non-finite, not written.
132  * @param[in] t_s_mean [optional] Mean surface temperature [K]; if non-finite, written as NaN.
133  * @param[in] t_s_max [optional] Max surface temperature [K]; if non-finite, written as NaN.
134  * @param[in] q_s_mean [optional] Mean surface moisture [kg/kg]; if non-finite, written as NaN.
135  * @param[in] q_s_max [optional] Max surface moisture [kg/kg]; if non-finite, written as NaN.
136  */
137  void append (int step, amrex::Real time, std::string const& call_site,
138  amrex::Real sw_surface, amrex::Real sw_toa, amrex::Real sw_up_toa,
139  amrex::Real lw_net_surface, amrex::Real lw_up_toa,
140  amrex::Real heating_rate_max,
141  amrex::Real seb_residual_mean = std::numeric_limits<amrex::Real>::quiet_NaN(),
142  amrex::Real seb_residual_max = std::numeric_limits<amrex::Real>::quiet_NaN(),
143  amrex::Real t_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN(),
144  amrex::Real t_s_max = std::numeric_limits<amrex::Real>::quiet_NaN(),
145  amrex::Real q_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN(),
146  amrex::Real q_s_max = std::numeric_limits<amrex::Real>::quiet_NaN());
147 
148 private:
149  /**
150  * @brief Write CSV header if file is new or doesn't exist.
151  */
152  void write_header_if_needed ();
153 
154  int m_verbosity; ///< Debug verbosity level
155  std::string m_diag_file; ///< Output CSV file path
156  int m_amr_level = 0; ///< AMR level this instance reports for
157  int m_last_write_step = -1; ///< Guard against duplicate writes
158  bool m_header_written = false; ///< Track whether CSV header was written
159  std::string m_last_write_call_site = "";
161 
162  // Diagnostics controls
163  bool m_diag_enable = true;
164  bool m_diag_stdout_enable = true;
165  bool m_diag_tagged_enable = true;
167  bool m_diag_csv_enable = true;
168  std::string m_diag_callsite_mode = "both";
170 };
171 
172 #endif // ERF_RADIATION_DIAGNOSTICS_H_
amrex::Real Real
Definition: ERF_ShocInterface.H:19
CSV logger and debug-print manager for radiation module.
Definition: ERF_RadiationDiagnostics.H:75
bool m_diag_tagged_enable
Definition: ERF_RadiationDiagnostics.H:165
bool m_diag_regtest_line_enable
Definition: ERF_RadiationDiagnostics.H:166
int m_last_write_step
Guard against duplicate writes.
Definition: ERF_RadiationDiagnostics.H:157
int m_verbosity
Debug verbosity level.
Definition: ERF_RadiationDiagnostics.H:154
bool m_diag_stdout_enable
Definition: ERF_RadiationDiagnostics.H:164
std::string m_diag_file
Output CSV file path.
Definition: ERF_RadiationDiagnostics.H:155
int m_amr_level
AMR level this instance reports for.
Definition: ERF_RadiationDiagnostics.H:156
bool m_header_written
Track whether CSV header was written.
Definition: ERF_RadiationDiagnostics.H:158
void write_header_if_needed()
Write CSV header if file is new or doesn't exist.
Definition: ERF_RadiationDiagnostics.cpp:39
RadiationDiagnostics(int verbosity, const std::string &diag_file, int amr_level, bool diag_enable=true, bool diag_stdout_enable=true, bool diag_tagged_enable=true, bool diag_regtest_line_enable=true, bool diag_csv_enable=true, const std::string &diag_callsite_mode="both", amrex::Real diag_dedup_tol=1.0e-12)
Constructor.
Definition: ERF_RadiationDiagnostics.cpp:12
std::string m_diag_callsite_mode
Definition: ERF_RadiationDiagnostics.H:168
amrex::Real m_last_write_time
Definition: ERF_RadiationDiagnostics.H:160
void append(int step, amrex::Real time, std::string const &call_site, amrex::Real sw_surface, amrex::Real sw_toa, amrex::Real sw_up_toa, amrex::Real lw_net_surface, amrex::Real lw_up_toa, amrex::Real heating_rate_max, amrex::Real seb_residual_mean=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real seb_residual_max=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real t_s_mean=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real t_s_max=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real q_s_mean=std::numeric_limits< amrex::Real >::quiet_NaN(), amrex::Real q_s_max=std::numeric_limits< amrex::Real >::quiet_NaN())
Append a diagnostic row to the CSV file.
Definition: ERF_RadiationDiagnostics.cpp:79
std::string m_last_write_call_site
Definition: ERF_RadiationDiagnostics.H:159
amrex::Real m_diag_dedup_tol
Definition: ERF_RadiationDiagnostics.H:169
~RadiationDiagnostics()
Destructor.
Definition: ERF_RadiationDiagnostics.cpp:33
bool m_diag_csv_enable
Definition: ERF_RadiationDiagnostics.H:167
bool m_diag_enable
Definition: ERF_RadiationDiagnostics.H:163