Skip to content

Commit

Permalink
Refs #4399. PyObject->V3D converter.
Browse files Browse the repository at this point in the history
  • Loading branch information
martyngigg committed Feb 21, 2012
1 parent 3dccec9 commit 676c2c0
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#ifndef MANTID_PYTHONINERFACE_PYOBJECTTOV3D_H_
#define MANTID_PYTHONINERFACE_PYOBJECTTOV3D_H_
/**
Copyright © 2012 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
This file is part of Mantid.
Mantid 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.
Mantid 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 this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
#include "MantidKernel/System.h"
#include "MantidKernel/V3D.h"
#include <boost/python/object.hpp>

namespace Mantid
{
namespace PythonInterface
{
namespace Converters
{
/**
* Takes a Python object and if it supports
* indexing and is of length 3 then it will
* attempt to convert a Kernel::V3D object from
* it
*/
struct DLLExport PyObjectToV3D
{
PyObjectToV3D(const boost::python::object & p);
/// Produces a V3D object from the given PyObject
Kernel::V3D operator()();
private:
/// A reference to the object
const boost::python::object & m_obj;
/// Is the object a wrapped instance of V3D
bool m_alreadyV3D;
};
}

}
}

#endif /* MANTID_PYTHONINERFACE_PYOBJECTTOV3D_H_ */
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ namespace Mantid
{
/** @name Create Mantid objects from python sequences */
//@{
/// Try and create a Mantid V3D object from the given PyObject.
DLLExport Kernel::V3D createV3D(PyObject *data);
/// Create a Matrix of doubles from a 2D numpy array
DLLExport Kernel::DblMatrix createDoubleMatrix(PyObject* data);
//@}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "MantidGeometry/Crystal/OrientedLattice.h"
#include "MantidPythonInterface/kernel/Converters/MatrixToNDArray.h"
#include "MantidPythonInterface/kernel/Converters/PyObjectToV3D.h"
#include "MantidPythonInterface/kernel/Policies/MatrixToNumpy.h"

#include "MantidPythonInterface/kernel/NumpyConverters.h"
#include <boost/python/class.hpp>

Expand All @@ -27,9 +29,9 @@ namespace //<unnamed>

/// Set the U matrix from 2 Python objects representing a V3D type. This can be a V3D object, a list
/// or a numpy array. If the arrays are used they must be of length 3
void setUFromVectors(OrientedLattice & self, PyObject * vec1, PyObject *vec2)
void setUFromVectors(OrientedLattice & self, object vec1, object vec2)
{
self.setUFromVectors(Numpy::createV3D(vec1), Numpy::createV3D(vec2));
self.setUFromVectors(Converters::PyObjectToV3D(vec1)(), Converters::PyObjectToV3D(vec2)());
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set ( SRC_FILES
src/Converters/NDArrayToVector.cpp
src/Converters/NDArrayTypeIndex.cpp
src/Converters/PyArrayType.cpp
src/Converters/PyObjectToV3D.cpp
src/Converters/VectorToNDArray.cpp
src/Registry/SequenceTypeHandler.cpp
src/Registry/TypeRegistry.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//----------------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------------
#include "MantidPythonInterface/kernel/Converters/PyObjectToV3D.h"
#include <boost/python/extract.hpp>
#include <boost/python/numeric.hpp>

// See http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PY_ARRAY_UNIQUE_SYMBOL
#define PY_ARRAY_UNIQUE_SYMBOL KERNEL_ARRAY_API
#define NO_IMPORT_ARRAY
#include <numpy/arrayobject.h>

namespace Mantid
{
namespace PythonInterface
{
namespace Converters
{
/**
* Construct the converter object with the given Python object
* @param p :: A boost::python object that should support
* the __getitem__ and __len__ protocol or be a wrapped V3D object.
* Throws std::invalid_argument if not
* if that is not the case.
*/
PyObjectToV3D::PyObjectToV3D(const boost::python::object & p)
: m_obj(p), m_alreadyV3D(false)
{
// Is it an already wrapped V3D ?
boost::python::extract<Kernel::V3D> converter(p);
if( converter.check() )
{
m_alreadyV3D = true;
return;
}
// Is it a sequence
try
{
const size_t length = boost::python::len(p);
if( length != 3 )
{
throw std::invalid_argument("Incorrect length for conversion to V3D");
}
// Can we index the object
p.attr("__getitem__")(0);
}
catch(boost::python::error_already_set&)
{
throw std::invalid_argument(std::string("Cannot convert object to V3D. Expected a python sequence found ")
+ p.ptr()->ob_type->tp_name);
}
}

/**
* Returns a V3D object from the Python object given
* to the converter
* @returns A newly constructed V3D object converted
* from the PyObject.
*/
Kernel::V3D PyObjectToV3D::operator ()()
{
using namespace boost::python;
if(m_alreadyV3D)
{
return extract<Kernel::V3D>(m_obj)();
}
// Numpy arrays need to be forced to a double
// as extract cannot convert from a int64->double
boost::python::object obj = m_obj;
if( PyArray_Check(obj.ptr()) )
{
obj = boost::python::numeric::array(obj).astype('d');
}
// Must be a sequence
return Kernel::V3D(extract<double>(obj[0])(),
extract<double>(obj[1])(),
extract<double>(obj[2])());
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,63 +19,6 @@ namespace Mantid
//--------------------------------------------------------------------------------------------
// Creation of Mantid objects
//--------------------------------------------------------------------------------------------
/**
* Try and create a Mantid V3D object from the given PyObject.
* @param data A pointer to a Python object representing either a V3D, a list or a numpy array
* @return A new V3D object
*/
Kernel::V3D createV3D(PyObject *data)
{
using namespace boost::python;
extract<Kernel::V3D> converter(data);
// Is it an already wrapped V3D ?
if( converter.check() ) return converter();

Kernel::V3D result;
// Python list
if( PyList_Check(data) )
{
boost::python::list pyList = extract<boost::python::list>(data);
if( len(pyList) == 3 )
{
result[0] = boost::python::extract<double>(pyList[0]);
result[1] = boost::python::extract<double>(pyList[1]);
result[2] = boost::python::extract<double>(pyList[2]);
}
else
{
std::ostringstream msg;
msg << "createV3D - Expected Python list to be of length 3, length=" << len(pyList);
throw std::invalid_argument(msg.str());
}

}
// Numpy array
else if( PyArray_Check(data) )
{
numeric::array ndarray = extract<numeric::array>(data);
if( PyArray_Size(ndarray.ptr()) == 3)
{
//force the array to be of double type (in case it was int)
numeric::array doubleArray = (boost::python::numeric::array)ndarray.astype('d');
result[0] = extract<double>(doubleArray[0]);
result[1] = extract<double>(doubleArray[1]);
result[2] = extract<double>(doubleArray[2]);
}
else
{
std::ostringstream msg;
msg << "createV3D - Expected numpy array to be of length 3, length=" << PyArray_Size(ndarray.ptr());
throw std::invalid_argument(msg.str());
}
}
else
{
throw std::invalid_argument(std::string("createV3D - Expected a V3D, list or numpy array but found a ") + data->ob_type->tp_name);
}

return result;
}

/**
* Create a Matrix of doubles from a 2D numpy array
Expand Down

0 comments on commit 676c2c0

Please sign in to comment.