1
/* This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus
3
* MAUS is free software: you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation, either version 3 of the License, or
6
* (at your option) any later version.
8
* MAUS is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with MAUS. If not, see <http://www.gnu.org/licenses/>.
18
// These ifdefs are required to avoid cpp compiler warning
19
#ifdef _POSIX_C_SOURCE
20
#undef _POSIX_C_SOURCE
28
#include <structmember.h>
36
#include "src/legacy/Config/MiceModule.hh"
38
#include "src/common_cpp/Utils/Exception.hh"
40
#define MAUS_PYMICEMODULE_CC
41
#include "src/py_cpp/PyMiceModule.hh"
42
#undef MAUS_PYMICEMODULE_CC
45
namespace PyMiceModule {
48
std::string get_name_docstring =
49
std::string("Get the name of this MiceModule\n\n")+
50
std::string(" Takes no arguments.\n")+
51
std::string("Returns a python string containing the module name.");
53
PyObject *get_name(PyObject* self, PyObject *args, PyObject *kwds) {
54
MiceModule* mod = C_API::get_mice_module(self);
55
PyObject* py_string = PyString_FromString(mod->name().c_str());
60
std::string get_property_docstring =
61
std::string("Returns the value of a particular MiceModule property\n\n")+
62
std::string(" - name (string) name of the property\n")+
63
std::string(" - type (string) type of the property\n")+
64
std::string("Returns a value of the appropriate type");
66
PyObject* get_bool(MiceModule* mod, std::string name) {
68
bool out = mod->propertyBoolThis(name);
69
int out_int = out ? 1 : 0; // ooh I feel so dirty
70
PyObject* py_out = Py_BuildValue("b", out_int);
73
} catch(std::exception& exc) {
74
PyErr_SetString(PyExc_KeyError, (&exc)->what());
79
PyObject* get_int(MiceModule* mod, std::string name) {
81
int out = mod->propertyIntThis(name);
82
PyObject* py_out = Py_BuildValue("i", out);
85
} catch(std::exception& exc) {
86
PyErr_SetString(PyExc_KeyError, (&exc)->what());
91
PyObject* get_double(MiceModule* mod, std::string name) {
93
double out = mod->propertyDoubleThis(name);
94
PyObject* py_out = Py_BuildValue("d", out);
97
} catch(std::exception& exc) {
98
PyErr_SetString(PyExc_KeyError, (&exc)->what());
103
PyObject* get_string(MiceModule* mod, std::string name) {
105
std::string out = mod->propertyStringThis(name);
106
PyObject* py_out = Py_BuildValue("s", out.c_str());
109
} catch(std::exception& exc) {
110
PyErr_SetString(PyExc_KeyError, (&exc)->what());
115
PyObject* get_hep3vector(MiceModule* mod, std::string name) {
117
CLHEP::Hep3Vector out = mod->propertyHep3VectorThis(name);
118
PyObject* py_out = PyDict_New();
120
PyObject* x = Py_BuildValue("d", out[0]);
122
PyObject* y = Py_BuildValue("d", out[1]);
124
PyObject* z = Py_BuildValue("d", out[2]);
126
PyDict_SetItemString(py_out, "x", x);
127
PyDict_SetItemString(py_out, "y", y);
128
PyDict_SetItemString(py_out, "z", z);
130
} catch(std::exception& exc) {
131
PyErr_SetString(PyExc_KeyError, (&exc)->what());
136
PyObject *get_property(PyObject* self, PyObject *args, PyObject *kwds) {
137
MiceModule* mod = C_API::get_mice_module(self);
139
PyErr_SetString(PyExc_TypeError,
140
"MiceModule was not properly initialised");
143
const char* name = NULL;
144
const char* c_type = NULL;
145
static char *kwlist[] = {const_cast<char*>("name"),
146
const_cast<char*>("type"), NULL};
147
if (!PyArg_ParseTupleAndKeywords
148
(args, kwds, "ss|", kwlist, &name, &c_type)) {
151
// convert type to lower case
152
std::string type(c_type);
153
for (size_t i = 0; i < type.size(); ++i) {
154
type[i] = std::tolower(type[i]);
157
if (type == "bool" || type == "boolean") {
158
return get_bool(mod, name);
159
} else if (type == "int") {
160
return get_int(mod, name);
161
} else if (type == "string") {
162
return get_string(mod, name);
163
} else if (type == "double") {
164
return get_double(mod, name);
165
} else if (type == "hep3vector") {
166
return get_hep3vector(mod, name);
168
std::stringstream message;
169
message << "Did not recognise type '" << type << "' ";
170
message << " - should be one of bool, int, string, double, hep3vector";
171
PyErr_SetString(PyExc_TypeError, message.str().c_str());
176
bool set_property_hep3vector_one
177
(PyObject* py_dict, std::string dim, double* value) {
178
// py_value is borrowed ref
179
PyObject* py_value = PyDict_GetItemString(py_dict, dim.c_str());
181
PyErr_SetString(PyExc_KeyError,
182
"could not find x, y and z in hep3vector dictionary");
185
if (!PyArg_Parse(py_value, "d", value)) {
186
std::string err = "value['"+dim+"'] could not be converted to a number";
187
PyErr_SetString(PyExc_TypeError, err.c_str());
193
PyObject* set_property_hep3vector
194
(MiceModule* mod, std::string name, PyObject* py_value) {
195
CLHEP::Hep3Vector value;
196
if (!PyDict_Check(py_value)) {
197
PyErr_SetString(PyExc_TypeError,
198
"Failed to resolve Hep3Vector as a dict");
201
if (!set_property_hep3vector_one(py_value, "x", &value[0])) return NULL;
202
if (!set_property_hep3vector_one(py_value, "y", &value[1])) return NULL;
203
if (!set_property_hep3vector_one(py_value, "z", &value[2])) return NULL;
204
mod->setProperty(name, value);
206
return Py_None; // all is well
209
std::string set_property_docstring =
210
std::string("Sets the value of a particular MiceModule property\n\n")+
211
std::string(" - name (string) name of the property\n")+
212
std::string(" - type (string) type of the property\n")+
213
std::string(" - value (type) value to be set - should be convertible to\n")+
214
std::string(" the appropriate type\n")+
215
std::string("Returns None");
217
PyObject *set_property(PyObject* self, PyObject *args, PyObject *kwds) {
218
MiceModule* mod = C_API::get_mice_module(self);
220
PyErr_SetString(PyExc_TypeError,
221
"MiceModule was not properly initialised");
224
const char* name = NULL;
225
const char* c_type = NULL;
226
PyObject* py_value = NULL;
227
static char *kwlist[] = {const_cast<char*>("name"),
228
const_cast<char*>("type"),
229
const_cast<char*>("value"), NULL};
230
if (!PyArg_ParseTupleAndKeywords
231
(args, kwds, "ssO|", kwlist, &name, &c_type, &py_value)) {
234
// convert type to lower case
235
std::string type(c_type);
236
for (size_t i = 0; i < type.size(); ++i) {
237
type[i] = std::tolower(type[i]);
240
if (type == "bool" || type == "boolean") {
242
if (PyArg_Parse(py_value, "i", &value))
243
mod->setProperty(name, value != 0);
246
} else if (type == "int") {
248
if (PyArg_Parse(py_value, "i", &value))
249
mod->setProperty(name, value);
252
} else if (type == "string") {
254
if (PyArg_Parse(py_value, "s", &value))
255
mod->setProperty(name, std::string(value));
258
} else if (type == "double") {
260
if (PyArg_Parse(py_value, "d", &value))
261
mod->setProperty(name, value);
264
} else if (type == "hep3vector") {
265
return set_property_hep3vector(mod, name, py_value);
267
std::stringstream message;
268
message << "Did not recognise type '" << type << "' ";
269
message << " - should be one of bool, int, string, double, hep3vector";
270
PyErr_SetString(PyExc_TypeError, message.str().c_str());
277
std::string get_children_docstring =
278
std::string("Get child modules of this MiceModule\n\n")+
279
std::string(" Takes no arguments.\n")+
280
std::string("Returns a python list containing a deep copy of all child\n")+
281
std::string("MiceModules.");
283
PyObject *get_children(PyObject* self, PyObject *args, PyObject *kwds) {
284
MiceModule* mod = C_API::get_mice_module(self);
285
std::vector<MiceModule*> daughter_list = mod->allDaughters();
286
PyObject* py_list = PyList_New(daughter_list.size());
288
for (size_t i = 0; i < daughter_list.size(); ++i) {
289
if (daughter_list[i] == NULL) {
290
PyErr_SetString(PyExc_RuntimeError, "Could not find MiceModule");
293
PyObject* py_mod = C_API::create_empty_module();
295
MiceModule* new_child = MiceModule::deepCopy(*daughter_list[i], false);
296
C_API::set_mice_module(py_mod, new_child);
297
PyList_SetItem(py_list, i, py_mod);
303
bool will_circle(const MiceModule* ancestor, const MiceModule* child) {
304
if (ancestor == NULL)
306
else if (ancestor == child)
309
return will_circle(ancestor->mother(), child);
312
std::string set_children_docstring =
313
std::string("Set child modules of this MiceModule\n\n")+
314
std::string(" - children (list) list of MiceModule objects. The existing\n")+
315
std::string(" children will be replaced by deep copies of those in the\n")+
316
std::string(" list. The parent module of the children is updated to this\n")+
317
std::string(" MiceModule.\n")+
318
std::string("Returns None.");
320
PyObject *set_children(PyObject* self, PyObject *args, PyObject *kwds) {
321
MiceModule* mod = C_API::get_mice_module(self);
325
PyObject* py_children = NULL;
326
static char *kwlist[] = {const_cast<char*>("children"), NULL};
327
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|", kwlist, &py_children)) {
330
if (!PyList_Check(py_children)) {
331
PyErr_SetString(PyExc_TypeError, "Argument should be a list");
334
std::vector<MiceModule*> children;
335
for (int i = 0; i < PyList_Size(py_children); ++i) {
336
PyObject* py_child = PyList_GetItem(py_children, i);
337
MiceModule* child = C_API::get_mice_module(py_child);
339
PyErr_SetString(PyExc_TypeError,
340
"List object was not a MiceModule");
341
return NULL; // no memory allocated and module unchanged
343
children.push_back(MiceModule::deepCopy(*child, false));
345
while (mod->allDaughters().size() > 0) {
346
mod->allDaughters()[0]->setMother(NULL);
347
delete mod->allDaughters()[0];
348
mod->removeDaughter(mod->allDaughters()[0]);
350
for (size_t i = 0; i < children.size(); ++i) {
351
mod->addDaughter(children[i]);
352
children[i]->setMother(mod);
359
PyObject *_alloc(PyTypeObject *type, Py_ssize_t nitems) {
360
void* void_mod = malloc(sizeof(PyMiceModule));
361
PyMiceModule* mod = reinterpret_cast<PyMiceModule*>(void_mod);
365
return reinterpret_cast<PyObject*>(mod);
368
int _init(PyObject* self, PyObject *args, PyObject *kwds) {
369
PyMiceModule* mod = reinterpret_cast<PyMiceModule*>(self);
370
// failed to cast or self was not initialised - something horrible happened
372
PyErr_SetString(PyExc_TypeError,
373
"Failed to resolve self as PyMiceModule in __init__");
376
// legal python to call initialised_object.__init__() to reinitialise, so
378
if (mod->mod != NULL) {
382
static char *kwlist[] = {const_cast<char*>("file_name"), NULL};
383
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist, &file_name)) {
388
mod->mod = new MiceModule(std::string(file_name));
389
} catch(std::exception& exc) {
390
PyErr_SetString(PyExc_ValueError, (&exc)->what());
396
void _free(PyMiceModule * self) {
398
if (self->mod != NULL && self->mod->mother() == NULL)
404
PyObject* _str(PyObject * self) {
405
MiceModule* mod = C_API::get_mice_module(self);
407
PyErr_SetString(PyExc_TypeError,
408
"MiceModule was not properly initialised");
411
std::stringstream ss_in;
412
mod->printThis(ss_in);
413
return PyString_FromString(ss_in.str().c_str());
416
const char* module_docstring =
417
"mice_module for geometry and field definitions including MiceModule class";
419
std::string class_docstring_str =
420
std::string("MiceModule provides bindings for defining geometries.\n\n")+
422
std::string("MiceModules are representations of the MAUS geometry and.\n")+
423
std::string("fields. They are structured as a tree; for now the tree is\n")+
424
std::string("mono-directional. Each level of the tree holds properties that\n")+
425
std::string("reflect the geometry objects at that level and child modules\n")+
426
std::string("that can be used to access lower level geometry objects. \n")+
428
std::string("See MAUS documentation chapter \"How to Define a Geometry\".\n")+
430
std::string("__init__(file_name)\n")+
431
std::string(" Constructor for a new MiceModule.\n")+
432
std::string(" - file_name (string) name of the file from which to read\n")+
433
std::string(" the MiceModule file. Either a path relative to the current\n")+
434
std::string(" directory or relative to the")+
435
std::string(" ${MICEFILES}/Models/Configurations/\n")+
436
std::string(" environment variable\n")+
437
std::string(" Returns a MiceModule object\n");
438
const char* class_docstring = class_docstring_str.c_str();
440
static PyMemberDef _members[] = {
444
static PyMethodDef _methods[] = {
445
{"get_name", (PyCFunction)get_name,
446
METH_VARARGS|METH_KEYWORDS, get_name_docstring.c_str()},
447
{"set_children", (PyCFunction)set_children,
448
METH_VARARGS|METH_KEYWORDS, set_children_docstring.c_str()},
449
{"get_children", (PyCFunction)get_children,
450
METH_VARARGS|METH_KEYWORDS, get_children_docstring.c_str()},
451
{"get_property", (PyCFunction)get_property,
452
METH_VARARGS|METH_KEYWORDS, get_property_docstring.c_str()},
453
{"set_property", (PyCFunction)set_property,
454
METH_VARARGS|METH_KEYWORDS, set_property_docstring.c_str()},
458
static PyTypeObject PyMiceModuleType = {
459
PyObject_HEAD_INIT(NULL)
461
"mice_module.MiceModule", /*tp_name*/
462
sizeof(PyMiceModule), /*tp_basicsize*/
464
(destructor)_free, /*tp_dealloc*/
471
0, /*tp_as_sequence*/
479
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
480
class_docstring, /* tp_doc */
483
0, /* tp_richcompare */
484
0, /* tp_weaklistoffset */
487
_methods, /* tp_methods */
488
_members, /* tp_members */
492
0, /* tp_descr_get */
493
0, /* tp_descr_set */
494
0, /* tp_dictoffset */
495
(initproc)_init, /* tp_init */
496
(allocfunc)_alloc, /* tp_alloc, called by new */
497
PyType_GenericNew, /* tp_new */
498
(freefunc)_free, /* tp_free, called by dealloc */
502
static PyMethodDef _keywdarg_methods[] = {
503
{NULL, NULL} /* sentinel */
506
PyMODINIT_FUNC initmice_module(void) {
507
if (PyType_Ready(&PyMiceModuleType) < 0)
510
PyObject* module = Py_InitModule3
511
("mice_module", _keywdarg_methods, module_docstring);
512
if (module == NULL) return;
514
PyTypeObject* mm_type = &PyMiceModuleType;
517
(module, "MiceModule", reinterpret_cast<PyObject*>(mm_type));
520
PyObject* mod_dict = PyModule_GetDict(module);
521
PyObject* cem_c_api = PyCObject_FromVoidPtr(reinterpret_cast<void *>
522
(C_API::create_empty_module), NULL);
523
PyObject* gmm_c_api = PyCObject_FromVoidPtr(reinterpret_cast<void *>
524
(C_API::get_mice_module), NULL);
525
PyObject* smm_c_api = PyCObject_FromVoidPtr(reinterpret_cast<void *>
526
(C_API::set_mice_module), NULL);
527
PyDict_SetItemString(mod_dict, "C_API_CREATE_EMPTY_MODULE", cem_c_api);
528
PyDict_SetItemString(mod_dict, "C_API_GET_MICE_MODULE", gmm_c_api);
529
PyDict_SetItemString(mod_dict, "C_API_SET_MICE_MODULE", smm_c_api);
533
PyObject* C_API::create_empty_module() {
534
return _alloc(&PyMiceModuleType, 0);
537
MiceModule* C_API::get_mice_module(PyObject* self) {
538
if (self->ob_type != &PyMiceModuleType) {
539
PyErr_SetString(PyExc_TypeError,
540
"Failed to resolve object as MiceModule");
543
PyMiceModule* py_mod = reinterpret_cast<PyMiceModule*>(self);
547
int C_API::set_mice_module(PyObject* self, MiceModule* mod) {
548
if (self->ob_type != &PyMiceModuleType) {
549
PyErr_SetString(PyExc_TypeError,
550
"Failed to resolve object as MiceModule");
553
PyMiceModule* py_mod = reinterpret_cast<PyMiceModule*>(self);
554
if (py_mod->mod != NULL) {
557
// I can't keep memory consistent if I allow access back up the tree.
558
mod->setMother(NULL);