21#include <structmember.h>
26#include <boost/python.hpp>
27#include <boost/noncopyable.hpp>
28#include <boost/mpl/front.hpp>
66namespace PyOpalObjectNS {
69template <
class C>
class PyOpalObject;
70template <
class C>
struct PyOpalObjectGetProperty;
71template <
class C>
struct PyOpalObjectSetProperty;
156 inline boost::python::class_<PyC>
make_class(
const char* className);
176 template <
class PYCLASS>
181 template <
class PYCLASS>
187 template <
class PYCLASS>
193 template <
class PYCLASS>
199 template <
class PYCLASS>
205 template <
class PYCLASS>
212 template <
class PYCLASS>
223 template <
class PYCLASS>
244 template <
class PYCLASS>
246 double distanceUnits,
double timeUnits,
247 double bfieldUnits,
double efieldUnits);
252 template <
class ValueType>
263 template <
class ValueType>
264 inline void dummySet(ValueType test);
304 double x,
double y,
double z,
double t);
320 static boost::python::object
setAttributes(boost::python::tuple args,
321 boost::python::dict kwargs);
346template <
class ValueType>
355 double x,
double y,
double z,
double t) {
361 if (component ==
nullptr) {
363 "Failed to deduce Component from ElementBase.");
365 Vector_t R(x*distanceUnits_m, y*distanceUnits_m, z*distanceUnits_m);
370 bool outOfBounds = component->
apply(
R, P, t, E, B);
371 return boost::python::make_tuple(outOfBounds,
372 B[0]*bfieldUnits_m, B[1]*bfieldUnits_m, B[2]*bfieldUnits_m,
373 E[0]*efieldUnits_m, E[1]*efieldUnits_m, E[2]*efieldUnits_m);
379 boost::python::dict kwargs) {
380 if (boost::python::len(args) == 0) {
382 "Did not find class instance (i.e. 'self') when calling "
384 }
else if (boost::python::len(args) > 1) {
386 "set_attributes cannot take any non-keyword args (except the class"
389 PyOpalObject<C> self = boost::python::extract<PyOpalObject<C> >(args[0]);
390 boost::python::list key_list = kwargs.keys();
391 for (boost::python::ssize_t i = 0; i < boost::python::len(key_list); ++i) {
392 boost::python::object key = key_list[i];
393 std::string keyStr = boost::python::extract<std::string>(key);
394 boost::python::object value = kwargs[key];
398 "Did not recognise attribute '"+keyStr+
"'");
403 boost::python::object obj;
426 template <
class ArgumentPackage>
427 PyObject*
postcall(ArgumentPackage
const&, PyObject* result);
457 template <
class ArgumentPackage>
458 PyObject*
postcall(ArgumentPackage
const& args, PyObject* result);
475 objectPtr->execute();
482 if (objectPtr ==
nullptr) {
484 "Trying to register something that was not a Opal Object");
493 return objectPtr->getOpalName();
499 objectPtr->setOpalName(
name);
505 objectPtr->setOpalName(
name);
506 if (objectPtr->getElement()) {
507 objectPtr->getElement()->setName(
name);
513 std::shared_ptr<OpalElement> elementPtr =
514 std::dynamic_pointer_cast<OpalElement, C>(pyobject.
getOpalShared());
515 if (elementPtr.get() ==
nullptr) {
517 "Wrapped object was not an OpalElement");
520 boost::python::object pyelement(element);
536 "Object was not initialised");
538 Attribute* attribute = object_m->findAttribute(opalName);
539 if (attribute ==
nullptr) {
541 "Failed to parse attribute "+opalName);
553 pyvalue = PyFloat_FromDouble(value);
559 pyvalue = PyLong_FromDouble(value);
567 pyvalue = PyUnicode_FromString(value.c_str());
583 pyvalue = PyList_New(value.size());
584 for (
size_t i = 0; i < value.size(); ++i) {
585 PyList_SetItem(pyvalue, i, PyFloat_FromDouble(value[i]));
592 pyvalue = PyList_New(value.size());
593 for (
size_t i = 0; i < value.size(); ++i) {
594 PyList_SetItem(pyvalue, i, PyUnicode_FromString(value[i].c_str()));
613 "Element was not initialised");
615 Attribute* attribute = object_m->findAttribute(opalName);
616 if (attribute ==
nullptr) {
618 "Failed to parse attribute "+opalName);
623 double value = PyFloat_AsDouble(pyvalue);
629 double value = PyLong_AsDouble(pyvalue);
635 std::string value = PyUnicode_AsUTF8(pyvalue);
645 std::string value = PyUnicode_AsUTF8(pyvalue);
651 std::string value = PyUnicode_AsUTF8(pyvalue);
657 bool value = PyObject_IsTrue(pyvalue);
663 Py_ssize_t listSize = PyList_Size(pyvalue);
664 std::vector<double> value(listSize);
665 for (Py_ssize_t i = 0; i < listSize; ++i) {
666 double value_i = PyFloat_AsDouble(PyList_GetItem(pyvalue, i));
674 Py_ssize_t listSize = PyList_Size(pyvalue);
675 std::vector<std::string> value(listSize);
676 for (Py_ssize_t i = 0; i < listSize; ++i) {
677 PyObject* pyvalue_i = PyList_GetItem(pyvalue, i);
678 std::string value_i = PyUnicode_AsUTF8(pyvalue_i);
699 if (attribute ==
nullptr) {
717 typedef boost::python::class_<PyOpalObject<C> > PyClass;
718 boost::python::docstring_options docop(
true,
true,
false);
719 PyClass pyclass = PyClass(className);
721 addAttributes(pyclass);
722 addGetOpalName(pyclass);
723 addSetAttributes(pyclass);
725 std::cerr <<
"Failed to initialise class because '" << exc.
what()
728 }
catch (std::exception& exc) {
729 std::cerr <<
"Failed to initialise class because '" << exc.
what()
733 if (
gmsg ==
nullptr) {
735 "Failed to initialise class because gmsg was not initialised.\n"
736 "PyOpal::Globals::Initialise() must be called before attempting to\n"
739 "Globals not initialised");
746 auto pyclass = make_generic_class(className);
747 addSetOpalName(pyclass);
753 auto pyclass = make_generic_class(className);
754 addSetOpalElementName(pyclass);
755 addGetOpalElement(pyclass);
760template <
class PYCLASS>
766template <
class PYCLASS>
772template <
class PYCLASS>
778template <
class PYCLASS>
780 pyclass.def(
"set_attributes",
786template <
class PYCLASS>
792template <
class PYCLASS>
798template <
class PYCLASS>
804template <
class PYCLASS>
806 double distanceUnits,
double timeUnits,
807 double efieldUnits,
double bfieldUnits) {
808 distanceUnits_m = distanceUnits;
809 timeUnits_m = timeUnits;
810 bfieldUnits_m = bfieldUnits;
811 efieldUnits_m = efieldUnits;
812 pyclass.def(
"get_field_value",
814 boost::python::args(
"x",
"y",
"z",
"t"),
815 getFieldValueDocString.c_str());
819template <
class PYCLASS>
822 pyNameToAttribute[iter->pyName_m] = *iter;
825 std::string docString = getDocString(*iter);
826 std::string pyname = iter->pyName_m.c_str();
827 switch (iter->type_m) {
830 pyclass.add_property(pyname.c_str(),
831 boost::python::make_function(&PyC::dummyGet<double>, getProp),
832 boost::python::make_function(&PyC::dummySet<double>, setProp),
839 pyclass.add_property(pyname.c_str(),
840 boost::python::make_function(&PyC::dummyGet<int>, getProp),
841 boost::python::make_function(&PyC::dummySet<int>, setProp),
850 pyclass.add_property(pyname.c_str(),
851 boost::python::make_function(&PyC::dummyGet<std::string>, getProp),
852 boost::python::make_function(&PyC::dummySet<std::string>, setProp),
859 pyclass.add_property(pyname.c_str(),
860 boost::python::make_function(&PyC::dummyGet<bool>, getProp),
861 boost::python::make_function(&PyC::dummySet<bool>, setProp),
869 pyclass.add_property(pyname.c_str(),
870 boost::python::make_function(&PyC::dummyGet<boost::python::list>, getProp),
871 boost::python::make_function(&PyC::dummySet<boost::python::list>, setProp),
881 throw OpalException(
"PyOpalObject<C>::addAttributes",
"Type not implemented");
893 "Get the field value at a point in the field map.\n"
895 "The field lookup is performed against the last RINGDEFINITION that was\n"
896 "instantiated. This should be instantiated by calling\n"
897 "pyopal.parser.initialise_from_opal_file\n"
912 "The function returns a tuple containing 7 values:\n"
913 "out of bounds : int\n"
914 " 1 if the event was out of the field map boundary, else 0.\n"
916 " x magnetic field [T]\n"
918 " y magnetic field [T]\n"
920 " z magnetic field [T]\n"
922 " x electric field [MV/m]\n"
924 " y electric field [MV/m]\n"
926 " z electric field [MV/m]\n";
932template <
class ArgumentPackage>
935 result = object_m->getAttribute(type_m, opalName_m);
945template <
class ArgumentPackage>
949 if (!PyArg_ParseTuple(args,
"OO", &pyObject, &value)) {
953 object_m->setAttribute(type_m, opalName_m, value);
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
Inform & endl(Inform &inf)
const T * find(const T table[], const std::string &name)
Look up name.
double getReal(const Attribute &attr)
Return real value.
void setRealArray(Attribute &attr, const std::vector< double > &value)
Set array value.
void setBool(Attribute &attr, bool val)
Set logical value.
void setUpperCaseString(Attribute &attr, const std::string &val)
Set uppercase string value.
void setString(Attribute &attr, const std::string &val)
Set string value.
bool getBool(const Attribute &attr)
Return logical value.
void setReal(Attribute &attr, double val)
Set real value.
void setStringArray(Attribute &attr, const std::vector< std::string > &value)
Set string array value.
std::vector< double > getRealArray(const Attribute &attr)
Get array value.
std::vector< std::string > getStringArray(const Attribute &attr)
Get string array value.
void setPredefinedString(Attribute &attr, const std::string &val)
Set predefined string value.
std::string getString(const Attribute &attr)
Get string value.
std::string::iterator iterator
AttributeType
AttributeType is used to control conversion from python to OpalAttribute.
std::map< AttributeType, std::string > attributeName
Maps the AttributeType to a string representation for docstrings/etc.
void update(PyOpalObjectNS::PyOpalObject< C > pyelement)
Call update on a pyelement.
AttributeDef defines an attribute opalName_m: the name of the opal Attribute pyName_m: the name that ...
boost::function< boost::tuple< double, bool >(arguments_t)> type
A representation of an Object attribute.
const std::string & getHelp() const
Return the help string.
The base class for all OPAL objects.
static OpalData * getInstance()
void define(Object *newObject)
Define a new object.
Interface for a single beam element.
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B)
PyOpalObject<C> is the basic wrapper class for Opal Objects.
void addRegister(PYCLASS &pyclass)
Add a "register" method to the python class (to register against opal global data object)
void addGetOpalName(PYCLASS &pyclass)
Add a get_opal_name method to the python class (to get the opal internal string that uniquely identif...
static double distanceUnits_m
void dummySet(ValueType test)
dummySet sets the element ptr for PyOpalObjectSetProperty but doesn't actually do the set(....
static std::string getOpalName(const PyOpalObject< C > &pyobject)
method to get the opal name of an object
void addSetOpalName(PYCLASS &pyclass)
Add a set_opal_name method to the python class (to set the opal internal string that uniquely identif...
static std::vector< AttributeDef > attributes
static void registerObject(PyOpalObject< C > &pyobject)
method to call "register" on an object
std::shared_ptr< C > object_m
set to true if the converter has been registered
void addAttributes(PYCLASS &pyclass)
Add attributes to the python class.
void addGetOpalElement(PYCLASS &pyclass)
Add a "get_opal_element" method to the python class (to overload as a PyOpalElement)
virtual ~PyOpalObject()=default
Default destructor.
static std::map< std::string, AttributeDef > pyNameToAttribute
class data (attributes)
static double timeUnits_m
PyOpalObject()
Default constructor.
static boost::python::object setAttributes(boost::python::tuple args, boost::python::dict kwargs)
set many attributes at once as a dict, stored in kwarg.
static double bfieldUnits_m
void addSetOpalElementName(PYCLASS &pyclass)
Add a set_opal_name method to the python class (to set the opal internal string that uniquely identif...
boost::python::class_< PyC > make_generic_class(const char *className)
This is the basic method to make a class for generic Opal object type.
void addGetFieldValue(PYCLASS &pyclass, double distanceUnits, double timeUnits, double bfieldUnits, double efieldUnits)
Add a "get_field_value" method to the python class (for elements that expose a field)
ValueType dummyGet() const
dummyGet sets the object ptr for PyOpalObjectGetProperty but doesn't actually do the get(....
std::string getDocString(AttributeDef &def)
pointer to the element
PyOpalObject(std::shared_ptr< C > object)
Constructor taking the element as argument.
static boost::python::object getFieldValue(PyOpalObjectNS::PyOpalObject< C > &pyobject, double x, double y, double z, double t)
method to get field at a point in space-time
static boost::python::object getPyOpalElement(PyOpalObject< C > &pyobject)
return the underlying element (used e.g.
virtual void doSetup()
Overload the method to perform any additional setup that can be made before the OpalObject is accesse...
static void setOpalElementName(PyOpalObject< C > &pyobject, std::string name)
method to set the opal name of an element - elements have two "names", one belonging to the OpalObjec...
static bool converterRegistered
class docstring
void addSetAttributes(PYCLASS &pyclass)
Add a set_attributes method to the python class (to setup opalobject from a dictionary of kwargs)
std::shared_ptr< C > getOpalShared()
Returns the Opal Object from the PyOpalObject.
PyObject * getAttribute(AttributeType type, std::string opalName) const
Get the value of an attribute.
boost::python::class_< PyC > make_class(const char *className)
This is the basic method to make a class for OpalObjects.
static void execute(PyOpalObject< C > &pyobject)
method to call "execute" on an object
boost::python::class_< PyC > make_element_class(const char *className)
This is the basic method to make a class for elements.
void addExecute(PYCLASS &pyclass)
Add an "execute" method to the python class (e.g.
static const std::string getFieldValueDocString
static std::string classDocstring
maps python name to AttributeDef for fast lookup
static double efieldUnits_m
std::shared_ptr< C > getOpalShared() const
Returns the Opal Object from the PyOpalObject (const version)
static void setOpalName(PyOpalObject< C > &pyobject, std::string name)
method to set the opal name of an object
void setAttribute(AttributeType type, std::string opalName, PyObject *value)
Set the value of an attribute.
Helper class to handle getting Attributes from python.
static void setObject(const PyOpalObject< C > *object)
Set pointer to the element; should be called before each postcall.
static const PyOpalObject< C > * object_m
~PyOpalObjectGetProperty()
destructor
PyObject * postcall(ArgumentPackage const &, PyObject *result)
postcall action
PyOpalObjectGetProperty(AttributeType type, std::string opalName)
Constructor.
Helper class to handle setting Attributes from python.
static void setObject(PyOpalObject< C > *object)
Set pointer to the element; should be called before each postcall.
~PyOpalObjectSetProperty()
destructor
PyObject * postcall(ArgumentPackage const &args, PyObject *result)
postcall action
static PyOpalObject< C > * object_m
PyOpalObjectSetProperty(AttributeType type, std::string opalName)
Constructor.
The base class for all OPAL exceptions.
virtual const std::string & what() const
Return the message string for the exception.