IgANet
IGAnets - Isogeometric Analysis Networks
Loading...
Searching...
No Matches
serialize.hpp
Go to the documentation of this file.
1
15#pragma once
16
17#include <iganet/core/core.hpp>
19
20#include <nlohmann/json.hpp>
21#include <pugixml.hpp>
22
23namespace iganet::utils {
24
31 virtual ~Serializable() = default;
32
35 virtual nlohmann::json to_json() const = 0;
36
39 virtual void pretty_print(std::ostream &os = Log(log::info)) const = 0;
40};
41
47template <typename T, std::size_t N>
48inline auto to_json(const torch::TensorAccessor<T, N> &accessor) {
49 auto json = nlohmann::json::array();
50
51 if constexpr (N == 1) {
52 for (int64_t i = 0; i < accessor.size(0); ++i)
53 json.push_back(accessor[i]);
54 } else if constexpr (N == 2) {
55 for (int64_t i = 0; i < accessor.size(0); ++i)
56 for (int64_t j = 0; j < accessor.size(1); ++j)
57 json.push_back(accessor[i][j]);
58 } else if constexpr (N == 3) {
59 for (int64_t i = 0; i < accessor.size(0); ++i)
60 for (int64_t j = 0; j < accessor.size(1); ++j)
61 for (int64_t k = 0; k < accessor.size(2); ++k)
62 json.push_back(accessor[i][j][k]);
63 } else if constexpr (N == 4) {
64 for (int64_t i = 0; i < accessor.size(0); ++i)
65 for (int64_t j = 0; j < accessor.size(1); ++j)
66 for (int64_t k = 0; k < accessor.size(2); ++k)
67 for (int64_t l = 0; l < accessor.size(3); ++l)
68 json.push_back(accessor[i][j][k][l]);
69 }
70
71 return json;
72}
73
79template <typename T, std::size_t N>
80inline auto to_json(const torch::Tensor &tensor) {
81 if (tensor.is_cuda()) {
82 auto [tensor_cpu, accessor] = to_tensorAccessor<T, N>(tensor, torch::kCPU);
83 return to_json(accessor);
84 } else {
85 auto accessor = to_tensorAccessor<T, N>(tensor);
86 return to_json(accessor);
87 }
88}
89
97template <typename T, std::size_t N, std::size_t M>
98inline auto to_json(const utils::TensorArray<M> &tensors) {
99 auto json = nlohmann::json::array();
100
101 for (std::size_t i = 0; i < M; ++i) {
102 if (tensors[i].is_cuda()) {
103 auto [tensor_cpu, accessor] =
104 to_tensorAccessor<T, N>(tensors[i], torch::kCPU);
105 json.push_back(to_json<T, N>(accessor));
106 } else {
107 auto accessor = to_tensorAccessor<T, N>(tensors[i]);
108 json.push_back(to_json<T, N>(accessor));
109 }
110 }
111
112 return json;
113}
114
115#ifdef IGANET_WITH_GISMO
117template <typename T, int Rows, int Cols, int Options>
118inline auto to_json(const gismo::gsMatrix<T, Rows, Cols, Options> &matrix,
119 bool flatten = false, bool transpose = false) {
120 auto json = nlohmann::json::array();
121
122 if constexpr (Options == gismo::RowMajor) {
123 if (flatten) {
124 if (transpose) {
125 for (std::size_t j = 0; j < matrix.cols(); ++j)
126 for (std::size_t i = 0; i < matrix.rows(); ++i)
127 json.push_back(matrix(i, j));
128 } else {
129 for (std::size_t i = 0; i < matrix.rows(); ++i)
130 for (std::size_t j = 0; j < matrix.cols(); ++j)
131 json.push_back(matrix(i, j));
132 }
133 } else {
134 if (transpose) {
135 for (std::size_t j = 0; j < matrix.cols(); ++j) {
136 auto data = nlohmann::json::array();
137 for (std::size_t i = 0; i < matrix.rows(); ++i) {
138 data.push_back(matrix(i, j));
139 }
140 json.emplace_back(data);
141 }
142 } else {
143 for (std::size_t i = 0; i < matrix.rows(); ++i) {
144 auto data = nlohmann::json::array();
145 for (std::size_t j = 0; j < matrix.cols(); ++j) {
146 data.push_back(matrix(i, j));
147 }
148 json.emplace_back(data);
149 }
150 }
151 }
152
153 } else if constexpr (Options == gismo::ColMajor) {
154 if (flatten) {
155 if (transpose) {
156 for (std::size_t i = 0; i < matrix.rows(); ++i)
157 for (std::size_t j = 0; j < matrix.cols(); ++j)
158 json.push_back(matrix(i, j));
159 } else {
160 for (std::size_t j = 0; j < matrix.cols(); ++j)
161 for (std::size_t i = 0; i < matrix.rows(); ++i)
162 json.push_back(matrix(i, j));
163 }
164 } else {
165 if (transpose) {
166 for (std::size_t i = 0; i < matrix.rows(); ++i) {
167 auto data = nlohmann::json::array();
168 for (std::size_t j = 0; j < matrix.cols(); ++j) {
169 data.push_back(matrix(i, j));
170 }
171 json.emplace_back(data);
172 }
173 } else {
174 for (std::size_t j = 0; j < matrix.cols(); ++j) {
175 auto data = nlohmann::json::array();
176 for (std::size_t i = 0; i < matrix.rows(); ++i) {
177 data.push_back(matrix(i, j));
178 }
179 json.emplace_back(data);
180 }
181 }
182 }
183
184 } else
185 throw std::runtime_error("Invalid matrix options");
186
187 return json;
188}
189
191template <typename T> inline auto to_json(const gismo::gsBSpline<T> &bspline) {
192 auto json = nlohmann::json();
193
194 json["degrees"] = nlohmann::json::array();
195
196 for (std::size_t i = 0; i < bspline.parDim(); ++i)
197 json["degrees"].push_back(bspline.degree(i));
198
199 json["geoDim"] = bspline.geoDim();
200 json["parDim"] = bspline.parDim();
201
202 json["ncoeffs"] = nlohmann::json::array();
203 for (std::size_t i = 0; i < bspline.parDim(); ++i)
204 json["ncoeffs"].push_back(bspline.basis().size(i));
205
206 json["coeffs"] = to_json(bspline.coefs());
207
208 json["nknots"] = nlohmann::json::array();
209 for (std::size_t i = 0; i < bspline.parDim(); ++i)
210 json["nknots"].push_back(bspline.knots(i).size());
211
212 json["knots"] = nlohmann::json::array();
213 for (std::size_t i = 0; i < bspline.parDim(); ++i)
214 json["knots"].push_back(bspline.knots(i));
215
216 return json;
217}
218
220template <int d, typename T>
221inline auto to_json(const gismo::gsTensorBSpline<d, T> &bspline) {
222 auto json = nlohmann::json();
223
224 json["degrees"] = nlohmann::json::array();
225
226 for (std::size_t i = 0; i < bspline.parDim(); ++i)
227 json["degrees"].push_back(bspline.degree(i));
228
229 json["geoDim"] = bspline.geoDim();
230 json["parDim"] = bspline.parDim();
231
232 json["ncoeffs"] = nlohmann::json::array();
233 for (std::size_t i = 0; i < bspline.parDim(); ++i)
234 json["ncoeffs"].push_back(bspline.basis().size(i));
235
236 json["coeffs"] = to_json(bspline.coefs());
237
238 json["nknots"] = nlohmann::json::array();
239 for (std::size_t i = 0; i < bspline.parDim(); ++i)
240 json["nknots"].push_back(bspline.knots(i).size());
241
242 json["knots"] = nlohmann::json::array();
243 for (std::size_t i = 0; i < bspline.parDim(); ++i)
244 json["knots"].push_back(bspline.knots(i));
245
246 return json;
247}
248
250template <typename T>
251inline auto to_json(const gismo::gsGeometry<T> &geometry) {
252
253 if (auto patch = dynamic_cast<const gismo::gsBSpline<T> *>(&geometry))
254 return to_json(*patch);
255 else if (auto patch =
256 dynamic_cast<const gismo::gsTensorBSpline<2, T> *>(&geometry))
257 return to_json(*patch);
258 else if (auto patch =
259 dynamic_cast<const gismo::gsTensorBSpline<3, T> *>(&geometry))
260 return to_json(*patch);
261 else if (auto patch =
262 dynamic_cast<const gismo::gsTensorBSpline<4, T> *>(&geometry))
263 return to_json(*patch);
264 else
265 return nlohmann::json("{ Invalid patch type }");
266}
267
269template <typename T>
270inline auto
271to_json(const typename gismo::gsMultiPatch<T>::ifContainer &interfaces) {
272
273 auto json = nlohmann::json::array();
274
275 for (auto const &interface : interfaces) {
276 auto interface_json = nlohmann::json();
277
278 interface_json["patches"] = {interface.first().patchIndex(),
279 interface.second().patchIndex()};
280 interface_json["sides"] = {interface.first().side().index(),
281 interface.second().side().index()};
282 interface_json["direction"] = "NOT IMPLEMENTED YET";
283 interface_json["orientation"] = "NOT IMPLEMENTED YET";
284
285 json.push_back(interface_json);
286 }
287
288 return json;
289}
290
292template <typename T>
293inline auto
294to_json(const typename gismo::gsMultiPatch<T>::bContainer &boundaries) {
295
296 auto json = nlohmann::json::array();
297
298 for (auto const &boundary : boundaries) {
299 auto boundary_json = nlohmann::json();
300
301 boundary_json["patch"] = boundary.patchIndex();
302 boundary_json["side"] = boundary.side().index();
303
304 json.push_back(boundary_json);
305 }
306
307 return json;
308}
309
311template <typename T>
312inline auto to_json(const gismo::gsMultiPatch<T> &mp, bool verbose = false) {
313
314 auto json = nlohmann::json();
315
316 // Create list of patch indices
317 auto patches_json = nlohmann::json::array();
318 for (std::size_t i = 0; i < mp.nPatches(); ++i)
319 patches_json.push_back(i);
320
321 json["patches"] = patches_json;
322 json["interfaces"] = to_json<T>(mp.interfaces());
323 json["boundaries"] = to_json<T>(mp.boundaries());
324
325 if (verbose) {
326 auto patches_json = nlohmann::json::array();
327
328 for (std::size_t i = 0; i < mp.nPatches(); ++i)
329 patches_json.push_back(to_json(mp.patch(i)));
330
331 json["patches"] = patches_json;
332 }
333
334 return json;
335}
336#endif
337
338template <typename T, std::size_t N>
339inline pugi::xml_node &to_xml(const torch::TensorAccessor<T, N> &accessor,
340 torch::IntArrayRef sizes, pugi::xml_node &root,
341 std::string tag = "Matrix", int id = 0,
342 const std::string &label = "", int index = -1);
343
354template <typename T, std::size_t N>
355inline pugi::xml_document to_xml(const torch::TensorAccessor<T, N> &accessor,
356 torch::IntArrayRef sizes,
357 std::string tag = "Matrix", int id = 0,
358 const std::string &label = "", int index = -1) {
359 pugi::xml_document doc;
360 pugi::xml_node root = doc.append_child("xml");
361 to_xml(accessor, sizes, root, tag, id, label, index);
362
363 return doc;
364}
365
377template <typename T, std::size_t N>
378inline pugi::xml_node &to_xml(const torch::TensorAccessor<T, N> &accessor,
379 torch::IntArrayRef sizes, pugi::xml_node &root,
380 std::string tag, int id, const std::string &label,
381 int index) {
382
383 // add node
384 pugi::xml_node node = root.append_child(tag.c_str());
385
386 if (id >= 0)
387 node.append_attribute("id") = id;
388
389 if (index >= 0)
390 node.append_attribute("index") = index;
391
392 if (!label.empty())
393 node.append_attribute("label") = label.c_str();
394
395 // add rows/cols or dimensions
396 if (tag == "Matrix") {
397 if constexpr (N == 1) {
398 node.append_attribute("rows") = sizes[0];
399 node.append_attribute("cols") = 1;
400
401 std::stringstream ss;
402 for (std::size_t i = 0; i < sizes[0]; ++i)
403 ss << std::to_string(accessor[i]) << (i < sizes[0] - 1 ? " " : "");
404 node.append_child(pugi::node_pcdata).set_value(ss.str().c_str());
405 } else if constexpr (N == 2) {
406 node.append_attribute("rows") = sizes[0];
407 node.append_attribute("cols") = sizes[1];
408
409 std::stringstream ss;
410 for (std::size_t i = 0; i < sizes[0]; ++i)
411 for (std::size_t j = 0; j < sizes[1]; ++j)
412 ss << std::to_string(accessor[i][j])
413 << (j < sizes[1] - 1 ? " " : (i < sizes[0] - 1 ? " " : ""));
414 node.append_child(pugi::node_pcdata).set_value(ss.str().c_str());
415 } else
416 throw std::runtime_error(
417 "Tag \"Matrix\" only supports 1- and 2-dimensional tensors");
418 } else {
419 std::stringstream ss;
420 for (const auto &size : sizes)
421 ss << std::to_string(size) << " ";
422
423 pugi::xml_node dims = node.append_child("Dimensions");
424 dims.append_child(pugi::node_pcdata).set_value(ss.str().c_str());
425
426 ss.str("");
427 if constexpr (N == 1) {
428 for (std::size_t i = 0; i < sizes[0]; ++i)
429 ss << std::to_string(accessor[i]) << " ";
430 } else if constexpr (N == 2) {
431 for (std::size_t i = 0; i < sizes[0]; ++i)
432 for (std::size_t j = 0; j < sizes[1]; ++j)
433 ss << std::to_string(accessor[i][j]) << " ";
434 } else if constexpr (N == 3) {
435 for (std::size_t i = 0; i < sizes[0]; ++i)
436 for (std::size_t j = 0; j < sizes[1]; ++j)
437 for (std::size_t k = 0; k < sizes[2]; ++k)
438 ss << std::to_string(accessor[i][j][k]) << " ";
439 } else if constexpr (N == 4) {
440 for (std::size_t i = 0; i < sizes[0]; ++i)
441 for (std::size_t j = 0; j < sizes[1]; ++j)
442 for (std::size_t k = 0; k < sizes[2]; ++k)
443 for (std::size_t l = 0; l < sizes[3]; ++l)
444 ss << std::to_string(accessor[i][j][k][l]) << " ";
445
446 } else if constexpr (N == 5) {
447 for (std::size_t i = 0; i < sizes[0]; ++i)
448 for (std::size_t j = 0; j < sizes[1]; ++j)
449 for (std::size_t k = 0; k < sizes[2]; ++k)
450 for (std::size_t l = 0; l < sizes[3]; ++l)
451 for (std::size_t m = 0; m < sizes[4]; ++m)
452 ss << std::to_string(accessor[i][j][k][l][m]) << " ";
453 } else if constexpr (N == 6) {
454 for (std::size_t i = 0; i < sizes[0]; ++i)
455 for (std::size_t j = 0; j < sizes[1]; ++j)
456 for (std::size_t k = 0; k < sizes[2]; ++k)
457 for (std::size_t l = 0; l < sizes[3]; ++l)
458 for (std::size_t m = 0; m < sizes[4]; ++m)
459 for (std::size_t n = 0; n < sizes[5]; ++n)
460 ss << std::to_string(accessor[i][j][k][l][m][n]) << " ";
461 } else
462 throw std::runtime_error(
463 "Dimensions higher than 6 are not implemented yet");
464
465 pugi::xml_node data = node.append_child("Data");
466 data.append_child(pugi::node_pcdata).set_value(ss.str().c_str());
467 }
468
469 return root;
470}
471
472template <typename T, std::size_t N>
473inline pugi::xml_node &to_xml(const torch::Tensor &tensor,
474 pugi::xml_node &root,
475 std::string tag = "Matrix", int id = 0,
476 const std::string &label = "", int index = -1);
477
487template <typename T, std::size_t N>
488inline pugi::xml_document to_xml(const torch::Tensor &tensor,
489 std::string tag = "Matrix", int id = 0,
490 const std::string &label = "", int index = -1) {
491 pugi::xml_document doc;
492 pugi::xml_node root = doc.append_child("xml");
493 to_xml<T, N>(tensor, root, tag, id, label, index);
494
495 return doc;
496}
497
508template <typename T, std::size_t N>
509inline pugi::xml_node &to_xml(const torch::Tensor &tensor, pugi::xml_node &root,
510 std::string tag, int id, const std::string &label,
511 int index) {
512
513 if (tensor.is_cuda()) {
514 auto [tensor_cpu, accessor] = to_tensorAccessor<T, N>(tensor, torch::kCPU);
515 return to_xml(accessor, tensor.sizes(), root, tag, id, label, index);
516 } else {
517 auto accessor = to_tensorAccessor<T, N>(tensor);
518 return to_xml(accessor, tensor.sizes(), root, tag, id, label, index);
519 }
520}
521
522template <typename T, std::size_t N, std::size_t M>
523inline pugi::xml_node &to_xml(const utils::TensorArray<M> &tensors,
524 pugi::xml_node &root,
525 std::string tag = "Matrix", int id = 0,
526 const std::string &label = "");
527
539template <typename T, std::size_t N, std::size_t M>
540inline pugi::xml_document to_xml(const utils::TensorArray<M> &tensors,
541 std::string tag = "Matrix", int id = 0,
542 const std::string &label = "", int index = -1) {
543 pugi::xml_document doc;
544 pugi::xml_node root = doc.append_child("xml");
545 to_xml<T, N>(tensors, root, tag, id, label);
546
547 return doc;
548}
549
561template <typename T, std::size_t N, std::size_t M>
562inline pugi::xml_node &to_xml(const utils::TensorArray<M> &tensors,
563 pugi::xml_node &root, std::string tag, int id,
564 const std::string &label) {
565
566 for (std::size_t i = 0; i < M; ++i) {
567 if (tensors[i].is_cuda()) {
568 auto [tensor_cpu, accessor] =
569 to_tensorAccessor<T, N>(tensors[i], torch::kCPU);
570 to_xml(accessor, tensors[i].sizes(), root, tag, id, label, i);
571 } else {
572 auto accessor = to_tensorAccessor<T, N>(tensors[i]);
573 to_xml(accessor, tensors[i].sizes(), root, tag, id, label, i);
574 }
575 }
576
577 return root;
578}
579
591template <typename T, std::size_t N>
592inline torch::TensorAccessor<T, N> &
593from_xml(const pugi::xml_document &doc, torch::TensorAccessor<T, N> &accessor,
594 torch::IntArrayRef sizes, std::string tag = "Matrix", int id = 0,
595 const std::string &label = "", int index = -1) {
596 return from_xml(doc.child("xml"), accessor, sizes, tag, id, label, index);
597}
598
610template <typename T, std::size_t N>
611inline torch::TensorAccessor<T, N> &
612from_xml(const pugi::xml_node &root, torch::TensorAccessor<T, N> &accessor,
613 torch::IntArrayRef sizes, std::string tag = "Matrix", int id = 0,
614 const std::string &label = "", int index = -1) {
615
616 return accessor;
617}
618
619template <typename T, std::size_t N>
620inline torch::Tensor &from_xml(const pugi::xml_node &root,
621 torch::Tensor &tensor,
622 std::string tag = "Matrix", int id = 0,
623 const std::string &label = "", bool alloc = true,
624 int index = -1);
625
637template <typename T, std::size_t N>
638inline torch::Tensor &
639from_xml(const pugi::xml_document &doc, torch::Tensor &tensor,
640 std::string tag = "Matrix", int id = 0,
641 const std::string &label = "",
642 bool alloc = true, int index = -1) {
643 return from_xml<T, N>(doc.child("xml"), tensor, tag, id, label, alloc,
644 index);
645}
646
658template <typename T, std::size_t N>
659inline torch::Tensor &
660from_xml(const pugi::xml_node &root, torch::Tensor &tensor,
661 std::string tag, int id, const std::string &label, bool alloc,
662 int index) {
663
664 // Loop through all nodes
665 for (pugi::xml_node node : root.children(tag.c_str())) {
666
667 if ((id >= 0 ? node.attribute("id").as_int() == id : true) &&
668 (index >= 0 ? node.attribute("index").as_int() == index : true) &&
669 (!label.empty() ? node.attribute("label").value() == label : true)) {
670
671 if (tag == "Matrix") {
672
673 int64_t rows = node.attribute("rows").as_int();
674 int64_t cols = node.attribute("cols").as_int();
675
676 if constexpr (N == 1) {
677 if (cols != 1)
678 throw std::runtime_error("Invalid matrix dimensions");
679 if (!alloc && (tensor.dim() != 1 || tensor.size(0) != rows))
680 throw std::runtime_error("Invalid matrix dimensions");
681 if (alloc && (tensor.dim() != 1 || tensor.size(0) != rows))
682 tensor = torch::zeros({rows}, tensor.options());
683 } else if constexpr (N == 2) {
684 if (!alloc &&
685 (tensor.dim() != 2 || tensor.size(0) != rows ||
686 tensor.size(1) != cols))
687 throw std::runtime_error("Invalid matrix dimensions");
688 if (alloc &&
689 (tensor.dim() != 2 || tensor.size(0) != rows ||
690 tensor.size(1) != cols))
691 tensor = torch::zeros({rows, cols}, tensor.options());
692 } else {
693 throw std::runtime_error(
694 "Tag \"Matrix\" only supports 1- and 2-dimensional tensors");
695 }
696
697 std::string values = std::regex_replace(
698 node.text().get(), std::regex("[\t\r\n\a]+| +"), " ");
699
700 auto [tensor_cpu, accessor] =
701 to_tensorAccessor<T, N>(tensor, torch::kCPU);
702 auto value = strtok(&values[0], " ");
703
704 if constexpr (N == 1) {
705 for (int64_t i = 0; i < rows; ++i) {
706 if (value == nullptr)
707 throw std::runtime_error(
708 "XML object does not provide enough coefficients");
709 accessor[i] = static_cast<T>(std::stod(value));
710 value = strtok(nullptr, " ");
711 }
712 } else if constexpr (N == 2) {
713 for (int64_t i = 0; i < rows; ++i)
714 for (int64_t j = 0; j < cols; ++j) {
715 if (value == nullptr)
716 throw std::runtime_error(
717 "XML object does not provide enough coefficients");
718 accessor[i][j] = static_cast<T>(std::stod(value));
719 value = strtok(nullptr, " ");
720 }
721 }
722
723 if (value != nullptr)
724 throw std::runtime_error("XML object provides too many coefficients");
725
726 if (tensor.device().type() != torch::kCPU)
727 tensor = std::move(tensor_cpu);
728
729 return tensor;
730
731 } else {
732
733 // Check for "Dimensions"
734 if (pugi::xml_node dims = node.child("Dimensions")) {
735 std::vector<int64_t> sizes;
736
737 std::string values = std::regex_replace(
738 dims.text().get(), std::regex("[\t\r\n\a]+| +"), " ");
739 for (auto value = strtok(&values[0], " "); value != nullptr;
740 value = strtok(nullptr, " "))
741 sizes.push_back(static_cast<std::size_t>(std::stoi(value)));
742
743 if (!alloc && (tensor.sizes() != sizes))
744 throw std::runtime_error("Invalid tensor dimensions");
745
746 else if (alloc && (tensor.sizes() != sizes))
747 tensor = torch::zeros(torch::IntArrayRef{sizes}, tensor.options());
748
749 if (sizes.size() != N)
750 throw std::runtime_error("Invalid tensor dimensions");
751
752 // Check for "Data"
753 if (pugi::xml_node data = node.child("Data")) {
754 std::string values = std::regex_replace(
755 data.text().get(), std::regex("[\t\r\n\a]+| +"), " ");
756
757 auto [tensor_cpu, accessor] =
758 to_tensorAccessor<T, N>(tensor, torch::kCPU);
759 auto value = strtok(&values[0], " ");
760
761 if constexpr (N == 1) {
762 for (int64_t i = 0; i < sizes[0]; ++i) {
763 if (value == nullptr)
764 throw std::runtime_error(
765 "XML object does not provide enough coefficients");
766
767 accessor[i] = static_cast<T>(std::stod(value));
768 value = strtok(nullptr, " ");
769 }
770 } else if constexpr (N == 2) {
771 for (int64_t i = 0; i < sizes[0]; ++i)
772 for (int64_t j = 0; j < sizes[1]; ++j) {
773 if (value == nullptr)
774 throw std::runtime_error(
775 "XML object does not provide enough coefficients");
776
777 accessor[i][j] = static_cast<T>(std::stod(value));
778 value = strtok(nullptr, " ");
779 }
780 } else if constexpr (N == 3) {
781 for (int64_t i = 0; i < sizes[0]; ++i)
782 for (int64_t j = 0; j < sizes[1]; ++j)
783 for (int64_t k = 0; k < sizes[2]; ++k) {
784 if (value == nullptr)
785 throw std::runtime_error(
786 "XML object does not provide enough coefficients");
787
788 accessor[i][j][k] = static_cast<T>(std::stod(value));
789 value = strtok(nullptr, " ");
790 }
791 } else if constexpr (N == 4) {
792 for (int64_t i = 0; i < sizes[0]; ++i)
793 for (int64_t j = 0; j < sizes[1]; ++j)
794 for (int64_t k = 0; k < sizes[2]; ++k)
795 for (int64_t l = 0; l < sizes[3]; ++l) {
796 if (value == nullptr)
797 throw std::runtime_error(
798 "XML object does not provide enough coefficients");
799
800 accessor[i][j][k][l] = static_cast<T>(std::stod(value));
801 value = strtok(nullptr, " ");
802 }
803 } else if constexpr (N == 5) {
804 for (int64_t i = 0; i < sizes[0]; ++i)
805 for (int64_t j = 0; j < sizes[1]; ++j)
806 for (int64_t k = 0; k < sizes[2]; ++k)
807 for (int64_t l = 0; l < sizes[3]; ++l)
808 for (int64_t m = 0; m < sizes[4]; ++m) {
809 if (value == nullptr)
810 throw std::runtime_error(
811 "XML object does not provide enough "
812 "coefficients");
813
814 accessor[i][j][k][l][m] =
815 static_cast<T>(std::stod(value));
816 value = strtok(nullptr, " ");
817 }
818 } else if constexpr (N == 6) {
819 for (int64_t i = 0; i < sizes[0]; ++i)
820 for (int64_t j = 0; j < sizes[1]; ++j)
821 for (int64_t k = 0; k < sizes[2]; ++k)
822 for (int64_t l = 0; l < sizes[3]; ++l)
823 for (int64_t m = 0; m < sizes[4]; ++m)
824 for (int64_t n = 0; n < sizes[5]; ++n) {
825 if (value == nullptr)
826 throw std::runtime_error(
827 "XML object does not provide enough "
828 "coefficients");
829
830 accessor[i][j][k][l][m][n] =
831 static_cast<T>(std::stod(value));
832 value = strtok(nullptr, " ");
833 }
834 }
835
836 if (value != nullptr)
837 throw std::runtime_error(
838 "XML object provides too many coefficients");
839
840 if (tensor.device().type() != torch::kCPU)
841 tensor = std::move(tensor_cpu);
842
843 return tensor;
844 } // "Data"
845 } // "Dimenions"
846
847 throw std::runtime_error(
848 "XML object does not provide a \"Dimensions\" tag");
849
850 return tensor;
851 }
852
853 } // try next node
854 } // "tag"
855
856 throw std::runtime_error(
857 "XML object does not provide tag with given id, index, and/or label");
858 return tensor;
859}
860
861template <typename T, std::size_t N, std::size_t M>
863from_xml(const pugi::xml_node &root, utils::TensorArray<M> &tensors,
864 std::string tag = "Matrix", int id = 0, bool alloc = true,
865 const std::string &label = "");
866
879template <typename T, std::size_t N, std::size_t M>
881from_xml(const pugi::xml_document &doc, utils::TensorArray<M> &tensors,
882 std::string tag = "Matrix", int id = 0, bool alloc = true,
883 const std::string &label = "") {
884
885 return from_xml<T, N>(doc.child("xml"), tensors, tag, id, alloc, label);
886}
887
899template <typename T, std::size_t N, std::size_t M>
901from_xml(const pugi::xml_node &root, utils::TensorArray<M> &tensors,
902 std::string tag, int id, bool alloc, const std::string &label) {
903
904 for (std::size_t i = 0; i < M; ++i) {
905 from_xml<T, N>(root, tensors[i], tag, id, label, alloc, i);
906 }
907
908 return tensors;
909}
910
911} // namespace iganet::utils
The Options class handles the automated determination of dtype from the template argument and the sel...
Definition options.hpp:47
Core components.
Definition blocktensor.hpp:24
auto to_json(const torch::TensorAccessor< T, N > &accessor)
Converts a torch::TensorAccessor object to a JSON object.
Definition serialize.hpp:48
pugi::xml_node & to_xml(const torch::TensorAccessor< T, N > &accessor, torch::IntArrayRef sizes, pugi::xml_node &root, std::string tag="Matrix", int id=0, const std::string &label="", int index=-1)
Converts a torch::TensorAccessor object to an XML object.
Definition serialize.hpp:378
std::array< torch::Tensor, N > TensorArray
Definition tensorarray.hpp:26
torch::TensorAccessor< T, N > & from_xml(const pugi::xml_document &doc, torch::TensorAccessor< T, N > &accessor, torch::IntArrayRef sizes, std::string tag="Matrix", int id=0, const std::string &label="", int index=-1)
Converts an XML document object to a torch::TensorAccessor object.
Definition serialize.hpp:593
struct iganet::@0 Log
Logger.
Serialization prototype.
Definition serialize.hpp:29
virtual void pretty_print(std::ostream &os=Log(log::info)) const =0
Returns a string representation of the object.
virtual nlohmann::json to_json() const =0
Returns the object as JSON object.
virtual ~Serializable()=default
Destructor.
TensorArray utility functions.