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