MaMiCo 1.2
Loading...
Searching...
No Matches
conversion.h
1// This file is part of the MaMiCo project. For conditions of distribution
2// and use, please see the copyright notice in MaMiCo's main folder
3
4#pragma once
5
6#include <array>
7#include <optional>
8#include <pybind11/numpy.h>
9#include <pybind11/pybind11.h>
10#include <stdexcept>
11#include <vector>
12
13/*
14 * Functions of this namespace provide conversion bewtween popular C++ and
15 * Python data structures. To be used by mamico.cpp
16 * @author Felix Maurer
17 */
18
19namespace py = pybind11;
20
21/*TODO:
22 * template for dim
23 * template for T
24 */
25namespace coupling {
26namespace conversion {
27
28// Converts 3-dimensional double vectors to numpy arrays
29// template<class T>
30py::array_t<double> stlVectorToNumpyArray_Scalar(const std::vector<double>& stl_vector, const std::vector<std::array<unsigned int, 3>>& indices) {
31 if (indices.empty() || stl_vector.empty())
32 throw std::runtime_error("One or more input vector is empty");
33
34 std::vector<unsigned int> shape{(indices.back()[0]) + 1, (indices.back()[1]) + 1, (indices.back()[2]) + 1};
35 py::array_t<double> res = py::array_t<double>(shape);
36 auto res_unchecked = res.mutable_unchecked<3>();
37
38 unsigned int c = 0;
39 for (unsigned int i = 0; i < shape[0]; i++)
40 for (unsigned int j = 0; j < shape[1]; j++)
41 for (unsigned int k = 0; k < shape[2]; k++) {
42 res_unchecked(i, j, k) = stl_vector[c];
43 c++;
44 }
45
46 return res;
47}
48
49// template<class T>
50py::array_t<double> stlVectorToNumpyArray_Vector(const std::vector<std::array<double, 3>>& stl_vector,
51 const std::vector<std::array<unsigned int, 3>>& indices) {
52 if (indices.empty() || stl_vector.empty())
53 throw std::runtime_error("One or more input vector is empty");
54
55 std::vector<unsigned int> shape({indices.back()[0] + 1, indices.back()[1] + 1, indices.back()[2] + 1, 3});
56 py::array_t<double> res = py::array_t<double>(shape);
57 auto res_unchecked = res.mutable_unchecked<4>();
58
59 unsigned int c = 0;
60 for (unsigned int i = 0; i < shape[0]; i++)
61 for (unsigned int j = 0; j < shape[1]; j++)
62 for (unsigned int k = 0; k < shape[2]; k++) {
63 res_unchecked(i, j, k, 0) = stl_vector[c][0];
64 res_unchecked(i, j, k, 1) = stl_vector[c][1];
65 res_unchecked(i, j, k, 2) = stl_vector[c][2];
66 c++;
67 }
68
69 return res;
70}
71
72// Other way around. Still restricted to 3 dimensions and double.
73// template<class T>
74std::vector<double> numpyArrayToStlVector_Scalar(const py::array_t<double>& numpy_array) {
75 if (numpy_array.ndim() != 3)
76 throw std::runtime_error("Input array must be of exactly 3 dimensions.");
77
78 std::vector<double> res;
79 auto np_unchecked = numpy_array.unchecked<3>();
80
81 for (unsigned int i = 0; i < numpy_array.shape(0); i++)
82 for (unsigned int j = 0; j < numpy_array.shape(1); j++)
83 for (unsigned int k = 0; k < numpy_array.shape(2); k++)
84 res.push_back(np_unchecked(i, j, k));
85
86 return res;
87}
88
89// template<class T>
90std::vector<std::array<double, 3>> numpyArrayToStlVector_Vector(const py::array_t<double>& numpy_array) {
91 if (numpy_array.ndim() != 4)
92 throw std::runtime_error("Input array must be of exactly 4 dimensions.");
93 if (numpy_array.shape(3) != 3)
94 throw std::runtime_error("Input array's 4th dimension must be {0..2}.");
95
96 std::vector<std::array<double, 3>> res;
97 auto np_unchecked = numpy_array.unchecked<4>();
98
99 for (unsigned int i = 0; i < numpy_array.shape(0); i++)
100 for (unsigned int j = 0; j < numpy_array.shape(1); j++)
101 for (unsigned int k = 0; k < numpy_array.shape(2); k++) {
102 std::array<double, 3> vec = {np_unchecked(i, j, k, 0), np_unchecked(i, j, k, 1), np_unchecked(i, j, k, 2)};
103 res.push_back(vec);
104 }
105
106 return res;
107}
108
109// template<class T>
110std::function<std::vector<double>(std::vector<double> /*stl_vector*/, std::vector<std::array<unsigned int, 3>> /*indices*/)>*
111functionWrapper_Scalar(std::function<py::array_t<double>(py::array_t<double>)>* py_func_ptr) {
112 // case: py_func exists
113 if (py_func_ptr) {
114 // create copy at current scope
115 auto py_func = *py_func_ptr;
116 return new std::function<std::vector<double>(std::vector<double> /*stl_vector*/, std::vector<std::array<unsigned int, 3>> /*indices*/)>{
117 [py_func](std::vector<double> stl_vector, std::vector<std::array<unsigned int, 3>> indices) {
118 py::array_t<double> np_input = conversion::stlVectorToNumpyArray_Scalar(stl_vector, indices);
119 py::array_t<double> np_output = py_func(np_input);
120 return conversion::numpyArrayToStlVector_Scalar(np_output);
121 }};
122 }
123 // case: py_func is "None"
124 else
125 return new std::function<std::vector<double>(std::vector<double> /*stl_vector*/, std::vector<std::array<unsigned int, 3>> /*indices*/)>{
126 [](std::vector<double> stl_vector, std::vector<std::array<unsigned int, 3>> indices) { return stl_vector; }};
127}
128
129// template<class T>
130std::function<std::vector<std::array<double, 3>>(std::vector<std::array<double, 3>> /*stl_vector*/, std::vector<std::array<unsigned int, 3>> /*indices*/)>*
131functionWrapper_Vector(std::function<py::array_t<double>(py::array_t<double>)>* py_func_ptr) {
132 // case: py_func exists
133 if (py_func_ptr) {
134 // create copy at current scope
135 auto py_func = *py_func_ptr;
136 return new std::function<std::vector<std::array<double, 3>>(std::vector<std::array<double, 3>> /*stl_vector*/,
137 std::vector<std::array<unsigned int, 3>> /*indices*/)>{
138 [py_func](std::vector<std::array<double, 3>> stl_vector, std::vector<std::array<unsigned int, 3>> indices) {
139 auto np_input = conversion::stlVectorToNumpyArray_Vector(stl_vector, indices);
140 auto np_output = py_func(np_input);
141 return conversion::numpyArrayToStlVector_Vector(np_output);
142 }};
143 }
144 // case: py_func is "None"
145 else
146 return new std::function<std::vector<std::array<double, 3>>(std::vector<std::array<double, 3>> /*stl_vector*/,
147 std::vector<std::array<unsigned int, 3>> /*indices*/)>{
148 [](std::vector<std::array<double, 3>> stl_vector, std::vector<std::array<unsigned int, 3>> indices) { return stl_vector; }};
149}
150} // namespace conversion
151} // namespace coupling
everything necessary for coupling operations, is defined in here
Definition AdditiveMomentumInsertion.h:15