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