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  * Duplicate detection uses a 3-tuple identity (step, call_site, time):
56  * - step: timestep number (int)
57  * - call_site: diagnostic call-site label (e.g., "pre_dycore", "post_dycore")
58  * - time: simulation time with tolerance m_diag_dedup_tol
59  *
60  * This ensures:
61  * 1. Accidental repeated calls at the same (step, call_site, time) are suppressed.
62  * 2. Legitimate pre_dycore + post_dycore entries at the same step are both retained
63  * (they have different call_site values, so dedup identity differs).
64  * 3. Mode filtering (pre_only, post_only, both) preserves this contract by checking
65  * whether to emit BEFORE the dedup guard runs.
66  *
67  * Follows the duplicate-write-guard pattern from UCMDiagnostics.
68  */
70 {
71 public:
72  /**
73  * @brief Constructor.
74  *
75  * @param[in] verbosity Debug verbosity level (0=off, 1+=print).
76  * @param[in] diag_file Output CSV file path (relative to working directory).
77  * @param[in] amr_level AMR level index.
78  * @param[in] diag_enable Master switch for all diagnostics.
79  * @param[in] diag_stdout_enable Enable human-readable stdout block.
80  * @param[in] diag_tagged_enable Enable tagged debug lines.
81  * @param[in] diag_regtest_line_enable Enable RADIATION_DIAG: lines.
82  * @param[in] diag_csv_enable Enable CSV file writes.
83  * @param[in] diag_callsite_mode Call-site filter: "both", "pre_only", "post_only".
84  * @param[in] diag_dedup_tol Tolerance for time equality in duplicate guard.
85  */
86  RadiationDiagnostics(int verbosity, const std::string& diag_file,
87  bool diag_enable = true, bool diag_stdout_enable = true,
88  bool diag_tagged_enable = true, bool diag_regtest_line_enable = true,
89  bool diag_csv_enable = true, const std::string& diag_callsite_mode = "both",
90  amrex::Real diag_dedup_tol = 1.0e-12);
91 
92  /**
93  * @brief Destructor.
94  */
96 
97  /**
98  * @brief Append a diagnostic row to the CSV file.
99  *
100  * Records a row of radiation diagnostics for the current timestep:
101  *
102  * CSV columns (order):
103  * step, time, call_site, SW_surface, SW_TOA, SW_up_TOA, LW_net_surface, LW_up_TOA, heating_rate_max
104  * [optional]: SEB_residual_mean, SEB_residual_max (only if seb_diagnostic_enable=true)
105  *
106  * Also prints tagged debug output and RADIATION_DIAG: line for RegTest parsing.
107  *
108  * Guards against duplicate writes (uses m_last_write_step).
109  *
110  * @param[in] step Current timestep number.
111  * @param[in] time Current simulation time [s].
112  * @param[in] call_site Diagnostic call-site label (e.g., "pre_dycore", "post_dycore").
113  * @param[in] SW_surface SW absorbed by the surface, (1 - albedo) * incident [W/m^2].
114  * @param[in] SW_TOA Incident SW at the top of the atmosphere [W/m^2].
115  * @param[in] SW_up_TOA Reflected SW leaving the top of the atmosphere [W/m^2].
116  * @param[in] LW_net_surface Net LW (up - down) at the surface [W/m^2].
117  * @param[in] LW_up_TOA Outgoing LW at the top of the atmosphere [W/m^2].
118  * @param[in] heating_rate_max Maximum heating rate magnitude [K/s].
119  * @param[in] seb_residual_mean [optional] Mean SEB residual [W/m^2]; if non-finite, not written.
120  * @param[in] seb_residual_max [optional] Max SEB residual [W/m^2]; if non-finite, not written.
121  * @param[in] t_s_mean [optional] Mean surface temperature [K]; if non-finite, written as NaN.
122  * @param[in] t_s_max [optional] Max surface temperature [K]; if non-finite, written as NaN.
123  * @param[in] q_s_mean [optional] Mean surface moisture [kg/kg]; if non-finite, written as NaN.
124  * @param[in] q_s_max [optional] Max surface moisture [kg/kg]; if non-finite, written as NaN.
125  */
126  void append(int step, amrex::Real time, std::string const& call_site,
127  amrex::Real sw_surface, amrex::Real sw_toa, amrex::Real sw_up_toa,
128  amrex::Real lw_net_surface, amrex::Real lw_up_toa,
129  amrex::Real heating_rate_max,
130  amrex::Real seb_residual_mean = std::numeric_limits<amrex::Real>::quiet_NaN(),
131  amrex::Real seb_residual_max = std::numeric_limits<amrex::Real>::quiet_NaN(),
132  amrex::Real t_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN(),
133  amrex::Real t_s_max = std::numeric_limits<amrex::Real>::quiet_NaN(),
134  amrex::Real q_s_mean = std::numeric_limits<amrex::Real>::quiet_NaN(),
135  amrex::Real q_s_max = std::numeric_limits<amrex::Real>::quiet_NaN());
136 
137 private:
138  /**
139  * @brief Write CSV header if file is new or doesn't exist.
140  */
141  void write_header_if_needed();
142 
143  int m_verbosity; ///< Debug verbosity level
144  std::string m_diag_file; ///< Output CSV file path
145  int m_last_write_step = -1; ///< Guard against duplicate writes
146  bool m_header_written = false; ///< Track whether CSV header was written
147  std::string m_last_write_call_site = "";
149 
150  // Diagnostics controls
151  bool m_diag_enable = true;
152  bool m_diag_stdout_enable = true;
153  bool m_diag_tagged_enable = true;
155  bool m_diag_csv_enable = true;
156  std::string m_diag_callsite_mode = "both";
158 };
159 
160 #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:70
bool m_diag_tagged_enable
Definition: ERF_RadiationDiagnostics.H:153
bool m_diag_regtest_line_enable
Definition: ERF_RadiationDiagnostics.H:154
int m_last_write_step
Guard against duplicate writes.
Definition: ERF_RadiationDiagnostics.H:145
int m_verbosity
Debug verbosity level.
Definition: ERF_RadiationDiagnostics.H:143
bool m_diag_stdout_enable
Definition: ERF_RadiationDiagnostics.H:152
std::string m_diag_file
Output CSV file path.
Definition: ERF_RadiationDiagnostics.H:144
bool m_header_written
Track whether CSV header was written.
Definition: ERF_RadiationDiagnostics.H:146
void write_header_if_needed()
Write CSV header if file is new or doesn't exist.
Definition: ERF_RadiationDiagnostics.cpp:38
std::string m_diag_callsite_mode
Definition: ERF_RadiationDiagnostics.H:156
amrex::Real m_last_write_time
Definition: ERF_RadiationDiagnostics.H:148
RadiationDiagnostics(int verbosity, const std::string &diag_file, 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
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:75
std::string m_last_write_call_site
Definition: ERF_RadiationDiagnostics.H:147
amrex::Real m_diag_dedup_tol
Definition: ERF_RadiationDiagnostics.H:157
~RadiationDiagnostics()
Destructor.
Definition: ERF_RadiationDiagnostics.cpp:32
bool m_diag_csv_enable
Definition: ERF_RadiationDiagnostics.H:155
bool m_diag_enable
Definition: ERF_RadiationDiagnostics.H:151