/* 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 .
*
*/
#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#include
#include
#include
#include
#include "src/common_cpp/Utils/Globals.hh"
#include "src/common_cpp/Recon/Kalman/Global/ErrorTracking.hh"
#include "src/common_cpp/Recon/Global/MaterialModel.hh"
#include "src/py_cpp/PyGlobalErrorTracking.hh"
namespace MAUS {
namespace PyGlobalErrorTracking {
using Kalman::Global::ErrorTracking;
int get_centroid(PyObject* py_centroid, std::vector& x_in) {
if (!PyList_Check(py_centroid)) {
PyErr_SetString(PyExc_TypeError, "centroid was not a list");
return 1;
}
if (PyList_Size(py_centroid) != 8) {
PyErr_SetString(PyExc_ValueError, "centroid was not length 8");
return 1;
}
for (Py_ssize_t i = 0; i < 8; ++i) {
PyObject* value = PyList_GetItem(py_centroid, i);
if (value == NULL) {
return 1;
}
if (!PyFloat_Check(value)) {
PyErr_SetString(PyExc_TypeError, "centroid had non-float");
return 1;
}
x_in[i] = PyFloat_AsDouble(value);
}
return 0;
}
int get_ellipse(PyObject* py_ellipse,
std::vector& x_in) {
if (!PyList_Check(py_ellipse)) {
PyErr_SetString(PyExc_TypeError, "ellipse was not a list");
return 1;
}
if (PyList_Size(py_ellipse) != 6) {
PyErr_SetString(PyExc_ValueError, "ellipse was not length 6");
return 1;
}
int index = 8;
for (Py_ssize_t i = 0; i < 6; ++i) {
PyObject* py_row = PyList_GetItem(py_ellipse, i);
if (py_row == NULL) {
return 1;
}
if (!PyList_Check(py_row)) {
PyErr_SetString(PyExc_TypeError, "ellipse row was not a list");
return 1;
}
if (PyList_Size(py_row) != 6) {
PyErr_SetString(PyExc_ValueError, "ellipse row was not length 6");
return 1;
}
for (Py_ssize_t j = i; j < 6; ++j) {
PyObject* py_value = PyList_GetItem(py_row, j);
if (!PyFloat_Check(py_value)) {
PyErr_SetString(PyExc_TypeError, "ellipse had non-float");
return 1;
}
x_in[index] = PyFloat_AsDouble(py_value);
index++;
}
}
return 0;
}
PyObject* set_centroid(std::vector x_in) {
PyObject* list = PyList_New(8);
for (Py_ssize_t i = 0; i < 8; ++i) {
PyObject* element = PyFloat_FromDouble(x_in[i]);
PyList_SetItem(list, i, element);
}
return list;
}
PyObject* set_matrix(std::vector< std::vector > matrix) {
PyObject* ellipse = PyList_New(6);
for (Py_ssize_t i = 0; i < 6; ++i) {
PyObject* ellipse_row = PyList_New(6);
for (Py_ssize_t j = 0; j < 6; ++j) {
PyObject* element = PyFloat_FromDouble(matrix[i][j]);
PyList_SetItem(ellipse_row, j, element);
}
PyList_SetItem(ellipse, i, ellipse_row);
}
return ellipse;
}
PyObject* set_variance(std::vector x_in) {
int index = 8;
std::vector< std::vector > matrix(6, std::vector(6, 0.));
for (size_t i = 0; i < 6; ++i)
for (size_t j = i; j < 6; ++j) {
matrix[i][j] = matrix[j][i] = x_in[index];
index++;
}
return set_matrix(matrix);
}
std::string set_deviations_docstring =
std::string("Set the deviations used for calculating field map derivatives\n")+
std::string(" - dx: horizontal deviation\n")+
std::string(" - dy: vertical deviation\n")+
std::string(" - dz: longitudinal deviation\n")+
std::string(" - dt: time deviation\n")+
std::string("Returns None\n");
static PyObject* set_deviations(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("dx"),
const_cast("dy"),
const_cast("dz"),
const_cast("dt"),
NULL};
std::vector delta(4, 0.);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "dddd", kwlist,
&delta[0], &delta[1], &delta[2], &delta[3])) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
glet->SetDeviations(delta[0], delta[1], delta[2], delta[3]);
Py_INCREF(Py_None);
return Py_None;
}
std::string get_deviations_docstring =
std::string("Get the deviations used for calculating field map derivatives\n")+
std::string(" - Takes no arguments\n")+
std::string("Returns a tuple of the deviations in x, y, z, time\n");
static PyObject* get_deviations(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
std::vector dev = glet->GetDeviations();
PyObject* value = Py_BuildValue("dddd", dev[0], dev[1], dev[2], dev[3]);
return value;
}
std::string enable_material_docstring =
std::string("Enable a material so that it exerts energy loss and scattering\n")+
std::string(" - material: string name of the material to be enabled. By\n")+
std::string(" default materials are disabled.\n")+
std::string("Returns None\n");
static PyObject* enable_material(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("material"),
NULL};
char* material = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &material)) {
// error message is set in PyArg_Parse...
return NULL;
}
MaterialModel::EnableMaterial(std::string(material));
Py_INCREF(Py_None);
return Py_None;
}
std::string disable_material_docstring =
std::string("Disable a material\n")+
std::string(" - material: string name of the material to be disabled. By\n")+
std::string(" default materials are disabled. Volumes with disabled\n")+
std::string(" materials do not affect the tracking.\n")+
std::string("Returns None\n");
static PyObject* disable_material(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("material"),
NULL};
char* material = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &material)) {
// error message is set in PyArg_Parse...
return NULL;
}
MaterialModel::DisableMaterial(std::string(material));
Py_INCREF(Py_None);
return Py_None;
}
std::string is_enabled_material_docstring =
std::string("Return true if a material is enabled\n")+
std::string(" - material: string name of the material to check.\n")+
std::string("Returns a boolean True if the material was enabled, else False.\n");
static PyObject* is_enabled_material(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("material"),
NULL};
char* material = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &material)) {
// error message is set in PyArg_Parse...
return NULL;
}
bool enabled = MaterialModel::IsEnabledMaterial(std::string(material));
if (enabled) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
std::string set_max_step_size_docstring =
std::string("Set the maximum step size that will be used by the tracking\n")+
std::string(" - max_step_size: float corresponding to the maximum step\n")+
std::string(" size. Steps can be smaller if the step might intersect a\n")+
std::string(" physical volume. Always takes absolute value (tracking\n")+
std::string(" determines direction).\n")+
std::string("Returns None.\n");
static PyObject* set_max_step_size(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("max_step_size"),
NULL};
double step_size = 1.;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "d", kwlist,
&step_size)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
try {
glet->SetMaxStepSize(step_size);
} catch (std::exception& exc) {
PyErr_SetString(PyExc_RuntimeError, (&exc)->what());
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
std::string get_max_step_size_docstring =
std::string("Returns the maximum step size that will be used by the tracking\n");
static PyObject* get_max_step_size(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
double step = glet->GetMaxStepSize();
PyObject* value = PyFloat_FromDouble(step);
Py_INCREF(value);
return value;
}
std::string set_min_step_size_docstring =
std::string("Set the minimum step size that will be used by the tracking\n")+
std::string(" - min_step_size: float corresponding to the minimum step\n")+
std::string(" size. Steps cannot be smaller even if there is a nearby\n")+
std::string(" physical volume. Always takes absolute value (tracking\n")+
std::string(" determines direction).\n")+
std::string("Returns None.\n");
static PyObject* set_min_step_size(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("min_step_size"),
NULL};
double step_size = 1.;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "d", kwlist,
&step_size)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
try {
glet->SetMinStepSize(step_size);
} catch (std::exception& exc) {
PyErr_SetString(PyExc_RuntimeError, (&exc)->what());
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
std::string get_min_step_size_docstring =
std::string("Returns the minimum step size that will be used by the tracking\n");
static PyObject* get_min_step_size(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
double step = glet->GetMinStepSize();
PyObject* value = PyFloat_FromDouble(step);
Py_INCREF(value);
return value;
}
std::string set_charge_docstring =
std::string("Set the particle charge that will be used by the tracking\n")+
std::string(" - charge: float corresponding to the particle that will be\n")+
std::string(" used by the tracking.\n")+
std::string("Returns None.\n");
static PyObject* set_charge(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("charge"),
NULL};
double charge = 1.;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "d", kwlist,
&charge)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
glet->SetCharge(charge);
Py_INCREF(Py_None);
return Py_None;
}
std::string get_charge_docstring =
std::string("Returns the particle charge that will be used by the tracking\n");
static PyObject* get_charge(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
double charge = glet->GetCharge();
PyObject* value = PyFloat_FromDouble(charge);
Py_INCREF(value);
return value;
}
std::string set_energy_loss_model_docstring =
std::string("Set the energy loss model that will be used by the tracking\n")+
std::string(" - model: string corresponding to the energy loss model.\n")+
std::string(" Options are:\n")+
std::string(" 'no_eloss' particles never lose energy in material.\n")+
std::string(" 'bethe_bloch_forwards' forwards-travelling particles lose\n")+
std::string(" energy in material; backwards-travelling particles gain\n")+
std::string(" energy in material.\n")+
std::string(" 'bethe_bloch_backwards' backwards-travelling particles lose\n")+
std::string(" energy in material; forwards-travelling particles gain\n")+
std::string(" energy in material.\n")+
std::string("Returns None.\n");
static PyObject* set_energy_loss_model(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("model"),
NULL};
char* eloss = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &eloss)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
// now set the eloss model
ErrorTracking::ELossModel eloss_model = ErrorTracking::no_eloss;
if (strcmp(eloss, "no_eloss") == 0) {
} else if (strcmp(eloss, "bethe_bloch_forwards") == 0) {
eloss_model = ErrorTracking::bethe_bloch_forwards;
} else if (strcmp(eloss, "bethe_bloch_backwards") == 0) {
eloss_model = ErrorTracking::bethe_bloch_backwards;
} else {
PyErr_SetString(PyExc_RuntimeError, "Did not recognise energy loss model");
return NULL;
}
glet->SetEnergyLossModel(eloss_model);
// return None
Py_INCREF(Py_None);
return Py_None;
}
std::string get_energy_loss_model_docstring =
std::string("Returns a string corresponding to the energy loss model that\n")+
std::string("will be used by the tracking\n");
static PyObject* get_energy_loss_model(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
ErrorTracking::ELossModel eloss_model = glet->GetEnergyLossModel();
PyObject* py_eloss_model = NULL;
switch (eloss_model) {
case ErrorTracking::bethe_bloch_forwards:
py_eloss_model = PyString_FromString("bethe_bloch_forwards");
break;
case ErrorTracking::bethe_bloch_backwards:
py_eloss_model = PyString_FromString("bethe_bloch_backwards");
break;
case ErrorTracking::no_eloss:
py_eloss_model = PyString_FromString("no_eloss");
break;
}
if (py_eloss_model != NULL)
Py_INCREF(py_eloss_model);
return py_eloss_model;
}
std::string set_scattering_model_docstring =
std::string("Set the scattering model that will be used by the tracking.\n")+
std::string("Scattering results in a systematic change in the propagated\n")+
std::string("errors. The mean trajectory is not deviated.\n")+
std::string(" - model: string corresponding to the scattering model.\n")+
std::string(" Options are:\n")+
std::string(" 'no_mcs' propagated errors are not affected by scattering.\n")+
std::string(" 'moliere_forwards' error associated with forwards-travelling\n")+
std::string(" particles grows according to the pdg formula. Error\n")+
std::string(" associated with backwards-travelling particles shrinks\n")+
std::string(" according to the pdg formula\n")+
std::string(" 'moliere_backwards' error associated with forwards-travelling\n")+
std::string(" particles shrinks according to the pdg formula. Error\n")+
std::string(" associated with backwards-travelling particles grows\n")+
std::string(" according to the pdg formula\n")+
std::string("Returns None.\n");
// enum MCSModel {moliere_forwards, moliere_backwards, no_mcs};
static PyObject* set_scattering_model(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("model"),
NULL};
char* scat_model_str = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &scat_model_str)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
// now set the eloss model
ErrorTracking::MCSModel scat_model = ErrorTracking::no_mcs;
if (strcmp(scat_model_str, "no_mcs") == 0) {
} else if (strcmp(scat_model_str, "moliere_forwards") == 0) {
scat_model = ErrorTracking::moliere_forwards;
} else if (strcmp(scat_model_str, "moliere_backwards") == 0) {
scat_model = ErrorTracking::moliere_backwards;
} else {
PyErr_SetString(PyExc_RuntimeError, "Did not recognise scattering model");
return NULL;
}
glet->SetMCSModel(scat_model);
// return None
Py_INCREF(Py_None);
return Py_None;
}
std::string get_scattering_model_docstring =
std::string("Returns a string corresponding to the scattering model that\n")+
std::string("will be used by the tracking.\n");
static PyObject* get_scattering_model(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
ErrorTracking::MCSModel scat_model = glet->GetMCSModel();
PyObject* py_scat_model = NULL;
switch (scat_model) {
case ErrorTracking::moliere_forwards:
py_scat_model = PyString_FromString("moliere_forwards");
break;
case ErrorTracking::moliere_backwards:
py_scat_model = PyString_FromString("moliere_backwards");
break;
case ErrorTracking::no_mcs:
py_scat_model = PyString_FromString("no_mcs");
break;
}
if (py_scat_model != NULL)
Py_INCREF(py_scat_model);
return py_scat_model;
}
std::string set_tracking_model_docstring =
std::string("Set the tracking model that will be used for integration.\n")+
std::string(" - model: string corresponding to the tracking model.\n")+
std::string(" Options are:\n")+
std::string(" 'em_rk4_forwards_dynamic' integrate the particle\n")+
std::string(" trajectory downstream, choosing step size dynamically.\n")+
std::string(" 'em_rk4_backwards_dynamic' integrate the particle\n")+
std::string(" trajectory upstream, choosing step size dynamically.\n")+
std::string(" 'em_rk4_forwards_static' integrate the particle\n")+
std::string(" trajectory downstream, using a fixed step size.\n")+
std::string(" 'em_rk4_backwards_static' integrate the particle\n")+
std::string(" trajectory upstream, choosing step size dynamically.\n")+
std::string("Returns None.\n");
// enum MCSModel {moliere_forwards, moliere_backwards, no_mcs};
static PyObject* set_tracking_model(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("model"),
NULL};
char* track_model_str = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &track_model_str)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
// now set the eloss model
ErrorTracking::TrackingModel track_model = ErrorTracking::em_forwards_dynamic;
if (strcmp(track_model_str, "em_rk4_forwards_dynamic") == 0) {
} else if (strcmp(track_model_str, "em_rk4_backwards_dynamic") == 0) {
track_model = ErrorTracking::em_backwards_dynamic;
} else if (strcmp(track_model_str, "em_rk4_forwards_static") == 0) {
track_model = ErrorTracking::em_forwards_static;
} else if (strcmp(track_model_str, "em_rk4_backwards_static") == 0) {
track_model = ErrorTracking::em_backwards_static;
} else {
PyErr_SetString(PyExc_RuntimeError, "Did not recognise tracking model");
return NULL;
}
glet->SetTrackingModel(track_model);
// return None
Py_INCREF(Py_None);
return Py_None;
}
std::string get_tracking_model_docstring =
std::string("Returns a string corresponding to the tracking model.\n");
static PyObject* get_tracking_model(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
ErrorTracking::TrackingModel track_model = glet->GetTrackingModel();
PyObject* py_track_model = NULL;
switch (track_model) {
case ErrorTracking::em_forwards_dynamic:
py_track_model = PyString_FromString("em_rk4_forwards_dynamic");
break;
case ErrorTracking::em_backwards_dynamic:
py_track_model = PyString_FromString("em_rk4_backwards_dynamic");
break;
case ErrorTracking::em_forwards_static:
py_track_model = PyString_FromString("em_rk4_forwards_static");
break;
case ErrorTracking::em_backwards_static:
py_track_model = PyString_FromString("em_rk4_backwards_static");
break;
}
if (py_track_model != NULL)
Py_INCREF(py_track_model);
return py_track_model;
}
std::string set_geometry_model_docstring =
std::string("Set the geometry model that will be used for materials lookups.\n")+
std::string(" - model: string corresponding to the geometry model.\n")+
std::string(" Options are:\n")+
std::string(" 'geant4' use the full geant4 geometry.\n")+
std::string(" 'axial_lookup' use a lookup table constructed at runtime,\n")+
std::string(" corresponding to the on-axis materials assuming the world\n")+
std::string(" is made of infinite radius cylinders.\n")+
std::string("Returns None.\n");
// enum MCSModel {moliere_forwards, moliere_backwards, no_mcs};
static PyObject* set_geometry_model(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("model"),
NULL};
char* geometry_model_str = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &geometry_model_str)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
// now set the eloss model
ErrorTracking::GeometryModel geometry_model = ErrorTracking::geant4;
if (strcmp(geometry_model_str, "geant4") == 0) {
} else if (strcmp(geometry_model_str, "axial_lookup") == 0) {
geometry_model = ErrorTracking::axial_lookup;
} else {
PyErr_SetString(PyExc_RuntimeError, "Did not recognise geometry model");
return NULL;
}
glet->SetGeometryModel(geometry_model);
// return None
Py_INCREF(Py_None);
return Py_None;
}
std::string get_geometry_model_docstring =
std::string("Get the geometry model that will be used for materials lookups.");
static PyObject* get_geometry_model(PyObject *self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
ErrorTracking::GeometryModel geometry_model = glet->GetGeometryModel();
PyObject* py_geometry_model = NULL;
switch (geometry_model) {
case ErrorTracking::geant4:
py_geometry_model = PyString_FromString("geant4");
break;
case ErrorTracking::axial_lookup:
py_geometry_model = PyString_FromString("axial_lookup");
break;
}
if (py_geometry_model != NULL)
Py_INCREF(py_geometry_model);
return py_geometry_model;
}
std::string propagate_errors_docstring =
std::string("Propagate a trajectory and associated errors.\n")+
std::string(" - centroid: list of length 8, corresponding to initial\n")+
std::string(" position of the trajectory. elements are:\n")+
std::string(" t, x, y, z, (total) energy, px, py, pz\n")+
std::string(" - ellipse: list of lists, corresponding to a 6x6 matrix with\n")+
std::string(" elements defining the initial error covariance matrix, given\n")+
std::string(" by Cov(u_i, u_j) with u = (t, x, y, energy, px, py) and\n")+
std::string(" Cov(u_i, u_j) is the covariance.\n")+
std::string(" - target_z: target z position to which trajectory should be\n")+
std::string(" integrated.\n")+
std::string("Returns tuple of (centroid, ellipse) after propagation.\n");
static PyObject* propagate_errors
(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {const_cast("centroid"),
const_cast("ellipse"),
const_cast("target_z"),
NULL};
PyObject* py_centroid = NULL;
PyObject* py_ellipse = NULL;
double target_z = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOd|", kwlist,
&py_centroid, &py_ellipse, &target_z)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
std::vector x_in(29, 0.);
if (get_centroid(py_centroid, x_in)) {
return NULL;
}
if (get_ellipse(py_ellipse, x_in)) {
return NULL;
}
try {
glet->SetField(Globals::GetInstance()->GetMCFieldConstructor());
glet->Propagate(&x_in[0], target_z);
} catch (Exceptions::Exception exc) {
PyErr_SetString(PyExc_RuntimeError, (&exc)->what());
return NULL;
}
// py_centroid/py_ellipse own all of their memory
// Memory - issue #1909
py_centroid = set_centroid(x_in);
py_ellipse = set_variance(x_in);
// initialises with a refcnt 1
PyObject* ret_tuple = Py_BuildValue("OO", py_centroid, py_ellipse);
// py_centroid and py_ellipse are initialised with a ref count = 1;
// BuildValue then adds a ref count; but only ret_tuple holds a reference
Py_DECREF(py_centroid);
Py_DECREF(py_ellipse);
return ret_tuple; // ret_tuple;
}
std::string get_transfer_matrix_docstring =
std::string("Calculate the infinitesimal transfer matrix.\n")+
std::string(" - centroid: The central trajectory around which the transfer\n")+
std::string(" matrix is calculated. List of length 8, as per propagate.\n")+
std::string(" - direction: Either +1 or -1; if +1, calculate the matrix\n")+
std::string(" for a forwards-going particle. If -1 calculate the matrix\n")+
std::string(" for a backwards-going particle.\n")+
std::string("Returns a 6x6 matrix formatted as a list of lists.\n");
static PyObject* get_transfer_matrix
(PyObject *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {
const_cast("centroid"),
const_cast("direction"),
NULL};
PyObject* py_centroid = NULL;
double direction = 1.;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "Od|", kwlist,
&py_centroid, &direction)) {
// error message is set in PyArg_Parse...
return NULL;
}
PyGlobalErrorTracking* py_glet = reinterpret_cast(self);
if (py_glet == NULL) {
PyErr_SetString(PyExc_TypeError, "Could not resolve global error tracking");
return NULL;
}
ErrorTracking* glet = py_glet->tracking;
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError, "GlobalErrorTracking was not initialised properly");
return NULL;
}
try {
std::vector x_in(8, 0.);
if (get_centroid(py_centroid, x_in)) {
return NULL;
}
glet->UpdateTransferMatrix(&x_in[0], direction);
std::vector > matrix = glet->GetMatrix();
PyObject* ellipse = set_matrix(matrix);
if (ellipse == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Error calculating matrix");
return NULL;
}
return ellipse;
} catch (Exceptions::Exception exc) {
PyErr_SetString(PyExc_RuntimeError, (&exc)->what());
return NULL;
}
}
std::string class_docstring_str =
std::string("The GlobalErrorTracking module provides routines to propagate\n")+
std::string("tracks and associated errors through an arbitrary MAUS\n")+
std::string("geometry. A track is represented by a vector of time, position,\n")+
std::string("energy and momentum. Errors are represented by a covariance\n")+
std::string("matrix in time, transverse position, energy and transverse\n")+
std::string("momentum. Routines are provided to propagate tracks through EM\n")+
std::string("fields and materials.\n");
const char* class_docstring = class_docstring_str.c_str();
PyObject *_alloc(PyTypeObject *type, Py_ssize_t nitems) {
void* void_glet = malloc(sizeof(PyGlobalErrorTracking));
PyGlobalErrorTracking* glet = reinterpret_cast(void_glet);
glet->tracking = NULL;
glet->ob_refcnt = 1;
glet->ob_type = type;
return reinterpret_cast(glet);
}
int _init(PyObject* self, PyObject *args, PyObject *kwds) {
PyGlobalErrorTracking* glet = reinterpret_cast(self);
// failed to cast or self was not initialised - something horrible happened
if (glet == NULL) {
PyErr_SetString(PyExc_TypeError,
"Failed to resolve self as PyGlobalErrorTracking in __init__");
return -1;
}
// legal python to call initialised_object.__init__() to reinitialise, so
// handle this case
if (glet->tracking != NULL) {
delete glet->tracking;
}
try {
glet->tracking = new ErrorTracking();
} catch (std::exception& exc) {
PyErr_SetString(PyExc_ValueError, (&exc)->what());
return -1;
}
return 0;
}
void _free(PyGlobalErrorTracking * self) {
if (self != NULL) {
if (self->tracking != NULL)
delete self->tracking;
free(self);
}
}
PyObject* _str(PyObject * self) {
return PyString_FromString("GlobalErrorTracking object");
}
static PyMemberDef _members[] = {
{NULL}
};
static PyMethodDef _methods[] = {
{"propagate_errors", (PyCFunction)propagate_errors,
METH_VARARGS|METH_KEYWORDS, propagate_errors_docstring.c_str()},
{"get_transfer_matrix", (PyCFunction)get_transfer_matrix,
METH_VARARGS|METH_KEYWORDS, get_transfer_matrix_docstring.c_str()},
{"set_deviations", (PyCFunction)set_deviations,
METH_VARARGS|METH_KEYWORDS, set_deviations_docstring.c_str()},
{"get_deviations", (PyCFunction)get_deviations,
METH_VARARGS|METH_KEYWORDS, get_deviations_docstring.c_str()},
{"set_charge", (PyCFunction)set_charge,
METH_VARARGS|METH_KEYWORDS, set_charge_docstring.c_str()},
{"get_charge", (PyCFunction)get_charge,
METH_VARARGS|METH_KEYWORDS, get_charge_docstring.c_str()},
{"set_max_step_size", (PyCFunction)set_max_step_size,
METH_VARARGS|METH_KEYWORDS, set_max_step_size_docstring.c_str()},
{"get_max_step_size", (PyCFunction)get_max_step_size,
METH_VARARGS|METH_KEYWORDS, get_max_step_size_docstring.c_str()},
{"set_min_step_size", (PyCFunction)set_min_step_size,
METH_VARARGS|METH_KEYWORDS, set_min_step_size_docstring.c_str()},
{"get_min_step_size", (PyCFunction)get_min_step_size,
METH_VARARGS|METH_KEYWORDS, get_min_step_size_docstring.c_str()},
{"set_energy_loss_model", (PyCFunction)set_energy_loss_model,
METH_VARARGS|METH_KEYWORDS, set_energy_loss_model_docstring.c_str()},
{"get_energy_loss_model", (PyCFunction)get_energy_loss_model,
METH_VARARGS|METH_KEYWORDS, get_energy_loss_model_docstring.c_str()},
{"set_scattering_model", (PyCFunction)set_scattering_model,
METH_VARARGS|METH_KEYWORDS, set_scattering_model_docstring.c_str()},
{"get_scattering_model", (PyCFunction)get_scattering_model,
METH_VARARGS|METH_KEYWORDS, get_scattering_model_docstring.c_str()},
{"set_tracking_model", (PyCFunction)set_tracking_model,
METH_VARARGS|METH_KEYWORDS, set_tracking_model_docstring.c_str()},
{"get_tracking_model", (PyCFunction)get_tracking_model,
METH_VARARGS|METH_KEYWORDS, get_tracking_model_docstring.c_str()},
{"get_geometry_model", (PyCFunction)get_geometry_model,
METH_VARARGS|METH_KEYWORDS, get_geometry_model_docstring.c_str()},
{"set_geometry_model", (PyCFunction)set_geometry_model,
METH_VARARGS|METH_KEYWORDS, set_geometry_model_docstring.c_str()},
{NULL}
};
static PyTypeObject PyGlobalErrorTrackingType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"global_error_tracking.GlobalErrorTracking", /*tp_name*/
sizeof(PyGlobalErrorTracking), /*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, /* 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 */
PyType_GenericNew, /* tp_new */
(freefunc)_free, /* tp_free, called by dealloc */
};
static PyMethodDef _keywdarg_methods[] = {
{"enable_material", (PyCFunction)enable_material,
METH_VARARGS|METH_KEYWORDS, enable_material_docstring.c_str()},
{"disable_material", (PyCFunction)disable_material,
METH_VARARGS|METH_KEYWORDS, disable_material_docstring.c_str()},
{"is_enabled_material", (PyCFunction)is_enabled_material,
METH_VARARGS|METH_KEYWORDS, is_enabled_material_docstring.c_str()},
{NULL, NULL} /* sentinel */
};
std::string module_docstring =
std::string("The global_error_tracking module provides routines for\n")+
std::string("propagating tracks and errors through an arbitrary MAUS geometry.\n");
PyMODINIT_FUNC initglobal_error_tracking(void) {
if (PyType_Ready(&PyGlobalErrorTrackingType) < 0)
return;
PyObject* module = Py_InitModule3("global_error_tracking",
_keywdarg_methods,
module_docstring.c_str());
if (module == NULL) return;
PyTypeObject* tracking_type = &PyGlobalErrorTrackingType;
Py_INCREF(tracking_type);
PyModule_AddObject(module,
"GlobalErrorTracking",
reinterpret_cast(tracking_type));
}
} // namespace PyGlobalErrorTracking
} // namespace MAUS