Skip to content

Commit

Permalink
Refs #4399. return_value_policy for creation of numpy wrappers
Browse files Browse the repository at this point in the history
The policy avoids have to have a useless intermediary wrapping function and
creates code that is much more resuable
  • Loading branch information
martyngigg committed Feb 17, 2012
1 parent 12174a4 commit c94b713
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,33 +36,6 @@ namespace Mantid
namespace Numpy
{

#define DECLARE_ACCESS_FN(functionName) \
PyObject *functionName(API::MatrixWorkspace &self, const size_t index);

//** @name Numpy read-only wrappers */
///@{
/// Create a read-only numpy wrapper around the original X values at the given index
DECLARE_ACCESS_FN(readOnlyX);
/// Create a read-only numpy wrapper around the original Y values at the given index
DECLARE_ACCESS_FN(readOnlyY);
/// Create a read-only numpy wrapper around the original X values at the given index
DECLARE_ACCESS_FN(readOnlyE);
/// Create a read-only numpy wrapper around the original Dx values at the given index
DECLARE_ACCESS_FN(readOnlyDx);
///@}
//** @name Numpy writable array wrappers */
///@{
/// Create a writable wrapper around the original X values at the given index
DECLARE_ACCESS_FN(readWriteX);
/// Create a writable numpy wrapper around the original Y values at the given index
DECLARE_ACCESS_FN(readWriteY);
/// Create a writable numpy wrapper around the original X values at the given index
DECLARE_ACCESS_FN(readWriteE);
/// Create a writable numpy wrapper around the original Dx values at the given index
DECLARE_ACCESS_FN(readWriteDx);
///@}
#undef DECLARE_ACCESS_FN

//** @name Numpy clones of data*/
///{
/// Create a numpy array from the X values of the given workspace reference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ namespace Mantid
{
namespace Numpy
{
/**@name Array type */
DLLExport PyTypeObject * getNDArrayType();

/** @name Create Numpy arrays */
//@{
/// Create a numpy array wrapper around existing vector. This is only possible for contiguous data
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#ifndef MANTID_PYTHONINTERFACE_VECTORTONUMPY_H_
#define MANTID_PYTHONINTERFACE_VECTORTONUMPY_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 "MantidPythonInterface/kernel/NumpyConverters.h"
//#include <boost/mpl/if.hpp>
//#include <boost/mpl/or.hpp>
//#include <boost/type_traits/is_convertible.hpp>

#include <vector>

namespace Mantid
{
namespace PythonInterface
{
namespace Policies
{
//-----------------------------------------------------------------------
// Conversion Policies
//-----------------------------------------------------------------------

/**
* WrapReadOnly is a policy for VectorToPython
* to wrap the vector in a read-only numpy array
* that looks at the original data. No copy is performed
*/

struct WrapReadOnly
{
template<typename VectorType>
struct apply
{
/**
* Returns a read-only Numpy array wrapped around an existing vector
* @param cvector
* @return
*/
static PyObject * create(const VectorType & cvector)
{
return Numpy::wrapWithReadOnlyNumpy(cvector);
}
};
};

/**
* WrapReadWrite is a policy for VectorToPython
* to wrap the vector in a read-write numpy array
* that looks at the original data. No copy is performed
*/
struct WrapReadWrite
{
template<typename VectorType>
struct apply
{
/**
* Returns a read-write Numpy array wrapped around an existing vector
* @param cvector
* @return
*/
static PyObject * create(const VectorType & cvector)
{
return Numpy::wrapWithNumpy(cvector);
}
};
};

namespace // anonymous
{
/**
* Helper struct that implements the conversion
* policy.
*/
template<typename VectorType, typename ConversionPolicy>
struct ConvertVectorToNDArray
{
inline PyObject * operator()(const VectorType & cvector) const
{
typedef typename ConversionPolicy::template apply<VectorType> policy;
return policy::create(cvector);
}

inline PyTypeObject const* get_pytype() const
{
return Numpy::getNDArrayType();
}
};
}

//-----------------------------------------------------------------------
// return_value_policy
//-----------------------------------------------------------------------
/**
* Implements a return value policy that
* returns a numpy array from a std::vector
*
* The type of conversion is specified by a policy:
* (1) WrapReadOnly - Creates a read-only array around the original data (no copy is performed)
* (2) WrapReadWrite - Creates a read-write array around the original data (no copy is performed)
*/
template<typename ConversionPolicy>
struct VectorToNumpy
{
template <class T>
struct apply
{
typedef ConvertVectorToNDArray<T, ConversionPolicy> type;
};
};

}
}
}

#endif // MANTID_PYTHONINTERFACE_VECTORTONUMPY_H_
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "MantidPythonInterface/kernel/PropertyWithValue.h"
#include "MantidPythonInterface/kernel/Registry/RegisterSingleValueHandler.h"
#include "MantidPythonInterface/kernel/Policies/VectorToNumpy.h"
#include "MantidPythonInterface/api/WorkspaceToNumpy.h"

#include <boost/python/class.hpp>
Expand All @@ -15,6 +16,7 @@ using namespace Mantid::API;
using Mantid::Geometry::IDetector_sptr;
using Mantid::Kernel::PropertyWithValue;
using Mantid::Kernel::DataItem_sptr;
namespace Policies = Mantid::PythonInterface::Policies;
using namespace boost::python;

namespace
Expand All @@ -27,9 +29,17 @@ namespace

void export_MatrixWorkspace()
{

register_ptr_to_python<MatrixWorkspace_sptr>();

/// Typedef for data access, i.e. dataX,Y,E members
typedef Mantid::MantidVec&(MatrixWorkspace::*data_modifier)(const std::size_t);
/// return_value_policy for read-only numpy array
typedef return_value_policy<Policies::VectorToNumpy<Policies::WrapReadOnly> > return_readonly_numpy;
/// return_value_policy for read-write numpy array
typedef return_value_policy<Policies::VectorToNumpy<Policies::WrapReadWrite> > return_readwrite_numpy;



class_<MatrixWorkspace, boost::python::bases<ExperimentInfo,IMDWorkspace>, boost::noncopyable>("MatrixWorkspace", no_init)
//--------------------------------------- Meta information -----------------------------------------------------------------------
.def("blocksize", &MatrixWorkspace::blocksize, "Returns size of the Y data array")
Expand All @@ -56,21 +66,21 @@ void export_MatrixWorkspace()
return_value_policy<return_by_value>(), "Set distribution flag. If True the workspace has been divided by the bin-width.")
.def("replaceAxis", &MatrixWorkspace::replaceAxis)
//--------------------------------------- Data access ---------------------------------------------------------------------------
.def("readX", &Mantid::PythonInterface::Numpy::readOnlyX,
.def("readX", &MatrixWorkspace::readX, return_readonly_numpy(),
"Creates a read-only numpy wrapper around the original X data at the given index")
.def("readY", &Mantid::PythonInterface::Numpy::readOnlyY,
.def("readY", &MatrixWorkspace::readY, return_readonly_numpy(),
"Creates a read-only numpy wrapper around the original Y data at the given index")
.def("readE", &Mantid::PythonInterface::Numpy::readOnlyE,
.def("readE", &MatrixWorkspace::readE, return_readonly_numpy(),
"Creates a read-only numpy wrapper around the original E data at the given index")
.def("readDx", &Mantid::PythonInterface::Numpy::readOnlyDx,
.def("readDx", &MatrixWorkspace::readDx, return_readonly_numpy(),
"Creates a read-only numpy wrapper around the original Dx data at the given index")
.def("dataX", &Mantid::PythonInterface::Numpy::readWriteX,
.def("dataX", (data_modifier)&MatrixWorkspace::dataX, return_readwrite_numpy(),
"Creates a writable numpy wrapper around the original X data at the given index")
.def("dataY", &Mantid::PythonInterface::Numpy::readWriteY,
.def("dataY", (data_modifier)&MatrixWorkspace::dataY, return_readwrite_numpy(),
"Creates a writable numpy wrapper around the original Y data at the given index")
.def("dataE", &Mantid::PythonInterface::Numpy::readWriteE,
.def("dataE", (data_modifier)&MatrixWorkspace::dataE, return_readwrite_numpy(),
"Creates a writable numpy wrapper around the original E data at the given index")
.def("dataDx", &Mantid::PythonInterface::Numpy::readWriteDx,
.def("dataDx", (data_modifier)&MatrixWorkspace::dataDx, return_readwrite_numpy(),
"Creates a writable numpy wrapper around the original Dx data at the given index")
.def("extractX", Mantid::PythonInterface::Numpy::cloneX,
"Extracts (copies) the X data from the workspace into a 2D numpy array. "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,71 +82,6 @@ namespace Mantid
}
}

// -------------------------------------- Non-copying array access ------------------------------------
#define DEFINE_ACCESS_FN(functionName, workspaceMethod, wrapperMethod)\
PyObject *functionName(MatrixWorkspace &self, const size_t index)\
{\
PyArrayObject *nparray = (PyArrayObject*)wrapperMethod(self.workspaceMethod(index));\
return (PyObject*)nparray;\
}

/*
* Create a read-only numpy wrapper around the original X values at the given index
* @param self :: A reference to the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readOnlyX, readX, wrapWithReadOnlyNumpy);

/*
* Create a read-only numpy wrapper around the original Y values at the given index
* @param self :: A reference to the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readOnlyY, readY, wrapWithReadOnlyNumpy);

/*
* Create a read-only numpy wrapper around the original E values at the given index
* @param self :: A pointer to a PyObject representing the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readOnlyE, readE, wrapWithReadOnlyNumpy);

/*
* Create a read-only numpy wrapper around the original Dx values at the given index
* @param self :: A pointer to a PyObject representing the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readOnlyDx, readDx, wrapWithReadOnlyNumpy);

/*
* Create a read-only numpy wrapper around the original X values at the given index
* @param self :: A reference to the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readWriteX, readX, wrapWithNumpy);

/*
* Create a read-only numpy wrapper around the original Y values at the given index
* @param self :: A reference to the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readWriteY, readY, wrapWithNumpy);

/*
* Create a read-only numpy wrapper around the original E values at the given index
* @param self :: A pointer to a PyObject representing the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readWriteE, readE, wrapWithNumpy);

/*
* Create a read-only numpy wrapper around the original Dx values at the given index
* @param self :: A pointer to a PyObject representing the calling object
* @param index :: The index into the workspace
*/
DEFINE_ACCESS_FN(readWriteDx, readDx, wrapWithNumpy);


// -------------------------------------- Cloned arrays---------------------------------------------------
/* Create a numpy array from the X values of the given workspace reference
* This acts like a python method on a Matrixworkspace object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ namespace Mantid
{
namespace Numpy
{
/**
* Returns a pointer to the PyArray_Type object
* @return
*/
PyTypeObject * getNDArrayType()
{
return &PyArray_Type;
}


/**
* Create a numpy array wrapper around existing data. This is only possible for contiguous data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ def do_numpy_test(arr):
self.assertTrue(len(dx), 0)
self._do_numpy_comparison(self._test_ws, x, y, e, 0)

# Can we change something
ynow = y[0]
ynow *= 2.5
y[0] = ynow
self.assertEquals(self._test_ws.readY(0)[0], ynow)


def test_operators_with_workspaces_in_ADS(self):
run_algorithm('CreateWorkspace', OutputWorkspace='a',DataX=[1.,2.,3.], DataY=[2.,3.], DataE=[2.,3.],UnitX='TOF')
Expand Down

0 comments on commit c94b713

Please sign in to comment.