Skip to content

Commit

Permalink
Refs #4315. Finish off geometry exports
Browse files Browse the repository at this point in the history
This required a const to be added to a member of Matrix and
similarly to OrientedLattice.
  • Loading branch information
martyngigg committed Dec 14, 2011
1 parent 37b5f6e commit 199d27c
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ namespace Geometry
// Access private variables
const Kernel::DblMatrix& getU() const;
const Kernel::DblMatrix& getUB() const;
void setU(Kernel::DblMatrix& newU);
void setUB(Kernel::DblMatrix& newUB);
void setU(const Kernel::DblMatrix& newU);
void setUB(const Kernel::DblMatrix& newUB);
//get u and v vectors for Horace/Mslice
Kernel::V3D getuVector();
Kernel::V3D getvVector();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace Geometry

/** Sets the U matrix
@param newU :: the new U matrix*/
void OrientedLattice::setU(DblMatrix& newU)
void OrientedLattice::setU(const DblMatrix& newU)
{
if (newU.isRotation()==true)
{
Expand All @@ -108,7 +108,7 @@ namespace Geometry

/** Sets the UB matrix and recalculates lattice parameters
@param newUB :: the new UB matrix*/
void OrientedLattice::setUB(DblMatrix& newUB)
void OrientedLattice::setUB(const DblMatrix& newUB)
{
if (UB.determinant()>0)
{
Expand Down
4 changes: 2 additions & 2 deletions Code/Mantid/Framework/Kernel/inc/MantidKernel/Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ namespace Mantid
T compSum() const;

// Check if a rotation matrix
bool isRotation();
bool isRotation() const;
// Check if orthogonal
bool isOrthogonal();
bool isOrthogonal() const;
// Transform to a rotation matrix
std::vector<T> toRotation();
private:
Expand Down
4 changes: 2 additions & 2 deletions Code/Mantid/Framework/Kernel/src/Matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1645,7 +1645,7 @@ Matrix<T>::Diagonalise(Matrix<T>& EigenVec,Matrix<T>& DiagMatrix) const
}

template<typename T>
bool Matrix<T>::isRotation()
bool Matrix<T>::isRotation() const
/** Check if a matrix represents a proper rotation
@ return :: true/false
*/
Expand All @@ -1666,7 +1666,7 @@ bool Matrix<T>::isRotation()
}

template<typename T>
bool Matrix<T>::isOrthogonal()
bool Matrix<T>::isOrthogonal() const
/** Check if a matrix is orthogonal. Same as isRotation, but allows determinant to be -1
@ return :: true/false
*/
Expand Down
4 changes: 2 additions & 2 deletions Code/Mantid/Framework/PythonInterface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ set ( TEST_PY_FILES
test/python/InstrumentTest.py
test/python/LoggerTest.py
test/python/MatrixWorkspaceTest.py
test/python/OrientedLatticeTest.py
test/python/PythonPluginsTest.py
test/python/PropertyWithValueTest.py
test/python/PythonAlgorithmTest.py
Expand All @@ -90,8 +91,7 @@ set ( TEST_PY_FILES
test/python/WorkspaceTest.py
)

set ( PYTEST_HELPERS test/python/testhelpers.py
)
set ( PYTEST_HELPERS test/python/testhelpers.py )

# python unit tests
if (PYUNITTEST_FOUND)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <boost/python/object.hpp> //Safer way to include Python.h
#include <vector>
#include "MantidKernel/Matrix.h"
#include "MantidKernel/V3D.h"

namespace Mantid
{
Expand All @@ -46,7 +47,10 @@ namespace Mantid

/** @name Create Mantid objects from python sequences */
//@{
DLLExport Kernel::DblMatrix createMatrixFromNumpyArray(PyObject* data);
/// 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
Expand Up @@ -17,6 +17,7 @@ set ( EXPORT_FILES
src/DetectorGroup.cpp
src/Instrument.cpp
src/UnitCell.cpp
src/OrientedLattice.cpp
)

set ( SRC_FILES
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "MantidGeometry/Crystal/OrientedLattice.h"
#include "MantidPythonInterface/kernel/NumpyConverters.h"
#include <boost/python/class.hpp>

using Mantid::Geometry::OrientedLattice;
using Mantid::Geometry::UnitCell;
using Mantid::Geometry::angDegrees;
using namespace boost::python;

namespace //<unnamed>
{
using namespace Mantid::PythonInterface;

/// Return the U matrix as a 2D numpy array
PyObject * getU(OrientedLattice &self)
{
return Numpy::wrapWithReadOnlyNumpy(self.getU());
}

/// Set the U vector via a numpy array
void setU(OrientedLattice & self, PyObject *data)
{
self.setU(Numpy::createDoubleMatrix(data));
}

/// Return the U matrix as a 2D numpy array
PyObject * getUB(OrientedLattice &self)
{
return Numpy::wrapWithReadOnlyNumpy(self.getUB());
}

/// Set the U vector via a numpy array
void setUB(OrientedLattice & self, PyObject *data)
{
self.setUB(Numpy::createDoubleMatrix(data));
}

/// 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)
{
self.setUFromVectors(Numpy::createV3D(vec1), Numpy::createV3D(vec2));
}

}

void export_OrientedLattice()
{
class_<OrientedLattice, bases<UnitCell> >("OrientedLattice", init< >())
.def( init< OrientedLattice const & >(( arg("other") )) )
.def( init< double, double, double >(( arg("_a"), arg("_b"), arg("_c") )) )
.def( init< double, double, double, double, double, double,
optional< int > >(( arg("_a"), arg("_b"), arg("_c"), arg("_alpha"), arg("_beta"), arg("_gamma"), arg("Unit")=(int)(angDegrees) )) )
.def( init<UnitCell>( arg("uc") ) )
.def( "getuVector", (&OrientedLattice::getuVector))
.def( "getvVector", (&OrientedLattice::getvVector))
.def( "getU", &getU )
.def( "setU", &setU )
.def( "getUB",&getUB )
.def( "setUB",&setUB )
.def( "setUFromVectors", &setUFromVectors)

;
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,38 @@ using Mantid::Geometry::AngleUnits;
using Mantid::Geometry::angRadians;
using Mantid::Geometry::angDegrees;
using Mantid::Kernel::DblMatrix;
using Mantid::Kernel::V3D;
using namespace boost::python;

// Functions purely to aid with wrapping
namespace //<unnamed>
{
using namespace Mantid::PythonInterface;

/// Pass-through function to return the B matrix as a numpy array
PyObject * getB(UnitCell& self)
{
return Numpy::wrapWithReadOnlyNumpy(self.getB());
}

/// Pass-through function to return the B matrix as a numpy array
PyObject * getG(UnitCell& self)
{
return Numpy::wrapWithReadOnlyNumpy(self.getG());
}


/// Pass-through function to return the B matrix as a numpy array
PyObject * getGstar(UnitCell& self)
{
return Numpy::wrapWithReadOnlyNumpy(self.getGstar());
}

/// Pass-through function to set the unit cell from a 2D numpy array
void recalculateFromGstar(UnitCell & self, PyObject* values)
{
// Create a double matrix and put this in to the unit cell
self.recalculateFromGstar(Mantid::PythonInterface::Numpy::createMatrixFromNumpyArray(values));
self.recalculateFromGstar(Numpy::createDoubleMatrix(values));
}
}

Expand Down Expand Up @@ -54,7 +77,8 @@ void export_UnitCell()
.def( "bstar", (double ( UnitCell::* )() const) &UnitCell::bstar )
.def( "c", (double ( UnitCell::* )() const) &UnitCell::c )
.def( "cstar", (double ( UnitCell::* )() const) &UnitCell::cstar )
.def( "d", (double ( UnitCell::* )( double,double,double ) const) &UnitCell::d, (arg("h"), arg("k"), arg("l") ))
.def( "d", (double ( UnitCell::* )( double,double,double ) const) &UnitCell::d, (arg("h"), arg("k"), arg("l") ))
.def( "d", (double ( UnitCell::* )(const V3D &) const) &UnitCell::d, (arg("hkl")))
.def( "dstar", (double ( UnitCell::* )( double,double,double ) const) &UnitCell::dstar , (arg("h"), arg("k"), arg("l") ))
.def( "gamma", (double ( UnitCell::* )() const) &UnitCell::gamma )
.def( "gammastar", (double ( UnitCell::* )() const) &UnitCell::gammastar )
Expand All @@ -68,9 +92,9 @@ void export_UnitCell()
.def( "setc", (void ( UnitCell::* )( double ) )( &UnitCell::setc ), ( arg("_c") ) )
.def( "setgamma", (void ( UnitCell::* )( double,int const ) )( &UnitCell::setgamma ), ( arg("_gamma"), arg("Unit")=(int)(angDegrees) ) )
.def( "volume", (double ( UnitCell::* )() const) &UnitCell::volume)
// .def( "getG", &UnitCellWrapper::getG)
// .def( "getGstar", &UnitCellWrapper::getGstar)
//.def( "getB", &getB )
.def( "getG", &getG)
.def( "getGstar", &getGstar)
.def( "getB", &getB )
.def( "recalculateFromGstar", &recalculateFromGstar)
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,73 @@ namespace Mantid
return (PyObject*)nparray;
}

//--------------------------------------------------------------------------------------------
// 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
* @param data A python object that points to a 2D numpy array
* @return A Matrix<double> created from the input array
*/
Kernel::DblMatrix createMatrixFromNumpyArray(PyObject *data)
Kernel::DblMatrix createDoubleMatrix(PyObject *data)
{
using namespace boost::python;
if( PyArray_Check(data) )
Expand All @@ -81,7 +142,8 @@ namespace Mantid
if( boost::python::len(shape) != 2 )
{
std::ostringstream msg;
msg << "createMatrixFromNumpyArray - Expected an array with 2 dimensions but was given array with " << boost::python::len(shape) << " dimensions.";
msg << "createDoubleMatrix - Expected an array with 2 dimensions but was given array with "
<< boost::python::len(shape) << " dimensions.";
throw std::invalid_argument(msg.str());
}
size_t nx = boost::python::extract<size_t>(shape[0]);
Expand All @@ -98,7 +160,7 @@ namespace Mantid
}
else
{
throw std::invalid_argument(std::string("createMatrixFromNumpyArray - Expected numpy array as input, found ") + data->ob_type->tp_name);
throw std::invalid_argument(std::string("createDoubleMatrix - Expected numpy array as input, found ") + data->ob_type->tp_name);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import unittest
from mantid.geometry import OrientedLattice, UnitCell
from mantid.kernel import V3D
import numpy as np

class OrientedLatticeTest(unittest.TestCase):

def test_OrientedLattice_is_subclass_of_UnitCell(self):
self.assertTrue(issubclass(OrientedLattice, UnitCell))

def test_simple_values(self):
u1 = OrientedLattice()
self.assertEquals(u1.a1(),1)
self.assertEquals(u1.alpha(),90)

u2 = OrientedLattice(3,4,5)
self.assertAlmostEqual(u2.b1(),1./3.,10)
self.assertAlmostEqual(u2.alphastar(),90,10)
u3 = u2;
self.assertAlmostEqual(u3.volume(),1./u2.recVolume(),10)
u2.seta(3);
self.assertAlmostEqual(u2.a(),3,10)

def test_setu_matrix_from_vectors(self):
def run_test(v1, v2):
cell = OrientedLattice()
try:
cell.setUFromVectors(v1, v2)
except RuntimeError:
self.fail("The unit transformation should not raise an error")
rot = cell.getUB();
expected = np.array([(0,1.,0.), (0.,0.,1.), (1.,0.,0.)])
np.testing.assert_array_almost_equal(expected, rot, 8)

# Set from V3Ds
run_test(V3D(1,0,0),V3D(0,1,0))
# Set from Python lists
run_test([1,0,0],[0,1,0])
# Set from numpy arrays
run_test(np.array([1,0,0]),np.array([0,1,0]))


if __name__ == '__main__':
unittest.main()

0 comments on commit 199d27c

Please sign in to comment.