diff --git a/mfem/_par/array.i b/mfem/_par/array.i index f79e2833..d4c28c2d 100644 --- a/mfem/_par/array.i +++ b/mfem/_par/array.i @@ -134,10 +134,43 @@ namespace mfem{ %template(doubleSwap) Swap; %template(intSwap) Swap; } + +/* + Instantiation of Array templates. + + We instantiate some common use cases. Array.cpp instantiate these specialization. + + template class Array; + template class Array; + template class Array; + template class Array; + template class Array2D; + template class Array2D; +*/ + %import "../common/array_instantiation_macro.i" INSTANTIATE_ARRAY_INT INSTANTIATE_ARRAY_DOUBLE -IGNORE_ARRAY_METHODS(bool) +INSTANTIATE_ARRAY_NUMPYARRAY(int8, char, NPY_BYTE) // 8bit +INSTANTIATE_ARRAY_NUMPYARRAY(int64, long long, NPY_LONGLONG) // 64bit + +/* +For other classes, we need to ignore some methods + To ignore methos defined in Array.cpp, we use + IGNORE_ARRAY_METHODS_PREMITIVE + In more genral object, we need to futher ignore methods which uses comparision (> or == operators). + IGNORE_ARRAY_METHODS +*/ + +IGNORE_ARRAY_METHODS_PREMITIVE(bool) INSTANTIATE_ARRAY_BOOL +IGNORE_ARRAY_METHODS_PREMITIVE(unsigned int) +INSTANTIATE_ARRAY_NUMPYARRAY(uint, unsigned int, NPY_UINT) // 32bit +/* + for these Array2D, we instantiate it. But we dont extend it since, Array2D does not + expose the interanl pointer to array1d. +*/ +%template(intArray2D) mfem::Array2D; +%template(doubleArray2D) mfem::Array2D; diff --git a/mfem/_ser/array.i b/mfem/_ser/array.i index 5f0484ed..b65278c9 100644 --- a/mfem/_ser/array.i +++ b/mfem/_ser/array.i @@ -43,7 +43,7 @@ XXXPTR_SIZE_IN(bool *data_, int asize, bool) %pythonappend mfem::Array::Array %{ if len(args) == 1 and isinstance(args[0], list): if (len(args[0]) == 2 and hasattr(args[0][0], 'disown') and - not hasattr(args[0][1], 'disown')): + not hasattr(args[0][1], 'disown')): ## first element is SwigObject, like ## We do not own data in this case. pass @@ -147,8 +147,41 @@ namespace mfem{ %template(intSwap) Swap; } +/* + Instantiation of Array templates. + + We instantiate some common use cases. Array.cpp instantiate these specialization. + + template class Array; + template class Array; + template class Array; + template class Array; + template class Array2D; + template class Array2D; +*/ + %import "../common/array_instantiation_macro.i" INSTANTIATE_ARRAY_INT INSTANTIATE_ARRAY_DOUBLE -IGNORE_ARRAY_METHODS(bool) +INSTANTIATE_ARRAY_NUMPYARRAY(int8, char, NPY_BYTE) // for 8bit data +INSTANTIATE_ARRAY_NUMPYARRAY(int64, long long, NPY_LONGLONG) // 64bit + + /* +For other classes, we need to ignore some methods + To ignore methos defined in Array.cpp, we use + IGNORE_ARRAY_METHODS_PREMITIVE + In more genral object, we need to futher ignore methods which uses comparision (> or == operators). + IGNORE_ARRAY_METHODS + */ + +IGNORE_ARRAY_METHODS_PREMITIVE(bool) INSTANTIATE_ARRAY_BOOL +IGNORE_ARRAY_METHODS_PREMITIVE(unsigned int) +INSTANTIATE_ARRAY_NUMPYARRAY(uint, unsigned int, NPY_UINT) // 32bit + +/* + for these Array2D, we instantiate it. But we dont extend it since, Array2D does not + expose the interanl pointer to array1d. +*/ +%template(intArray2D) mfem::Array2D; +%template(doubleArray2D) mfem::Array2D; diff --git a/mfem/_ser/gslib.i b/mfem/_ser/gslib.i index 5a83a0b4..da079466 100644 --- a/mfem/_ser/gslib.i +++ b/mfem/_ser/gslib.i @@ -17,6 +17,7 @@ import_array(); %include "exception.i" %include "../common/typemap_macros.i" %include "../common/exception.i" +%import array.i %import vector.i %import mesh.i %import gridfunc.i diff --git a/mfem/common/array_instantiation_macro.i b/mfem/common/array_instantiation_macro.i index 8ac64b35..c7feb0f2 100644 --- a/mfem/common/array_instantiation_macro.i +++ b/mfem/common/array_instantiation_macro.i @@ -5,207 +5,298 @@ %template(##YYY##Array) mfem::Array; #endif %extend mfem::Array { - + PyObject * __getitem__(PyObject* param) { - int len = self->Size(); + int len = self->Size(); if (PySlice_Check(param)) { long start = 0, stop = 0, step = 0, slicelength = 0; int check; - //%#ifdef TARGET_PY3 - check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, - &slicelength); + //%#ifdef TARGET_PY3 + check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, + &slicelength); //%#else - //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, - // &slicelength); - //%#endif + //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, + // &slicelength); + //%#endif - if (check == -1) { + if (check == -1) { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array failed."); - return NULL; - } - if (step == 1) { - mfem::Array *vec; - vec = new mfem::Array(self->GetData() + start, slicelength); - return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); - } else { + return NULL; + } + if (step == 1) { + mfem::Array *vec; + vec = new mfem::Array(self->GetData() + start, slicelength); + return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); + } else { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array with stride>1 not supported."); - return NULL; - } + return NULL; + } } else { PyErr_Clear(); long idx = PyInt_AsLong(param); if (PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError, "Argument must be either int or slice"); - return NULL; + return NULL; } int own = 0; - swig_type_info *ty = $descriptor(const mfem::YYY *); + swig_type_info *ty = $descriptor(const mfem::YYY *); #if USEPTR == 1 - if (idx >= 0){ + if (idx >= 0){ return SWIG_NewPointerObj(SWIG_as_voidptr((self->operator[](idx))), ty, own); } else { - return SWIG_NewPointerObj(SWIG_as_voidptr((self->operator[](len+idx))), ty, own); - } + return SWIG_NewPointerObj(SWIG_as_voidptr((self->operator[](len+idx))), ty, own); + } #else if (idx >= 0){ return SWIG_NewPointerObj(SWIG_as_voidptr(&(self->operator[](idx))), ty, own); } else { - return SWIG_NewPointerObj(SWIG_as_voidptr(&(self->operator[](len+idx))), ty, own); - } - #endif + return SWIG_NewPointerObj(SWIG_as_voidptr(&(self->operator[](len+idx))), ty, own); + } + #endif } } }; %enddef %define INSTANTIATE_ARRAY(XXX) -INSTANTIATE_ARRAY0(XXX, XXX, 0) +INSTANTIATE_ARRAY0(XXX, XXX, 0) %enddef %define INSTANTIATE_ARRAY_INT %template(intArray) mfem::Array; -%extend mfem::Array { +%extend mfem::Array { PyObject * __getitem__(PyObject* param) { - int len = self->Size(); + int len = self->Size(); if (PySlice_Check(param)) { long start = 0, stop = 0, step = 0, slicelength = 0; int check; - //%#ifdef TARGET_PY3 - check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, - &slicelength); + //%#ifdef TARGET_PY3 + check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, + &slicelength); //%#else - //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, - // &slicelength); + //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, + // &slicelength); //%#endif - if (check == -1) { + if (check == -1) { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array failed."); - return NULL; - } - if (step == 1) { + return NULL; + } + if (step == 1) { mfem::Array *vec; vec = new mfem::Array(self->GetData() + start, slicelength); - return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); - } else { + return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); + } else { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array with stride>1 not supported."); - return NULL; - } + return NULL; + } } else { PyErr_Clear(); long idx = PyInt_AsLong(param); if (PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError, "Argument must be either int or slice"); - return NULL; + return NULL; } if (idx >= 0){ return PyLong_FromLong(self->operator[](idx)); } else { return PyLong_FromLong(self->operator[](len+idx)); - } + } } } + PyObject* GetDataArray(void) const{ + const int * A = self->GetData(); + int L = self->Size(); + npy_intp dims[] = {L}; + if (sizeof(int) == 4){ + return PyArray_SimpleNewFromData(1, dims, NPY_INT32, (void *)A); + } else { + // sizeof(int) == 8: + return PyArray_SimpleNewFromData(1, dims, NPY_INT64, (void *)A); + } + } + }; %enddef + %define INSTANTIATE_ARRAY_DOUBLE %template(doubleArray) mfem::Array; -%extend mfem::Array { +%extend mfem::Array { PyObject * __getitem__(PyObject* param) { - int len = self->Size(); + int len = self->Size(); if (PySlice_Check(param)) { long start = 0, stop = 0, step = 0, slicelength = 0; int check; - //%#ifdef TARGET_PY3 - check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, - &slicelength); + //%#ifdef TARGET_PY3 + check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, + &slicelength); //%#else - //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, - // &slicelength); - //%#endif + //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, + // &slicelength); + //%#endif - if (check == -1) { + if (check == -1) { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array failed."); - return NULL; - } - if (step == 1) { + return NULL; + } + if (step == 1) { mfem::Array *vec; vec = new mfem::Array(self->GetData() + start, slicelength); - return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); - } else { + return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); + } else { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array with stride>1 not supported."); - return NULL; - } + return NULL; + } } else { PyErr_Clear(); long idx = PyInt_AsLong(param); if (PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError, "Argument must be either int or slice"); - return NULL; + return NULL; } if (idx >= 0){ return PyFloat_FromDouble(self->operator[](idx)); } else { return PyFloat_FromDouble(self->operator[](len+idx)); - } + } } } + PyObject* GetDataArray(void) const{ + const double * A = self->GetData(); + int L = self->Size(); + npy_intp dims[] = {L}; + return PyArray_SimpleNewFromData(1, dims, NPY_FLOAT64, (void *)A); + } }; %enddef - + %define INSTANTIATE_ARRAY_BOOL %template(boolArray) mfem::Array; -%extend mfem::Array { +%extend mfem::Array { PyObject * __getitem__(PyObject* param) { - int len = self->Size(); + int len = self->Size(); if (PySlice_Check(param)) { long start = 0, stop = 0, step = 0, slicelength = 0; int check; - //%#ifdef TARGET_PY3 - check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, - &slicelength); + //%#ifdef TARGET_PY3 + check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, + &slicelength); //%#else - //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, - // &slicelength); - //%#endif + //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, + // &slicelength); + //%#endif - if (check == -1) { + if (check == -1) { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array failed."); - return NULL; - } - if (step == 1) { + return NULL; + } + if (step == 1) { mfem::Array *vec; vec = new mfem::Array(self->GetData() + start, slicelength); - return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); - } else { + return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); + } else { PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array with stride>1 not supported."); - return NULL; - } + return NULL; + } + } else { + PyErr_Clear(); + long idx = PyInt_AsLong(param); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "Argument must be either int or slice"); + return NULL; + } + if (idx >= 0){ + if (self->operator[](idx)){ + return Py_True; + } else { + return Py_False; + } + } else { + if (self->operator[](len+idx)){ + return Py_True; + } else { + return Py_False; + } + } + } + } + PyObject* GetDataArray(void) const{ + const bool* A = self->GetData(); + int L = self->Size(); + npy_intp dims[] = {L}; + return PyArray_SimpleNewFromData(1, dims, NPY_BOOL, (void *)A); + } + }; +%enddef + +// tool to deffine mfem::Array returining elements using numpy Scalar + // mfem::Array(unsigned int) -> uintArray + // NP_TYPE is things like NPY_FLOAT32 +%define INSTANTIATE_ARRAY_NUMPYARRAY(XXX, YYY, NP_TYPE) +%template(##XXX##Array) mfem::Array; +%extend mfem::Array { + PyObject * __getitem__(PyObject* param) { + int len = self->Size(); + if (PySlice_Check(param)) { + long start = 0, stop = 0, step = 0, slicelength = 0; + int check; + + //%#ifdef TARGET_PY3 + check = PySlice_GetIndicesEx(param, len, &start, &stop, &step, + &slicelength); + //%#else + //check = PySlice_GetIndicesEx((PySliceObject*)param, len, &start, &stop, &step, + // &slicelength); + //%#endif + + if (check == -1) { + PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array failed."); + return NULL; + } + if (step == 1) { + mfem::Array *vec; + vec = new mfem::Array(self->GetData() + start, slicelength); + return SWIG_NewPointerObj(SWIG_as_voidptr(vec), $descriptor(mfem::Array *), 1); + } else { + PyErr_SetString(PyExc_ValueError, "Slicing mfem::Array with stride>1 not supported."); + return NULL; + } } else { PyErr_Clear(); long idx = PyInt_AsLong(param); if (PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError, "Argument must be either int or slice"); - return NULL; + return NULL; } + PyObject *np_val = NULL; + PyArray_Descr *descr = NULL; + if(! (descr = PyArray_DescrFromType(NP_TYPE))) { + PyErr_SetString(PyExc_TypeError, "Improper descriptor"); + return NULL; + } + + YYY *data_ptr; if (idx >= 0){ - if (self->operator[](idx)){ - return Py_True; - } else { - return Py_False; - } + data_ptr = &(self->operator[](idx)); } else { - if (self->operator[](len+idx)){ - return Py_True; - } else { - return Py_False; - } - } + data_ptr = &(self->operator[](idx+len)); + } + np_val = PyArray_Scalar(data_ptr, descr, NULL); + return np_val; } } + PyObject* GetDataArray(void) const{ + const YYY * A = self->GetData(); + int L = self->Size(); + npy_intp dims[] = {L}; + return PyArray_SimpleNewFromData(1, dims, NP_TYPE, (void *)A); + } + }; %enddef @@ -226,5 +317,25 @@ INSTANTIATE_ARRAY0(XXX, XXX, 0) %ignore mfem::Array::PrintGZ; %ignore mfem::Array::SaveGZ; %ignore mfem::Array::Load; +%ignore mfem::Array2D::Print; +%ignore mfem::Array2D::PrintGZ; +%ignore mfem::Array2D::SaveGZ; +%enddef + + +%define IGNORE_ARRAY_METHODS_PREMITIVE(XXX) +%ignore mfem::Array::PartialSum; +%ignore mfem::Array::Sum; +%ignore mfem::Array::IsSorted; +%ignore mfem::Array::Save; +%ignore mfem::Array::Max; +%ignore mfem::Array::Min; +%ignore mfem::Array::Print; +%ignore mfem::Array::PrintGZ; +%ignore mfem::Array::SaveGZ; +%ignore mfem::Array::Load; +%ignore mfem::Array2D::Print; +%ignore mfem::Array2D::PrintGZ; +%ignore mfem::Array2D::SaveGZ; %enddef diff --git a/test/test_array2.py b/test/test_array2.py new file mode 100644 index 00000000..e2d92b78 --- /dev/null +++ b/test/test_array2.py @@ -0,0 +1,37 @@ +from __future__ import print_function +import os +import sys +import numpy as np + +if len(sys.argv) > 1 and sys.argv[1] == '-p': + import mfem.par as mfem + use_parallel = True + from mfem.common.mpi_debug import nicePrint as print + from mpi4py import MPI + myid = MPI.COMM_WORLD.rank + +else: + import mfem.ser as mfem + use_parallel = False + myid = 0 + +def run_test(): + a = mfem.uintArray(5) + b = mfem.int8Array(5) + c = mfem.int64Array(5) + d = mfem.boolArray(5) + + def check(a, value): + a.GetDataArray()[:] = value + print(a[0], a[-1], type(a[0]), ) + assert a[0] == value, "Array data element does not agree" + + + check(a, 5) + check(b, 100) + check(c, 1000) + check(d, True) + + +if __name__=='__main__': + run_test()