PolyFEM
Loading...
Searching...
No Matches
MatrixIO.cpp
Go to the documentation of this file.
1#include "MatrixIO.hpp"
2
4
5#include <igl/list_to_matrix.h>
6
7#include <iostream>
8#include <h5pp/h5pp.h>
9
10#include <fstream>
11#include <iomanip> // setprecision
12#include <limits>
13#include <vector>
14#include <filesystem>
15
16namespace polyfem::io
17{
18 template <typename T>
19 bool read_matrix(const std::string &path, Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &mat)
20 {
21 std::string extension = std::filesystem::path(path).extension().string();
22 std::transform(extension.begin(), extension.end(), extension.begin(),
23 [](unsigned char c) { return std::tolower(c); });
24
25 if (extension == ".txt")
26 {
27 return read_matrix_ascii(path, mat);
28 }
29 else if (extension == ".bin")
30 {
31 return read_matrix_binary(path, mat);
32 }
33 else
34 {
35 bool success = read_matrix_ascii(path, mat);
36 if (!success)
37 success = read_matrix_binary(path, mat); // Try with the binary format reader
38 return success;
39 }
40 }
41
42 template <typename Mat>
43 bool write_matrix(const std::string &path, const Mat &mat)
44 {
45 std::string extension = std::filesystem::path(path).extension().string();
46 std::transform(extension.begin(), extension.end(), extension.begin(),
47 [](unsigned char c) { return std::tolower(c); });
48
49 if (extension == ".txt")
50 {
51 return write_matrix_ascii(path, mat);
52 }
53 else if (extension == ".bin")
54 {
55 return write_matrix_binary(path, mat);
56 }
57 else
58 {
59 logger().warn("Uknown output matrix format (\"{}\"). Using ASCII format.");
60 return write_matrix_ascii(path, mat);
61 }
62 }
63
64 template <typename Mat>
65 bool write_matrix(const std::string &path, const std::string &key, const Mat &mat, const bool replace)
66 {
67 h5pp::File hdf5_file(path, replace ? h5pp::FileAccess::REPLACE : h5pp::FileAccess::READWRITE);
68 hdf5_file.writeDataset(mat, key);
69
70 return true;
71 }
72
73 template <typename Mat>
74 bool read_matrix(const std::string &path, const std::string &key, Mat &mat)
75 {
76 h5pp::File hdf5_file(path, h5pp::FileAccess::READONLY);
77 if (!hdf5_file.linkExists(key))
78 return false;
79 mat = hdf5_file.readDataset<Mat>(key);
80 return true;
81 }
82
83 template <typename T>
84 bool read_matrix_ascii(const std::string &path, Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &mat)
85 {
86 std::ifstream file(path);
87
88 if (!file.good())
89 {
90 logger().error("Failed to open file: {}", path);
91 file.close();
92
93 return false;
94 }
95
96 std::string s;
97 std::vector<std::vector<T>> matrix;
98
99 while (getline(file, s))
100 {
101 if (s.empty())
102 continue;
103 std::stringstream input(s);
104 T temp;
105 matrix.emplace_back();
106
107 std::vector<T> &currentLine = matrix.back();
108
109 while (true)
110 {
111 input >> std::ws;
112 if (input.eof())
113 break;
114 if (!(input >> temp))
115 return false; // Reject malformed or out-of-range values, not a partial row.
116 currentLine.push_back(temp);
117 }
118 if (currentLine.empty())
119 matrix.pop_back();
120 }
121 if (file.bad())
122 return false;
123
124 if (!igl::list_to_matrix(matrix, mat))
125 {
126 logger().error("list to matrix error");
127 file.close();
128
129 return false;
130 }
131
132 return true;
133 }
134
135 template <typename Mat>
136 bool write_matrix_ascii(const std::string &path, const Mat &mat)
137 {
138 std::ofstream out(path);
139 if (!out.good())
140 {
141 logger().error("Failed to write to file: {}", path);
142 out.close();
143
144 return false;
145 }
146
147 out.precision(15);
148 out << mat;
149 out.close();
150
151 return true;
152 }
153
154 template <typename T>
155 bool read_matrix_binary(const std::string &path, Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &mat)
156 {
157 typedef typename Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>::Index Index;
158
159 std::ifstream in(path, std::ios::in | std::ios::binary);
160 if (!in.good())
161 {
162 logger().error("Failed to open file: {}", path);
163 in.close();
164
165 return false;
166 }
167
168 Index rows = 0, cols = 0;
169 in.read((char *)(&rows), sizeof(Index));
170 in.read((char *)(&cols), sizeof(Index));
171 if (!in || rows < 0 || cols < 0
172 || (cols && rows > std::numeric_limits<Index>::max() / cols))
173 return false;
174 const uintmax_t count = uintmax_t(rows) * uintmax_t(cols);
175 if (count > (uintmax_t(std::numeric_limits<std::streamsize>::max()) - 2 * sizeof(Index)) / sizeof(T))
176 return false;
177 in.seekg(0, std::ios::end);
178 if (in.tellg() != std::streamoff(2 * sizeof(Index) + count * sizeof(T)))
179 return false;
180 in.seekg(2 * sizeof(Index));
181
182 mat.resize(rows, cols);
183 in.read((char *)mat.data(), rows * cols * sizeof(T));
184 const bool success = bool(in);
185 in.close();
186
187 return success;
188 }
189
190 template <typename Mat>
191 bool write_matrix_binary(const std::string &path, const Mat &mat)
192 {
193 typedef typename Mat::Index Index;
194 typedef typename Mat::Scalar Scalar;
195 std::ofstream out(path, std::ios::out | std::ios::binary);
196
197 if (!out.good())
198 {
199 logger().error("Failed to write to file: {}", path);
200 out.close();
201
202 return false;
203 }
204
205 const Index rows = mat.rows(), cols = mat.cols();
206 out.write((const char *)(&rows), sizeof(Index));
207 out.write((const char *)(&cols), sizeof(Index));
208 out.write((const char *)mat.data(), rows * cols * sizeof(Scalar));
209 out.close();
210
211 return true;
212 }
213
214 bool write_sparse_matrix_csv(const std::string &path, const Eigen::SparseMatrix<double> &mat)
215 {
216 std::ofstream csv(path, std::ios::out);
217
218 if (!csv.good())
219 {
220 logger().error("Failed to write to file: {}", path);
221 csv.close();
222
223 return false;
224 }
225
226 csv << std::setprecision(std::numeric_limits<long double>::digits10 + 2);
227
228 csv << fmt::format("shape,{},{}\n", mat.rows(), mat.cols());
229 csv << "Row,Col,Val\n";
230 for (int k = 0; k < mat.outerSize(); ++k)
231 {
232 for (Eigen::SparseMatrix<double>::InnerIterator it(mat, k); it; ++it)
233 {
234 csv << it.row() << "," // row index
235 << it.col() << "," // col index (here it is equal to k)
236 << it.value() << "\n";
237 }
238 }
239 csv.close();
240
241 return true;
242 }
243
244 template <typename T>
246 const std::string &path, const json &import, Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &mat)
247 {
248 bool success;
249 if (import.contains("offset"))
250 {
251 const int offset = import["offset"];
252
253 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> tmp;
254 success = read_matrix(path, tmp);
255 if (success)
256 {
257 assert(mat.rows() >= offset && mat.cols() >= 1);
258 mat.block(0, 0, offset, 1) = tmp.block(0, 0, offset, 1);
259 }
260 }
261 else
262 {
263 success = read_matrix(path, mat);
264 }
265 return success;
266 }
267
268 // template instantiation
269 template bool read_matrix<int>(const std::string &, Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> &);
270 template bool read_matrix<double>(const std::string &, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> &);
271 template bool read_matrix<long>(const std::string &, Eigen::Matrix<long, Eigen::Dynamic, Eigen::Dynamic> &);
272
273 template bool read_matrix<Eigen::MatrixXi>(const std::string &, const std::string &, Eigen::MatrixXi &);
274 template bool read_matrix<Eigen::MatrixXd>(const std::string &, const std::string &, Eigen::MatrixXd &);
275
276 template bool write_matrix<Eigen::MatrixXd>(const std::string &, const Eigen::MatrixXd &);
277 template bool write_matrix<Eigen::MatrixXf>(const std::string &, const Eigen::MatrixXf &);
278 template bool write_matrix<Eigen::VectorXd>(const std::string &, const Eigen::VectorXd &);
279 template bool write_matrix<Eigen::VectorXf>(const std::string &, const Eigen::VectorXf &);
280
281 template bool write_matrix<Eigen::MatrixXd>(const std::string &, const std::string &, const Eigen::MatrixXd &, const bool);
282 template bool write_matrix<Eigen::MatrixXf>(const std::string &, const std::string &, const Eigen::MatrixXf &, const bool);
283 template bool write_matrix<Eigen::VectorXd>(const std::string &, const std::string &, const Eigen::VectorXd &, const bool);
284 template bool write_matrix<Eigen::VectorXf>(const std::string &, const std::string &, const Eigen::VectorXf &, const bool);
285
286 template bool read_matrix_ascii<int>(const std::string &, Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> &);
287 template bool read_matrix_ascii<double>(const std::string &, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> &);
288 template bool read_matrix_ascii<long>(const std::string &, Eigen::Matrix<long, Eigen::Dynamic, Eigen::Dynamic> &);
289
290 template bool write_matrix_ascii<Eigen::MatrixXd>(const std::string &, const Eigen::MatrixXd &);
291 template bool write_matrix_ascii<Eigen::MatrixXf>(const std::string &, const Eigen::MatrixXf &);
292 template bool write_matrix_ascii<Eigen::VectorXd>(const std::string &, const Eigen::VectorXd &);
293 template bool write_matrix_ascii<Eigen::VectorXf>(const std::string &, const Eigen::VectorXf &);
294
295 template bool read_matrix_binary<int>(const std::string &, Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> &);
296 template bool read_matrix_binary<double>(const std::string &, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> &);
297 template bool read_matrix_binary<long>(const std::string &, Eigen::Matrix<long, Eigen::Dynamic, Eigen::Dynamic> &);
298
299 template bool write_matrix_binary<Eigen::MatrixXd>(const std::string &, const Eigen::MatrixXd &);
300 template bool write_matrix_binary<Eigen::MatrixXf>(const std::string &, const Eigen::MatrixXf &);
301 template bool write_matrix_binary<Eigen::VectorXd>(const std::string &, const Eigen::VectorXd &);
302 template bool write_matrix_binary<Eigen::VectorXf>(const std::string &, const Eigen::VectorXf &);
303
304 template bool import_matrix<int>(const std::string &path, const json &import, Eigen::MatrixXi &mat);
305 template bool import_matrix<double>(const std::string &path, const json &import, Eigen::MatrixXd &mat);
306
307} // namespace polyfem::io
template bool import_matrix< double >(const std::string &path, const json &import, Eigen::MatrixXd &mat)
template bool write_matrix< Eigen::VectorXd >(const std::string &, const Eigen::VectorXd &)
template bool read_matrix_binary< int >(const std::string &, Eigen::Matrix< int, Eigen::Dynamic, Eigen::Dynamic > &)
template bool write_matrix< Eigen::VectorXf >(const std::string &, const Eigen::VectorXf &)
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:19
template bool write_matrix_ascii< Eigen::VectorXd >(const std::string &, const Eigen::VectorXd &)
bool read_matrix_binary(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Definition MatrixIO.cpp:155
template bool read_matrix_ascii< long >(const std::string &, Eigen::Matrix< long, Eigen::Dynamic, Eigen::Dynamic > &)
template bool import_matrix< int >(const std::string &path, const json &import, Eigen::MatrixXi &mat)
template bool read_matrix< long >(const std::string &, Eigen::Matrix< long, Eigen::Dynamic, Eigen::Dynamic > &)
template bool write_matrix_binary< Eigen::MatrixXd >(const std::string &, const Eigen::MatrixXd &)
template bool write_matrix_binary< Eigen::MatrixXf >(const std::string &, const Eigen::MatrixXf &)
bool import_matrix(const std::string &path, const json &import, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Definition MatrixIO.cpp:245
template bool write_matrix_ascii< Eigen::MatrixXf >(const std::string &, const Eigen::MatrixXf &)
template bool write_matrix_binary< Eigen::VectorXd >(const std::string &, const Eigen::VectorXd &)
template bool write_matrix< Eigen::MatrixXf >(const std::string &, const Eigen::MatrixXf &)
bool write_matrix_binary(const std::string &path, const Mat &mat)
Definition MatrixIO.cpp:191
bool read_matrix_ascii(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Definition MatrixIO.cpp:84
template bool write_matrix< Eigen::MatrixXd >(const std::string &, const Eigen::MatrixXd &)
bool write_matrix_ascii(const std::string &path, const Mat &mat)
Definition MatrixIO.cpp:136
template bool read_matrix_binary< double >(const std::string &, Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > &)
template bool read_matrix_binary< long >(const std::string &, Eigen::Matrix< long, Eigen::Dynamic, Eigen::Dynamic > &)
template bool read_matrix< Eigen::MatrixXd >(const std::string &, const std::string &, Eigen::MatrixXd &)
bool write_sparse_matrix_csv(const std::string &path, const Eigen::SparseMatrix< double > &mat)
Definition MatrixIO.cpp:214
template bool read_matrix< int >(const std::string &, Eigen::Matrix< int, Eigen::Dynamic, Eigen::Dynamic > &)
template bool read_matrix< Eigen::MatrixXi >(const std::string &, const std::string &, Eigen::MatrixXi &)
template bool write_matrix_binary< Eigen::VectorXf >(const std::string &, const Eigen::VectorXf &)
template bool read_matrix< double >(const std::string &, Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > &)
template bool write_matrix_ascii< Eigen::VectorXf >(const std::string &, const Eigen::VectorXf &)
template bool read_matrix_ascii< double >(const std::string &, Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > &)
template bool read_matrix_ascii< int >(const std::string &, Eigen::Matrix< int, Eigen::Dynamic, Eigen::Dynamic > &)
template bool write_matrix_ascii< Eigen::MatrixXd >(const std::string &, const Eigen::MatrixXd &)
bool write_matrix(const std::string &path, const Mat &mat)
Writes a matrix to a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:43
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
nlohmann::json json
Definition Common.hpp:9