OGS
MatrixOutput.cpp
Go to the documentation of this file.
1
11#include "MatrixOutput.h"
12
13#include <spdlog/fmt/bundled/ostream.h>
14
15#include <optional>
16#include <unordered_set>
17
18#include "BaseLib/Error.h"
19#include "BaseLib/Logging.h"
22
23namespace
24{
25std::string getSeparatorAfterFilenamePrefix(std::string const& filenamePrefix)
26{
27 return filenamePrefix.empty() || filenamePrefix.ends_with('/') ||
28 filenamePrefix.ends_with('\\')
29 ? ""
30 : "_";
31}
32
33#ifndef USE_PETSC
34static void outputGlobalMatrix(GlobalMatrix const& mat, std::ostream& os)
35{
36 os << std::setprecision(16) << "(" << mat.getNumberOfRows() << " x "
37 << mat.getNumberOfColumns() << ")\n";
38 mat.write(os);
39}
40
41static void outputGlobalVector(GlobalVector const& vec, std::ostream& os)
42{
43 os << std::setprecision(16) << "(" << vec.size() << ")\n";
44 os << vec.getRawVector() << '\n';
45}
46
47std::ofstream openGlobalMatrixOutputFile(std::string const& filenamePrefix,
48 std::size_t const counter,
49 double const t, int const process_id,
50 std::string const& which_matrix,
51 std::string const& extension)
52{
53 auto const filename = fmt::format(
54 "{}{}ogs_global_matrix_cnt_{:03}_t_{:g}_pcs_{}_{}.{}", filenamePrefix,
55 getSeparatorAfterFilenamePrefix(filenamePrefix), counter, t, process_id,
56 which_matrix, extension);
57
58 std::ofstream fh{filename};
59
60 if (!fh)
61 {
62 OGS_FATAL("Could not open file `{}' for global matrix debug output",
63 filename);
64 }
65
66 return fh;
67}
68#endif
69
70static std::optional<std::string> getEnvironmentVariable(
71 std::string const& env_var)
72{
73 char const* const prefix = std::getenv(env_var.c_str());
74 return prefix ? std::make_optional(prefix) : std::nullopt;
75}
76
77std::string localMatrixOutputFilename(std::string const& filenamePrefix)
78{
79 return fmt::format("{}{}ogs_local_matrix.log", filenamePrefix,
80 getSeparatorAfterFilenamePrefix(filenamePrefix));
81}
82
83Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
84 Eigen::RowMajor>>
85toSquareMatrixRowMajor(std::vector<double> entries)
86{
87 auto const num_r_c =
88 static_cast<Eigen::Index>(std::round(std::sqrt(entries.size())));
89
90 return {entries.data(), num_r_c, num_r_c};
91}
92} // namespace
93
95{
96namespace detail
97{
98std::unordered_set<std::size_t> parseSetOfSizeT(std::string const& str,
99 std::string const& warn_msg)
100{
101 std::istringstream sstr{str};
102 std::unordered_set<std::size_t> result;
103 std::ptrdiff_t value;
104
105 while (sstr >> value)
106 {
107 [[likely]] if (value >= 0)
108 {
109 result.insert(value);
110 }
111 else
112 {
113 if (!warn_msg.empty())
114 {
115 WARN("{}", warn_msg);
116 }
117
118 return result;
119 }
120 }
121
122 if (!sstr.eof() && !warn_msg.empty()) // The stream is not read until
123 // the end, must be an error.
124 {
125 WARN("{}", warn_msg);
126 }
127
128 return result;
129}
130
131std::function<bool(std::size_t)> createLocalMatrixOutputElementPredicate(
132 std::string const& element_ids_str)
133{
134 if (element_ids_str.empty())
135 {
136 return {};
137 }
138
139 if (element_ids_str == "*")
140 {
141 return [](std::size_t) { return true; };
142 }
143
144 auto element_ids = parseSetOfSizeT(
145 element_ids_str,
146 "Error parsing list of element ids for local matrix debug "
147 "output. We'll try to proceed anyway, as best as we can.");
148
149 if (element_ids.empty())
150 {
151 return {};
152 }
153
154 return [element_ids = std::move(element_ids)](std::size_t element_id)
155 { return element_ids.contains(element_id); };
156}
157} // namespace detail
158
160{
161 auto opt_prefix = getEnvironmentVariable("OGS_GLOBAL_MAT_OUT_PREFIX");
162
163 if (opt_prefix.has_value())
164 {
165#ifndef USE_PETSC
166 do_output_ = true;
167 filenamePrefix_ = std::move(*opt_prefix);
168#else
169 // TODO implement. PETScMatrix's viewer() method could be used for that.
170 WARN(
171 "You requested global matrix output (OGS_GLOBAL_MAT_OUT_PREFIX is "
172 "set), which is not yet implemented for PETSc matrices.");
173#endif
174 }
175}
176
177void GlobalMatrixOutput::operator()(double const t, int const process_id,
178 GlobalMatrix const& M,
179 GlobalMatrix const& K,
180 GlobalVector const& b,
181 GlobalMatrix const* const Jac)
182{
183 if (!do_output_)
184 {
185 return;
186 }
187
188#ifndef USE_PETSC
189 ++counter_;
190
191 {
192 auto fh = openGlobalMatrixOutputFile(filenamePrefix_, counter_, t,
193 process_id, "M", "mat");
194
195 fh << "M ";
196 outputGlobalMatrix(M, fh);
197 }
198
199 {
200 auto fh = openGlobalMatrixOutputFile(filenamePrefix_, counter_, t,
201 process_id, "K", "mat");
202
203 fh << "K ";
204 outputGlobalMatrix(K, fh);
205 }
206
207 {
208 auto fh = openGlobalMatrixOutputFile(filenamePrefix_, counter_, t,
209 process_id, "b", "vec");
210
211 fh << "b ";
212 outputGlobalVector(b, fh);
213 }
214
215 if (Jac)
216 {
217 auto fh = openGlobalMatrixOutputFile(filenamePrefix_, counter_, t,
218 process_id, "Jac", "mat");
219
220 fh << "Jac ";
221 outputGlobalMatrix(*Jac, fh);
222 }
223#else
224 // do nothing, warning message already printed in the constructor
225 (void)t;
226 (void)process_id;
227 (void)M;
228 (void)K;
229 (void)b;
230 (void)Jac;
231#endif
232}
233
235{
236 auto const opt_prefix = getEnvironmentVariable("OGS_LOCAL_MAT_OUT_PREFIX");
237 auto const opt_elements =
238 getEnvironmentVariable("OGS_LOCAL_MAT_OUT_ELEMENTS");
239
240 if (!opt_prefix)
241 {
242 if (opt_elements)
243 {
244 WARN(
245 "Environment variable OGS_LOCAL_MAT_OUT_ELEMENTS is set, but "
246 "OGS_LOCAL_MAT_OUT_PREFIX is not. Local matrix debug output "
247 "will be disabled.");
248 }
249
250 return;
251 }
252 if (!opt_elements)
253 {
254 WARN(
255 "Environment variable OGS_LOCAL_MAT_OUT_PREFIX is set, but "
256 "OGS_LOCAL_MAT_OUT_ELEMENTS is not. Local matrix debug output "
257 "will be disabled.");
258 return;
259 }
260
263
265 {
266 WARN(
267 "Environment variable OGS_LOCAL_MAT_OUT_ELEMENTS not set "
268 "properly. Local matrix debug output will be disabled.");
269 return;
270 }
271
272 auto const outputFilename = localMatrixOutputFilename(*opt_prefix);
273 outputFile_.open(outputFilename);
274
275 if (!outputFile_)
276 {
277 OGS_FATAL(
278 "File `{}' for local matrix debug output could not be "
279 "opened.",
280 outputFilename);
281 }
282
283 DBUG("Successfully opened local matrix debug output file {}.",
284 outputFilename);
285}
286
288 double const t, int const process_id, std::size_t const element_id,
289 std::vector<double> const& local_M_data,
290 std::vector<double> const& local_K_data,
291 std::vector<double> const& local_b_data,
292 std::vector<double> const* const local_Jac_data)
293{
294 [[likely]] if (!isOutputRequested(element_id))
295 {
296 return;
297 }
298
299 std::lock_guard lock_guard{mutex_};
300
301 auto& fh = outputFile_;
302
303 DBUG("Writing to local matrix debug output file...");
304
305 fmt::print(fh, "## t = {:.15g}, process id = {}, element id = {}\n\n", t,
306 process_id, element_id);
307
308 if (!local_M_data.empty())
309 {
310 DBUG("... M");
311 fmt::print(fh, "# M\n{}\n\n", toSquareMatrixRowMajor(local_M_data));
312 }
313
314 if (!local_K_data.empty())
315 {
316 DBUG("... K");
317 fmt::print(fh, "# K\n{}\n\n", toSquareMatrixRowMajor(local_K_data));
318 }
319
320 if (!local_b_data.empty())
321 {
322 DBUG("... b");
323 fmt::print(fh, "# b\n{}\n\n", MathLib::toVector(local_b_data));
324 }
325
326 if (local_Jac_data && !local_Jac_data->empty())
327 {
328 DBUG("... Jac");
329 fmt::print(fh, "# Jac\n{}\n\n\n",
330 toSquareMatrixRowMajor(*local_Jac_data));
331 }
332}
333
334bool LocalMatrixOutput::isOutputRequested(std::size_t const element_id) const
335{
337}
338
340} // namespace ProcessLib::Assembly
#define OGS_FATAL(...)
Definition Error.h:26
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
IndexType getNumberOfColumns() const
return the number of columns
Definition EigenMatrix.h:55
void write(const std::string &filename) const
printout this matrix for debugging
IndexType getNumberOfRows() const
return the number of rows
Definition EigenMatrix.h:52
Global vector based on Eigen vector.
Definition EigenVector.h:25
IndexType size() const
return a vector length
Definition EigenVector.h:42
RawVectorType & getRawVector()
return a raw Eigen vector object
Eigen::Map< const Vector > toVector(std::vector< double > const &data, Eigen::VectorXd::Index size)
Creates an Eigen mapped vector from the given data vector.
std::unordered_set< std::size_t > parseSetOfSizeT(std::string const &str, std::string const &warn_msg)
std::function< bool(std::size_t)> createLocalMatrixOutputElementPredicate(std::string const &element_ids_str)
std::string localMatrixOutputFilename(std::string const &filenamePrefix)
Eigen::Map< const Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > > toSquareMatrixRowMajor(std::vector< double > entries)
static std::optional< std::string > getEnvironmentVariable(std::string const &env_var)
std::string getSeparatorAfterFilenamePrefix(std::string const &filenamePrefix)
void operator()(double const t, int const process_id, GlobalMatrix const &M, GlobalMatrix const &K, GlobalVector const &b, GlobalMatrix const *const Jac=nullptr)
bool isOutputRequested(std::size_t const element_id) const
std::function< bool(std::size_t)> output_element_predicate_
void operator()(double const t, int const process_id, std::size_t const element_id, std::vector< double > const &local_M_data, std::vector< double > const &local_K_data, std::vector< double > const &local_b_data, std::vector< double > const *const local_Jac_data=nullptr)