forked from Argonne-National-Laboratory/neml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpyhelp.h
146 lines (127 loc) · 3.91 KB
/
pyhelp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#ifndef PYHELP_H
#define PYHELP_H
// To fix redef warnings
#include "Python.h"
#include "pybind11.h"
#include "numpy.h"
#include "stl.h"
#include <vector>
#include <algorithm>
#include <stdexcept>
#include "objects.h"
#include "interpolate.h"
#include "nemlerror.h"
namespace py = pybind11;
namespace neml {
// Convert an array to a pointer
template<class T> T* arr2ptr(py::array_t<T, py::array::c_style> arr)
{
return static_cast<T*>(arr.request().ptr);
}
// Allocate a new, zeroed vector
template<class T> py::array_t<T> alloc_vec(size_t n)
{
auto arr = py::array(py::buffer_info(
nullptr,
sizeof(T),
py::format_descriptor<T>::value,
1,
{n},
{sizeof(T)}
));
auto ptr = arr2ptr<T>(arr);
std::fill(ptr, ptr + n, 0);
return arr;
}
// Allocate a new, zeroed matrix
template<class T> py::array_t<T> alloc_mat(size_t m, size_t n)
{
auto arr = py::array(py::buffer_info(
nullptr,
sizeof(T),
py::format_descriptor<T>::value,
2,
{m, n},
{sizeof(T) * n, sizeof(T)}
));
auto ptr = arr2ptr<T>(arr);
std::fill(ptr, ptr + m * n, 0);
return arr;
}
/// Map a python object into a parameter from a set
void assign_python_parameter(ParameterSet & pset, std::string name,
py::object value)
{
switch (pset.get_object_type(name)) {
case TYPE_DOUBLE:
pset.assign_parameter(name, py::cast<double>(value));
break;
case TYPE_INT:
pset.assign_parameter(name, py::cast<int>(value));
break;
case TYPE_BOOL:
pset.assign_parameter(name, py::cast<bool>(value));
break;
case TYPE_VEC_DOUBLE:
pset.assign_parameter(name, py::cast<std::vector<double>>(value));
break;
case TYPE_NEML_OBJECT:
// If it's a double then we actually want a ConstantInterpolate
// I hate using exceptions here, but what I actually want is:
// "is this something that can be cast to a double"
// and not
// "is this actually a c++ double"
try {
double v = py::cast<double>(value);
pset.assign_parameter(name, std::make_shared<ConstantInterpolate>(v));
break;
}
catch (py::cast_error e) {
}
pset.assign_parameter(name, py::cast<std::shared_ptr<NEMLObject>>(value));
break;
case TYPE_VEC_NEML_OBJECT:
// If it's a vector<double> then we actually want a vector of
// ConstantInterpolates
try {
std::vector<double> v = py::cast<std::vector<double>>(value);
std::vector<std::shared_ptr<NEMLObject>> vect;
for (auto it = v.begin(); it != v.end(); ++it) {
vect.push_back(std::make_shared<ConstantInterpolate>(*it));
}
pset.assign_parameter(name, vect);
break;
}
catch (py::cast_error e) {
}
pset.assign_parameter(name, py::cast<std::vector<std::shared_ptr<NEMLObject>>>(value));
break;
case TYPE_STRING:
pset.assign_parameter(name, py::cast<std::string>(value));
break;
default:
throw std::runtime_error("Unrecognized object type!");
break;
}
}
/// Create an object from args and kwargs
template<typename T>
std::shared_ptr<T> create_object_python(py::args args, py::kwargs kwargs,
std::vector<std::string> names)
{
ParameterSet pset = Factory::Creator()->provide_parameters(T::type());
// The parameter names must map to each required arg
if (args.size() != names.size()) {
throw std::runtime_error("Each arg in args does not have a name in names.");
}
for (size_t i=0; i<args.size(); i++) {
assign_python_parameter(pset, names[i], args[i]);
}
for (auto item : kwargs) {
assign_python_parameter(pset, item.first.cast<std::string>(),
item.second.cast<py::object>());
}
return Factory::Creator()->create<T>(pset);
}
} // namespace neml
#endif // namespace neml