Loading...
Searching...
No Matches
PycArrayComCC.h
Go to the documentation of this file.
//# PycArrayCom.h: Common code to convert an Array to/from a Python array
//# Copyright (C) 2006
//# Associated Universities, Inc. Washington DC, USA.
//#
//# This library is free software; you can redistribute it and/or modify it
//# under the terms of the GNU Library General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or (at your
//# option) any later version.
//#
//# This library 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 Library General Public
//# License for more details.
//#
//# You should have received a copy of the GNU Library General Public License
//# along with this library; if not, write to the Free Software Foundation,
//# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
//#
//# Correspondence concerning AIPS++ should be addressed as follows:
//# Internet email: casa-feedback@nrao.edu.
//# Postal address: AIPS++ Project Office
//# National Radio Astronomy Observatory
//# 520 Edgemont Road
//# Charlottesville, VA 22903-2475 USA
#include <boost/python.hpp>
#include <numpy/arrayobject.h>
#if PY_MAJOR_VERSION >= 3
#define IS_PY3K
#endif
Bool PycArrayCheck (PyObject* obj_ptr)
{
if (!PyArray_API) {
if (!isImported()) return False;
loadAPI();
}
return PyArray_Check (obj_ptr);
}
Bool isImported()
{
using namespace boost::python;
// PySys_GetObject uses char* instead of const char*, so use a cast.
const char* modStr = "modules";
PyObject* mods = PySys_GetObject(const_cast<char*>(modStr));
dict d = extract<dict>(mods)();
return d.has_key(PYC_USE_PYARRAY);
}
void loadAPI()
{
if (!PyArray_API) {
if (!importArray() || !PyArray_API) {
throw AipsError ("PycArray: failed to load the " PYC_USE_PYARRAY
" API");
}
}
}
template <typename T> struct TypeConvTraits {
typedef T casa_type;
typedef void* python_type;
static NPY_TYPES pyType()
{ throw AipsError ("PycArray: unknown casa type"); }
};
template <> struct TypeConvTraits<casacore::Bool> {
typedef casacore::Bool casa_type;
typedef npy_bool python_type;
static NPY_TYPES pyType() { return NPY_BOOL; }
};
template <> struct TypeConvTraits<casacore::uChar> {
typedef casacore::uChar casa_type;
typedef npy_uint16 python_type; // Note: numarray uInt8 is Bool
static NPY_TYPES pyType() { return NPY_UINT16; }
};
template <> struct TypeConvTraits<casacore::Short> {
typedef casacore::Short casa_type;
typedef npy_int16 python_type;
static NPY_TYPES pyType() { return NPY_INT16; }
};
template <> struct TypeConvTraits<casacore::uShort> {
typedef casacore::uShort casa_type;
typedef npy_uint16 python_type;
static NPY_TYPES pyType() { return NPY_UINT16; }
};
template <> struct TypeConvTraits<casacore::Int> {
typedef casacore::Int casa_type;
typedef npy_int32 python_type;
static NPY_TYPES pyType() { return NPY_INT32; }
};
template <> struct TypeConvTraits<casacore::uInt> {
typedef casacore::uInt casa_type;
typedef npy_uint32 python_type;
static NPY_TYPES pyType() { return NPY_UINT32; }
};
template <> struct TypeConvTraits<casacore::Int64> {
typedef casacore::Int64 casa_type;
typedef npy_int64 python_type;
static NPY_TYPES pyType() { return NPY_INT64; }
};
template <> struct TypeConvTraits<casacore::uInt64> {
typedef casacore::uInt64 casa_type;
typedef npy_uint64 python_type;
static NPY_TYPES pyType() { return NPY_UINT64; }
};
template <> struct TypeConvTraits<casacore::Float> {
typedef casacore::Float casa_type;
typedef npy_float32 python_type;
static NPY_TYPES pyType() { return NPY_FLOAT32; }
};
template <> struct TypeConvTraits<casacore::Double> {
typedef casacore::Double casa_type;
typedef npy_float64 python_type;
static NPY_TYPES pyType() { return NPY_FLOAT64; }
};
template <> struct TypeConvTraits<casacore::Complex> {
typedef casacore::Complex casa_type;
typedef npy_complex64 python_type;
static NPY_TYPES pyType() { return NPY_COMPLEX64; }
};
template <> struct TypeConvTraits<casacore::DComplex> {
typedef casacore::DComplex casa_type;
typedef npy_complex128 python_type;
static NPY_TYPES pyType() { return NPY_COMPLEX128; }
};
template <> struct TypeConvTraits<casacore::String> {
typedef casacore::String casa_type;
typedef ::PyObject* python_type;
static NPY_TYPES pyType() { return NPY_OBJECT; }
};
// This one is only used to convert numpy BYTE and SBYTE to casa short.
// There is no back conversion, so an exception is thrown.
template <> struct TypeConvTraits<signed char> {
typedef signed char casa_type;
typedef npy_int8 python_type;
static NPY_TYPES pyType()
{ throw AipsError ("PycArray: unknown casa type"); }
};
template <typename T>
void ArrayCopy<T>::toPy (void* to, const T* from, size_t nr)
{
if (sizeof(T) == sizeof(typename TypeConvTraits<T>::python_type)) {
::memcpy (to, from, nr*sizeof(T));
} else {
typename TypeConvTraits<T>::python_type* dst =
static_cast<typename TypeConvTraits<T>::python_type*>(to);
for (size_t i=0; i<nr; i++) {
dst[i] = from[i];
}
}
}
template <typename T>
void ArrayCopy<T>::fromPy (T* to, const void* from, size_t nr)
{
if (sizeof(T) == sizeof(typename TypeConvTraits<T>::python_type)) {
::memcpy (to, from, nr*sizeof(T));
} else {
const typename TypeConvTraits<T>::python_type* src =
static_cast<const typename TypeConvTraits<T>::python_type*>(from);
for (size_t i=0; i<nr; i++) {
to[i] = src[i];
}
}
}
template <typename T>
Array<T> ArrayCopy<T>::toArray (const IPosition& shape,
void* data, bool copy)
{
// If the python array was contiguous, etc., we can directly use
// its data because the Array used is only temporary.
// However, if a copy of the Python array was made in PycArray.cc,
// we cannot do that because the Python copy is out of scope when
// the Array object gets used.
if (!copy) {
if (sizeof(T) == sizeof(typename TypeConvTraits<T>::python_type)) {
return Array<T> (shape, static_cast<T*>(data), SHARE);
}
}
Array<T> arr(shape);
fromPy (arr.data(), data, arr.size());
return arr;
}
void ArrayCopy<Complex>::toPy (void* to, const Complex* from, size_t nr)
{
if (sizeof(Complex) != sizeof(TypeConvTraits<Complex>::python_type)) {
throw AipsError("PycArray: size of Complex data type mismatches");
}
::memcpy (to, from, nr*sizeof(Complex));
}
void ArrayCopy<Complex>::fromPy (Complex* to, const void* from, size_t nr)
{
if (sizeof(Complex) != sizeof(TypeConvTraits<Complex>::python_type)) {
throw AipsError("PycArray: size of Complex data type mismatches");
}
::memcpy (to, from, nr*sizeof(Complex));
}
Array<Complex> ArrayCopy<Complex>::toArray (const IPosition& shape,
void* data, bool copy)
{
if (!copy) {
if (sizeof(Complex) == sizeof(TypeConvTraits<Complex>::python_type)) {
return Array<Complex> (shape, static_cast<Complex*>(data), SHARE);
}
}
Array<Complex> arr(shape);
fromPy (arr.data(), data, arr.size());
return arr;
}
void ArrayCopy<DComplex>::toPy (void* to, const DComplex* from, size_t nr)
{
if (sizeof(DComplex) != sizeof(TypeConvTraits<DComplex>::python_type)) {
throw AipsError("PycArray: size of DComplex data type mismatches");
}
::memcpy (to, from, nr*sizeof(DComplex));
}
void ArrayCopy<DComplex>::fromPy (DComplex* to, const void* from, size_t nr)
{
if (sizeof(DComplex) != sizeof(TypeConvTraits<DComplex>::python_type)) {
throw AipsError("PycArray: size of DComplex data type mismatches");
}
::memcpy (to, from, nr*sizeof(DComplex));
}
Array<DComplex> ArrayCopy<DComplex>::toArray (const IPosition& shape,
void* data, bool copy)
{
if (!copy) {
if (sizeof(DComplex) == sizeof(TypeConvTraits<DComplex>::python_type)) {
return Array<DComplex> (shape, static_cast<DComplex*>(data), SHARE);
}
}
Array<DComplex> arr(shape);
fromPy (arr.data(), data, arr.size());
return arr;
}
void ArrayCopy<String>::toPy (void* to, const String* from, size_t nr)
{
PyObject** dst = static_cast<PyObject**>(to);
for (size_t i=0; i<nr; i++) {
#ifdef IS_PY3K
dst[i] = PyUnicode_FromString(from[i].chars());
#else
dst[i] = PyString_FromString(from[i].chars());
#endif
}
}
void ArrayCopy<String>::fromPy (String* to, const void* from, size_t nr)
{
using namespace boost::python;
PyObject** src = (PyObject**)from;
for (size_t i=0; i<nr; i++) {
handle<> py_elem_hdl(src[i]);
object py_elem_obj(py_elem_hdl);
extract<String> elem_proxy(py_elem_obj);
to[i] = elem_proxy();
}
}
Array<String> ArrayCopy<String>::toArray (const IPosition& shape,
void* data, bool)
{
Array<String> arr(shape);
fromPy (arr.data(), data, arr.size());
return arr;
}
ValueHolder makeArray (PyObject* obj_ptr, Bool copyData)
{
if (! PycArrayCheck(obj_ptr)) {
throw AipsError ("PycArray: python object is not an array");
}
PyArrayObject* po = (PyArrayObject*)obj_ptr;
boost::python::object obj;
bool docopy = copyData; // copy data if wanted or needed
if (! PyArray_ISCONTIGUOUS(po)
|| ! PyArray_ISALIGNED(po)
|| PyArray_ISBYTESWAPPED(po)) {
boost::python::handle<> py_hdl(obj_ptr);
boost::python::object py_obj(py_hdl);
// incr refcount, because ~object decrements it
boost::python::incref(obj_ptr);
obj = py_obj.attr("copy")();
po = (PyArrayObject*)(obj.ptr());
docopy = true;
}
// Swap axes, because Casacore has row minor and Python row major order.
// A scalar is treated as a vector with length 1.
int nd = PyArray_NDIM(po);
IPosition shp(1, 1);
if (nd > 0) {
shp.resize (nd);
for (int i=0; i<nd; i++) {
shp[i] = PyArray_DIMS(po)[nd-i-1];
}
}
// Assert array is contiguous now.
// If the array is empty, numarray still sees it as non-contiguous.
if (shp.product() > 0) {
AlwaysAssert (PyArray_ISCONTIGUOUS(po)
&& !PyArray_ISBYTESWAPPED(po), AipsError);
}
// Create the correct array.
switch (PyArray_TYPE(po)) {
case NPY_BOOL:
return ValueHolder (ArrayCopy<Bool>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_INT16:
return ValueHolder (ArrayCopy<Short>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_UINT16:
return ValueHolder (ArrayCopy<uShort>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_INT32:
return ValueHolder (ArrayCopy<Int>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_UINT32:
return ValueHolder (ArrayCopy<uInt>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_INT64:
return ValueHolder (ArrayCopy<Int64>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_FLOAT32:
return ValueHolder (ArrayCopy<Float>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_FLOAT64:
return ValueHolder (ArrayCopy<Double>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_COMPLEX64:
return ValueHolder (ArrayCopy<Complex>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_COMPLEX128:
return ValueHolder (ArrayCopy<DComplex>::toArray(shp, PyArray_DATA(po), docopy));
case NPY_OBJECT:
return ValueHolder (ArrayCopy<String>::toArray(shp, PyArray_DATA(po), docopy));
default:
// Some types can be the same as other types, so they cannot
// be used in the switch (compiler complains).
// This is true for BYTE and SBYTE which can equal to BOOL in numarray.
// Similarly for STRING which exists for numpy and is set to
// INT for numarray.
if (PyArray_TYPE(po) == NPY_UINT64) {
Array<uInt64> arr = ArrayCopy<uInt64>::toArray(shp, PyArray_DATA(po), False);
Array<Int64> res(arr.shape());
convertArray (res, arr);
return ValueHolder(res);
} else if (PyArray_TYPE(po) == NPY_INT8) {
Array<signed char> arr = ArrayCopy<signed char>::toArray(shp, PyArray_DATA(po), False);
Array<Short> res(arr.shape());
convertArray (res, arr);
return ValueHolder(res);
} else if (PyArray_TYPE(po) == NPY_UINT8) {
// Copy using signed char, because uChar is mapped to Short in the Traits.
Array<signed char> arr = ArrayCopy<signed char>::toArray(shp, PyArray_DATA(po), False);
Array<Short> res(arr.shape());
void* varr = &arr;
Array<uChar>* uarr = static_cast<Array<uChar>*>(varr);
convertArray (res, *uarr);
return ValueHolder(res);
} else if (PyArray_TYPE(po) == NPY_STRING) {
size_t slen = 0;
if (nd > 0) {
slen = PyArray_STRIDES(po)[nd-1];
}
return ValueHolder (ArrayCopyStr_toArray(shp, PyArray_DATA(po), slen));
} else if (PyArray_TYPE(po) == NPY_UNICODE) {
size_t slen = 0;
if (nd > 0) {
slen = PyArray_STRIDES(po)[nd-1];
}
return ValueHolder (ArrayCopyUnicode_toArray(shp, PyArray_DATA(po), slen));
}
break;
}
throw AipsError ("PycArray: unknown python array data type");
}
// Instantiate the various templates.
template struct ArrayCopy<Bool>;
template struct ArrayCopy<signed char>;
template struct ArrayCopy<uChar>;
template struct ArrayCopy<Short>;
template struct ArrayCopy<uShort>;
template struct ArrayCopy<Int>;
template struct ArrayCopy<uInt>;
template struct ArrayCopy<Int64>;
template struct ArrayCopy<uInt64>;
template struct ArrayCopy<Float>;
template struct ArrayCopy<Double>;
template boost::python::object makePyArrayObject
(casacore::Array<Bool> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<uChar> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<Short> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<uShort> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<Int> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<uInt> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<Int64> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<Float> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<Double> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<Complex> const& arr);
template boost::python::object makePyArrayObject
(casacore::Array<DComplex> const& arr);
AlwaysAssert
#define AlwaysAssert(expr, exception)
These marcos are provided for use instead of simply using the assert_ function directly.
Definition Assert.h:134
makePyArrayObject
template boost::python::object makePyArrayObject(casacore::Array< Bool > const &arr)
PycArrayCheck
Bool PycArrayCheck(PyObject *obj_ptr)
Check if the PyObject is an array object.
Definition PycArrayComCC.h:35
isImported
Bool isImported()
Check if the API is or can be imported.
Definition PycArrayComCC.h:44
makeArray
ValueHolder makeArray(PyObject *obj_ptr, Bool copyData)
Convert the python array to a Casacore array in the ValueHolder.
Definition PycArrayComCC.h:278
loadAPI
void loadAPI()
Definition PycArrayComCC.h:54
ArrayCopyUnicode_toArray
Array< String > ArrayCopyUnicode_toArray(const IPosition &shape, void *data, size_t slen)
ArrayCopyStr_toArray
Array< String > ArrayCopyStr_toArray(const IPosition &shape, void *data, size_t slen)
importArray
Bool importArray()
PYC_USE_PYARRAY
#define PYC_USE_PYARRAY
Definition PycArrayNP.h:39
casacore::Array
Definition Array.h:155
casacore::String
String: the storage and methods of handling collections of characters.
Definition String.h:223
casacore
this file contains all the compiler specific defines
Definition mainpage.dox:28
casacore::uChar
unsigned char uChar
Definition aipstype.h:45
casacore::Short
short Short
Definition aipstype.h:46
casacore::uInt
unsigned int uInt
Definition aipstype.h:49
casacore::uShort
unsigned short uShort
Definition aipstype.h:47
casacore::Int64
long long Int64
Define the extra non-standard types used by Casacore (like proposed uSize, Size).
Definition aipsxtype.h:36
casacore::Float
float Float
Definition aipstype.h:52
casacore::Int
int Int
Definition aipstype.h:48
casacore::Bool
bool Bool
Define the standard types used by Casacore.
Definition aipstype.h:40
casacore::Double
double Double
Definition aipstype.h:53
casacore::uInt64
unsigned long long uInt64
Definition aipsxtype.h:37
ArrayCopy< Complex >::fromPy
static void fromPy(Complex *to, const void *from, size_t nr)
Definition PycArrayComCC.h:199
ArrayCopy< DComplex >::fromPy
static void fromPy(DComplex *to, const void *from, size_t nr)
Definition PycArrayComCC.h:227
ArrayCopy< String >::fromPy
static void fromPy(String *to, const void *from, size_t nr)
Definition PycArrayComCC.h:259
ArrayCopy
Copy/convert the array data as needed.
Definition PycArrayComH.h:47
ArrayCopy::toPy
static void toPy(void *to, const T *from, size_t nr)
Definition PycArrayComCC.h:147
ArrayCopy::fromPy
static void fromPy(T *to, const void *from, size_t nr)
Definition PycArrayComCC.h:160
ArrayCopy::toArray
static Array< T > toArray(const IPosition &shape, void *data, bool copy)
Definition PycArrayComCC.h:173
TypeConvTraits< casacore::Bool >::casa_type
casacore::Bool casa_type
Definition PycArrayComCC.h:72
TypeConvTraits< casacore::Bool >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:74
TypeConvTraits< casacore::Bool >::python_type
npy_bool python_type
Definition PycArrayComCC.h:73
TypeConvTraits< casacore::Complex >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:124
TypeConvTraits< casacore::Complex >::casa_type
casacore::Complex casa_type
Definition PycArrayComCC.h:122
TypeConvTraits< casacore::Complex >::python_type
npy_complex64 python_type
Definition PycArrayComCC.h:123
TypeConvTraits< casacore::DComplex >::python_type
npy_complex128 python_type
Definition PycArrayComCC.h:128
TypeConvTraits< casacore::DComplex >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:129
TypeConvTraits< casacore::DComplex >::casa_type
casacore::DComplex casa_type
Definition PycArrayComCC.h:127
TypeConvTraits< casacore::Double >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:119
TypeConvTraits< casacore::Double >::python_type
npy_float64 python_type
Definition PycArrayComCC.h:118
TypeConvTraits< casacore::Double >::casa_type
casacore::Double casa_type
Definition PycArrayComCC.h:117
TypeConvTraits< casacore::Float >::python_type
npy_float32 python_type
Definition PycArrayComCC.h:113
TypeConvTraits< casacore::Float >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:114
TypeConvTraits< casacore::Float >::casa_type
casacore::Float casa_type
Definition PycArrayComCC.h:112
TypeConvTraits< casacore::Int64 >::casa_type
casacore::Int64 casa_type
Definition PycArrayComCC.h:102
TypeConvTraits< casacore::Int64 >::python_type
npy_int64 python_type
Definition PycArrayComCC.h:103
TypeConvTraits< casacore::Int64 >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:104
TypeConvTraits< casacore::Int >::casa_type
casacore::Int casa_type
Definition PycArrayComCC.h:92
TypeConvTraits< casacore::Int >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:94
TypeConvTraits< casacore::Int >::python_type
npy_int32 python_type
Definition PycArrayComCC.h:93
TypeConvTraits< casacore::Short >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:84
TypeConvTraits< casacore::Short >::python_type
npy_int16 python_type
Definition PycArrayComCC.h:83
TypeConvTraits< casacore::Short >::casa_type
casacore::Short casa_type
Definition PycArrayComCC.h:82
TypeConvTraits< casacore::String >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:134
TypeConvTraits< casacore::String >::python_type
::PyObject * python_type
Definition PycArrayComCC.h:133
TypeConvTraits< casacore::String >::casa_type
casacore::String casa_type
Definition PycArrayComCC.h:132
TypeConvTraits< casacore::uChar >::python_type
npy_uint16 python_type
Definition PycArrayComCC.h:78
TypeConvTraits< casacore::uChar >::casa_type
casacore::uChar casa_type
Definition PycArrayComCC.h:77
TypeConvTraits< casacore::uChar >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:79
TypeConvTraits< casacore::uInt64 >::python_type
npy_uint64 python_type
Definition PycArrayComCC.h:108
TypeConvTraits< casacore::uInt64 >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:109
TypeConvTraits< casacore::uInt64 >::casa_type
casacore::uInt64 casa_type
Definition PycArrayComCC.h:107
TypeConvTraits< casacore::uInt >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:99
TypeConvTraits< casacore::uInt >::python_type
npy_uint32 python_type
Definition PycArrayComCC.h:98
TypeConvTraits< casacore::uInt >::casa_type
casacore::uInt casa_type
Definition PycArrayComCC.h:97
TypeConvTraits< casacore::uShort >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:89
TypeConvTraits< casacore::uShort >::casa_type
casacore::uShort casa_type
Definition PycArrayComCC.h:87
TypeConvTraits< casacore::uShort >::python_type
npy_uint16 python_type
Definition PycArrayComCC.h:88
TypeConvTraits< signed char >::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:141
TypeConvTraits< signed char >::casa_type
signed char casa_type
Definition PycArrayComCC.h:139
TypeConvTraits< signed char >::python_type
npy_int8 python_type
Definition PycArrayComCC.h:140
TypeConvTraits
Definition PycArrayComCC.h:65
TypeConvTraits::python_type
void * python_type
Definition PycArrayComCC.h:67
TypeConvTraits::pyType
static NPY_TYPES pyType()
Definition PycArrayComCC.h:68
TypeConvTraits::casa_type
T casa_type
Definition PycArrayComCC.h:66