/* This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus
*
* MAUS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MAUS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAUS. If not, see .
*
*/
// These ifdefs are required to avoid cpp compiler warning
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#include
#include
#include
#include "src/common_cpp/Utils/Exception.hh"
#include "src/common_cpp/Optics/PhaseSpaceVector.hh"
#define MAUS_PYPHASESPACEVECTOR_CC
#include "src/py_cpp/optics/PyPhaseSpaceVector.hh"
#undef MAUS_PYPHASESPACEVECTOR_CC
namespace MAUS {
namespace PyPhaseSpaceVector {
PyObject* get(PyObject* self,
double (PhaseSpaceVector::*get_function)() const) {
PhaseSpaceVector* psv = C_API::get_phase_space_vector(self);
if (psv == NULL) {
PyErr_SetString(PyExc_TypeError,
"Failed to resolve self as a PhaseSpaceVector");
return NULL;
}
double value = (psv->*get_function)();
PyObject* py_value = Py_BuildValue("d", value);
if (py_value == NULL) {
PyErr_SetString(PyExc_TypeError,
"PyCovarianceMatrix failed to get value");
return NULL;
}
Py_INCREF(py_value);
return py_value;
}
PyObject* set(PyObject* self, PyObject *args, PyObject *kwds,
void (PhaseSpaceVector::*set_function)(double value)) {
PhaseSpaceVector* psv = C_API::get_phase_space_vector(self);
if (psv == NULL) {
PyErr_SetString(PyExc_TypeError,
"Failed to resolve self as a PhaseSpaceVector");
return NULL;
}
double value = 0;
static char *kwlist[] = {const_cast("value"), NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|", kwlist, &value)) {
return NULL;
}
(psv->*set_function)(value);
Py_INCREF(Py_None);
return Py_None;
}
std::string get_t_docstring =
std::string("Returns the time [ns]\n");
PyObject* get_t(PyObject* self, PyObject *args, PyObject *kwds) {
return get(self, &PhaseSpaceVector::t);
}
std::string get_energy_docstring =
std::string("Returns the total energy (not kinetic energy) [MeV]\n");
PyObject* get_energy(PyObject* self, PyObject *args, PyObject *kwds) {
return get(self, &PhaseSpaceVector::E);
}
std::string get_x_docstring =
std::string("Returns the horizontal position x [mm]\n");
PyObject* get_x(PyObject* self, PyObject *args, PyObject *kwds) {
return get(self, &PhaseSpaceVector::x);
}
std::string get_px_docstring =
std::string("Returns the horizontal component of momentum px [MeV/c]\n");
PyObject* get_px(PyObject* self, PyObject *args, PyObject *kwds) {
return get(self, &PhaseSpaceVector::Px);
}
std::string get_y_docstring =
std::string("Returns the vertical position y [mm]\n");
PyObject* get_y(PyObject* self, PyObject *args, PyObject *kwds) {
return get(self, &PhaseSpaceVector::y);
}
std::string get_py_docstring =
std::string("Returns the vertical component of momentum py [MeV/c]\n");
PyObject* get_py(PyObject* self, PyObject *args, PyObject *kwds) {
return get(self, &PhaseSpaceVector::Py);
}
std::string set_t_docstring =
std::string("Set the time\n\n")+
std::string("- value (float) phase space vector time [ns]\n")+
std::string("Returns None");
PyObject* set_t(PyObject* self, PyObject *args, PyObject *kwds) {
return set(self, args, kwds, &PhaseSpaceVector::set_t);
}
std::string set_energy_docstring =
std::string("Set the total energy (not kinetic energy)\n\n")+
std::string("- value (float) phase space vector energy [MeV]\n")+
std::string("Returns None");
PyObject* set_energy(PyObject* self, PyObject *args, PyObject *kwds) {
return set(self, args, kwds, &PhaseSpaceVector::set_energy);
}
std::string set_x_docstring =
std::string("Set the horizontal position\n\n")+
std::string("- value (float) horizontal position [mm]\n")+
std::string("Returns None");
PyObject* set_x(PyObject* self, PyObject *args, PyObject *kwds) {
return set(self, args, kwds, &PhaseSpaceVector::set_x);
}
std::string set_px_docstring =
std::string("Set the horizontal component of momentum\n\n")+
std::string("- value (float) momentum px [MeV/c]\n")+
std::string("Returns None");
PyObject* set_px(PyObject* self, PyObject *args, PyObject *kwds) {
return set(self, args, kwds, &PhaseSpaceVector::set_Px);
}
std::string set_y_docstring =
std::string("Set the vertical position\n\n")+
std::string("- value (float) vertical position [mm]\n")+
std::string("Returns None");
PyObject* set_y(PyObject* self, PyObject *args, PyObject *kwds) {
return set(self, args, kwds, &PhaseSpaceVector::set_y);
}
std::string set_py_docstring =
std::string("Set the vertical component of momentum\n\n")+
std::string("- value (float) vertical momentum [MeV/c]\n")+
std::string("Returns None");
PyObject* set_py(PyObject* self, PyObject *args, PyObject *kwds) {
return set(self, args, kwds, &PhaseSpaceVector::set_Py);
}
static PyMemberDef _members[] = {
{NULL}
};
static PyMethodDef _methods[] = {
{"get_t", (PyCFunction)get_t, METH_VARARGS|METH_KEYWORDS,
get_t_docstring.c_str()},
{"get_energy", (PyCFunction)get_energy, METH_VARARGS|METH_KEYWORDS,
get_energy_docstring.c_str()},
{"get_x", (PyCFunction)get_x, METH_VARARGS|METH_KEYWORDS,
get_x_docstring.c_str()},
{"get_px", (PyCFunction)get_px, METH_VARARGS|METH_KEYWORDS,
get_px_docstring.c_str()},
{"get_y", (PyCFunction)get_y, METH_VARARGS|METH_KEYWORDS,
get_y_docstring.c_str()},
{"get_py", (PyCFunction)get_py, METH_VARARGS|METH_KEYWORDS,
get_py_docstring.c_str()},
{"set_t", (PyCFunction)set_t, METH_VARARGS|METH_KEYWORDS,
set_t_docstring.c_str()},
{"set_energy", (PyCFunction)set_energy, METH_VARARGS|METH_KEYWORDS,
set_energy_docstring.c_str()},
{"set_x", (PyCFunction)set_x, METH_VARARGS|METH_KEYWORDS,
set_x_docstring.c_str()},
{"set_px", (PyCFunction)set_px, METH_VARARGS|METH_KEYWORDS,
set_px_docstring.c_str()},
{"set_y", (PyCFunction)set_y, METH_VARARGS|METH_KEYWORDS,
set_y_docstring.c_str()},
{"set_py", (PyCFunction)set_py, METH_VARARGS|METH_KEYWORDS,
set_py_docstring.c_str()},
{NULL}
};
static PyObject* _str(PyObject * self) {
PhaseSpaceVector* psv = C_API::get_phase_space_vector(self);
if (psv == NULL) {
PyErr_SetString(PyExc_TypeError,
"PyPhaseSpaceVector not initialised properly");
return NULL;
}
char buffer[1024];
snprintf(buffer, sizeof(buffer), " [%10g, %10g, %10g, %10g, %10g, %10g]",
(*psv).t(), (*psv).energy(),
(*psv).x(), (*psv).Px(),
(*psv).y(), (*psv).Py());
return PyString_FromString(buffer);
}
const char* module_docstring =
"phase_space_vector module; merely a place holder for PhaseSpaceVector class";
std::string class_docstring =
std::string("PhaseSpaceVector provides bindings for particle tracks.\n\n")+
std::string("__init__()\n")+
std::string(" Takes no arguments. Returns a PhaseSpaceVector initialised\n")+
std::string(" 0. Note that PhaseSpaceVector coordinates are considered\n")+
std::string(" relative to 0, not relative to the\n")+
std::string(" 'simulation_reference_particle'.\n");
static PyTypeObject PyPhaseSpaceVectorType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"phase_space_vector.PhaseSpaceVector", /*tp_name*/
sizeof(PyPhaseSpaceVector), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)_free, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
_str, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
_str, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
class_docstring.c_str(), /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
_methods, /* tp_methods */
_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)_init, /* tp_init */
(allocfunc)_alloc, /* tp_alloc, called by new */
0, /* tp_new */
(freefunc)_free, /* tp_free, called by dealloc */
};
PyObject *_alloc(PyTypeObject *type, Py_ssize_t nitems) {
void* void_psv = malloc(sizeof(PyPhaseSpaceVector));
PyPhaseSpaceVector* py_psv =
reinterpret_cast(void_psv);
py_psv->psv = NULL;
py_psv->ob_refcnt = 1;
py_psv->ob_type = type;
return reinterpret_cast(py_psv);
}
int _init(PyObject* self, PyObject *args, PyObject *kwds) {
PyPhaseSpaceVector* py_psv = reinterpret_cast(self);
// failed to cast or self was not initialised - something horrible happened
if (py_psv == NULL) {
PyErr_SetString(PyExc_TypeError,
"Failed to resolve self as PyPhaseSpaceVector in __init__");
return -1;
}
// legal to call __init__ on an existing object
if (py_psv->psv == NULL)
py_psv->psv = new PhaseSpaceVector(0., 0., 0., 0., 0., 0.);
return 0;
}
std::string create_from_coordinates_docstring =
std::string("Create a new phase space vector given coordinates\n\n")+
std::string(" - t (float) time [ns]\n")+
std::string(" - energy (float) energy [MeV]\n")+
std::string(" - x (float) horizontal position [mm]\n")+
std::string(" - px (float) horizontal component of momentum [MeV/c]\n")+
std::string(" - y (float) vertical position [mm]\n")+
std::string(" - py (float) vertical component of momentum [MeV/c]\n")+
std::string("Returns the new phase space vector");
PyObject* create_from_coordinates(PyObject* self,
PyObject *args,
PyObject *kwds) {
PyPhaseSpaceVector* py_psv =
reinterpret_cast(C_API::create_empty_vector());
if (py_psv == NULL) {
PyErr_SetString(PyExc_TypeError,
"Failed to initialise PyPhaseSpaceVector");
return NULL;
}
double t(0), E(0), x(0), px(0), y(0), py(0);
// try to extract a numpy array from the arguments
static char *kwlist[] = {const_cast("t"),
const_cast("energy"),
const_cast("x"),
const_cast("px"),
const_cast("y"),
const_cast("py"), NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "dddddd|", kwlist, &t, &E,
&x, &px,
&y, &py)) {
// error message is set in PyArg_Parse...
free(py_psv);
return NULL;
}
// now initialise the internal phase space vector
try {
py_psv->psv = new PhaseSpaceVector(t, E, x, px, y, py);
} catch (std::exception& exc) {
PyErr_SetString(PyExc_RuntimeError, (&exc)->what());
free(py_psv);
return NULL;
}
Py_INCREF(py_psv);
return reinterpret_cast(py_psv);
}
void _free(PyPhaseSpaceVector * self) {
if (self != NULL) {
if (self->psv != NULL)
delete self->psv;
free(self);
}
}
static PyMethodDef _keywdarg_methods[] = {
{"create_from_coordinates", (PyCFunction)create_from_coordinates,
METH_VARARGS|METH_KEYWORDS, create_from_coordinates_docstring.c_str()},
{NULL, NULL} /* sentinel */
};
PyMODINIT_FUNC initphase_space_vector(void) {
PyPhaseSpaceVectorType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyPhaseSpaceVectorType) < 0) return;
PyObject* module = Py_InitModule3
("phase_space_vector", _keywdarg_methods, module_docstring);
if (module == NULL) return;
PyTypeObject* psv_type = &PyPhaseSpaceVectorType;
Py_INCREF(psv_type);
PyModule_AddObject
(module, "PhaseSpaceVector", reinterpret_cast(psv_type));
// C API
PyObject* psv_dict = PyModule_GetDict(module);
PyObject* cev_c_api = PyCObject_FromVoidPtr
(reinterpret_cast(C_API::create_empty_vector), NULL);
PyObject* gpsv_c_api = PyCObject_FromVoidPtr
(reinterpret_cast(C_API::get_phase_space_vector), NULL);
PyObject* spsv_c_api = PyCObject_FromVoidPtr
(reinterpret_cast(C_API::set_phase_space_vector), NULL);
PyDict_SetItemString(psv_dict, "C_API_CREATE_EMPTY_VECTOR", cev_c_api);
PyDict_SetItemString(psv_dict, "C_API_GET_PHASE_SPACE_VECTOR", gpsv_c_api);
PyDict_SetItemString(psv_dict, "C_API_SET_PHASE_SPACE_VECTOR", spsv_c_api);
}
PyObject *C_API::create_empty_vector() {
return _alloc(&PyPhaseSpaceVectorType, 0);
}
PhaseSpaceVector* C_API::get_phase_space_vector(PyObject* py_psv) {
if (py_psv == NULL || py_psv->ob_type != &PyPhaseSpaceVectorType) {
PyErr_SetString(PyExc_TypeError,
"Could not resolve variable into a PhaseSpaceVector");
return NULL;
}
PyPhaseSpaceVector* psv_ = reinterpret_cast(py_psv);
return psv_->psv;
}
int C_API::set_phase_space_vector(PyObject* py_psv_o, PhaseSpaceVector* psv) {
if (py_psv_o == NULL || py_psv_o->ob_type != &PyPhaseSpaceVectorType) {
PyErr_SetString(PyExc_TypeError,
"Could not resolve variable into a PhaseSpaceVector");
return 0;
}
PyPhaseSpaceVector* py_psv =
reinterpret_cast(py_psv_o);
if (py_psv->psv != NULL) {
delete py_psv->psv;
}
py_psv->psv = psv;
return 1;
}
}
}