1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
// In the code, one utilizes calls equvalent to PyArray API,
// except instead of PyArray_BYTES one uses Array_BYTES.
// Then, if GPAW is built with GPAW_GPU_AWARE_MPI define, these macros are rewritten with wrappers.
#ifndef GPAW_ARRAY_ALLOW_CUPY
#ifdef GPAW_ARRAY_DISABLE_NUMPY
#error "No CPAW_ARRAY_ALLOW_CUPY and GPAW_ARRAY_DISABLE_NUMPY is set. No array interfaces remain."
#endif
// Check that array is well-behaved and contains data that can be sent.
#define CHK_ARRAY(a) if ((a) == NULL || !PyArray_Check(a) \
|| !PyArray_ISCARRAY((PyArrayObject*)a) \
|| !PyArray_ISNUMBER((PyArrayObject*)a)) { \
PyErr_SetString(PyExc_TypeError, \
"Not a proper NumPy array for MPI communication."); \
return NULL; } else
// Check that array is well-behaved, read-only and contains data that
// can be sent.
#define CHK_ARRAY_RO(a) if ((a) == NULL || !PyArray_Check(a) \
|| !PyArray_ISCARRAY_RO((PyArrayObject*)a) \
|| !PyArray_ISNUMBER((PyArrayObject*)a)) { \
PyErr_SetString(PyExc_TypeError, \
"Not a proper NumPy array for MPI communication."); \
return NULL; } else
// Check that two arrays have the same type, and the size of the
// second is a given multiple of the size of the first
#define CHK_ARRAYS(a,b,n) \
if ((PyArray_TYPE((PyArrayObject*)a) != PyArray_TYPE((PyArrayObject*)b)) \
|| (PyArray_SIZE((PyArrayObject*)b) != PyArray_SIZE((PyArrayObject*)a) * n)) { \
PyErr_SetString(PyExc_ValueError, \
"Incompatible array types or sizes."); \
return NULL; } else
#define Array_NDIM(a) PyArray_NDIM((PyArrayObject*)a)
#define Array_DIM(a,d) PyArray_DIM((PyArrayObject*)a,d)
#define Array_ITEMSIZE(a) PyArray_ITEMSIZE((PyArrayObject*)a)
#define Array_BYTES(a) PyArray_BYTES((PyArrayObject*)a)
#define Array_DATA(a) PyArray_DATA((PyArrayObject*)a)
#define Array_SIZE(a) PyArray_SIZE((PyArrayObject*)a)
#define Array_TYPE(a) PyArray_TYPE((PyArrayObject*)a)
#define Array_NBYTES(a) PyArray_NBYTES((PyArrayObject*)a)
#define Array_ISCOMPLEX(a) PyArray_ISCOMPLEX((PyArrayObject*)a)
#else // GPAW_ARRAY_ALLOW_CUPY
#define CHK_ARRAY(a) // TODO
#define CHK_ARRAY_RO(a) // TODO
#define CHK_ARRAYS(a,b,n) // TODO
#include <stdio.h>
static inline int Array_NDIM(PyObject* obj)
{
#ifndef GPAW_ARRAY_DISABLE_NUMPY
if (PyArray_Check(obj))
{
return PyArray_NDIM((PyArrayObject*)obj);
}
#endif
// return len(obj.shape)
PyObject* shape = PyObject_GetAttrString(obj, "shape");
if (shape == NULL) return -1;
Py_DECREF(shape);
return PyTuple_Size(shape);
}
static inline int Array_DIM(PyObject* obj, int dim)
{
#ifndef GPAW_ARRAY_DISABLE_NUMPY
if (PyArray_Check(obj))
{
return PyArray_DIM((PyArrayObject*)obj, dim);
}
#endif
PyObject* shape = PyObject_GetAttrString(obj, "shape");
if (shape == NULL) return -1;
PyObject* pydim = PyTuple_GetItem(shape, dim);
Py_DECREF(shape);
if (pydim == NULL) return -1;
int value = (int) PyLong_AS_LONG(pydim);
return value;
}
static inline char* Array_BYTES(PyObject* obj)
{
#ifndef GPAW_ARRAY_DISABLE_NUMPY
if (PyArray_Check(obj))
{
return PyArray_BYTES((PyArrayObject*)obj);
}
#endif
// Equivalent to obj.data.ptr
PyObject* ndarray_data = PyObject_GetAttrString(obj, "data");
if (ndarray_data == NULL) return NULL;
PyObject* ptr_data = PyObject_GetAttrString(ndarray_data, "ptr");
if (ptr_data == NULL) return NULL;
char* ptr = (char*) PyLong_AS_LONG(ptr_data);
Py_DECREF(ptr_data);
Py_DECREF(ndarray_data);
return ptr;
}
#define Array_DATA(a) ((void*) Array_BYTES(a))
static inline int Array_SIZE(PyObject* obj)
{
PyObject* size = PyObject_GetAttrString(obj, "size");
int arraysize = (int) PyLong_AS_LONG(size);
Py_DECREF(size);
return arraysize;
}
static inline int Array_TYPE(PyObject* obj)
{
#ifndef GPAW_ARRAY_DISABLE_NUMPY
if (PyArray_Check(obj))
{
return PyArray_TYPE((PyArrayObject*)obj);
}
#endif
PyObject* dtype = PyObject_GetAttrString(obj, "dtype");
if (dtype == NULL) return -1;
PyObject* num = PyObject_GetAttrString(dtype, "num");
Py_DECREF(dtype);
if (num == NULL) return -1;
int value = (int) PyLong_AS_LONG(num);
Py_DECREF(num);
return value;
}
static inline int Array_ITEMSIZE(PyObject* obj)
{
#ifndef GPAW_ARRAY_DISABLE_NUMPY
if (PyArray_Check(obj))
{
return PyArray_ITEMSIZE((PyArrayObject*)obj);
}
#endif
PyObject* dtype = PyObject_GetAttrString(obj, "dtype");
if (dtype == NULL) return -1;
PyObject* itemsize_obj = PyObject_GetAttrString(dtype, "itemsize");
if (itemsize_obj == NULL) return -1;
int itemsize = (int) PyLong_AS_LONG(itemsize_obj);
Py_DECREF(itemsize_obj);
Py_DECREF(dtype);
return itemsize;
}
static inline long Array_NBYTES(PyObject* obj)
{
#ifndef GPAW_ARRAY_DISABLE_NUMPY
if (PyArray_Check(obj))
{
return PyArray_NBYTES((PyArrayObject*)obj);
}
#endif
PyObject* nbytes = PyObject_GetAttrString(obj, "nbytes");
long nbytesvalue = PyLong_AS_LONG(nbytes);
Py_DECREF(nbytes);
return nbytesvalue;
}
static inline int Array_ISCOMPLEX(PyObject* obj)
{
int result = PyTypeNum_ISCOMPLEX(Array_TYPE(obj));
return result;
}
static inline void print_array_info(PyObject* obj)
{
if (PyArray_Check(obj))
{
printf("numpy ");
}
if (Array_ISCOMPLEX(obj))
{
printf("complex ");
}
printf("itemsize: %d", Array_ITEMSIZE(obj));
printf("typenum %d", Array_TYPE(obj));
printf("shape: [");
for (int i=0; i<Array_NDIM(obj); i++)
{
printf("%d", Array_DIM(obj, i));
if (i != Array_NDIM(obj) - 1)
{
printf(", ");
}
else
{
printf("]");
}
printf("\n");
}
}
#endif
|