From 12598866eeb7325606972d4d553cf126f103d5a5 Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Thu, 15 Aug 2024 20:28:42 -0700 Subject: [PATCH 1/2] fixing Array2D wrapping --- mfem/_par/array.i | 59 +++++++++++++++++++++--- mfem/_ser/array.i | 60 ++++++++++++++++++++++--- mfem/common/array_instantiation_macro.i | 2 + test/test_blockmatrix.py | 4 ++ 4 files changed, 115 insertions(+), 10 deletions(-) diff --git a/mfem/_par/array.i b/mfem/_par/array.i index 95382e40..aa466eec 100644 --- a/mfem/_par/array.i +++ b/mfem/_par/array.i @@ -167,13 +167,62 @@ INSTANTIATE_ARRAY_BOOL IGNORE_ARRAY_METHODS_PREMITIVE(unsigned int) INSTANTIATE_ARRAY_NUMPYARRAY(uint, unsigned int, NPY_UINT) // 32bit +/* Array< Array *> */ +IGNORE_ARRAY_METHODS(mfem::Array *) +INSTANTIATE_ARRAY2(Array *, Array, intArray, 1) + /* - for these Array2D, we instantiate it. But we dont extend it since, Array2D does not - expose the interanl pointer to array1d. + Array2D:: Assign and data access */ + +%extend mfem::Array2D{ + void Assign(const T &a){ + *self = a; + } + void Assign(const mfem::Array2D &a){ + *self = a; + } + + void __setitem__(PyObject* param, const T v) { + if (PyTuple_Check(param)) { + PyErr_Clear(); + int i = PyInt_AsLong(PyTuple_GetItem(param, 0)); + int j = PyInt_AsLong(PyTuple_GetItem(param, 1)); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "Argument must be i, j"); + return; + } + T *arr = self -> GetRow(i); + arr[j] = v; + } + } + T __getitem__(PyObject* param) { + if (PyTuple_Check(param)) { + PyErr_Clear(); + int i = PyInt_AsLong(PyTuple_GetItem(param, 0)); + int j = PyInt_AsLong(PyTuple_GetItem(param, 1)); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "Argument must be i, j"); + i = 0; + j = 0; + } + T *arr = self -> GetRow(i); + return arr[j]; + } + } +} %template(intArray2D) mfem::Array2D; %template(doubleArray2D) mfem::Array2D; -/* Array< Array *> */ -IGNORE_ARRAY_METHODS(mfem::Array *) -INSTANTIATE_ARRAY2(Array *, Array, intArray, 1) +/* Array2D<* DenseMatrix>, Array2D<* SparseMatrix>, Array2D<* HypreParMatrix> */ + +IGNORE_ARRAY_METHODS(mfem::DenseMatrix *) +IGNORE_ARRAY_METHODS(mfem::SparseMatrix *) +IGNORE_ARRAY_METHODS(mfem::HypreParMatrix *) + +%template(densematArray2D) mfem::Array2D; +%template(sparsematArray2D) mfem::Array2D; +%template(hypreparmatArray2D) mfem::Array2D; + diff --git a/mfem/_ser/array.i b/mfem/_ser/array.i index 5d9f8e2a..c5699820 100644 --- a/mfem/_ser/array.i +++ b/mfem/_ser/array.i @@ -179,14 +179,64 @@ INSTANTIATE_ARRAY_BOOL IGNORE_ARRAY_METHODS_PREMITIVE(unsigned int) INSTANTIATE_ARRAY_NUMPYARRAY(uint, unsigned int, NPY_UINT) // 32bit +/* Array< Array *> */ +IGNORE_ARRAY_METHODS(mfem::Array *) +INSTANTIATE_ARRAY2(Array *, Array, intArray, 1) + /* - for these Array2D, we instantiate it. But we dont extend it since, Array2D does not - expose the interanl pointer to array1d. + Array2D:: Assign and data access */ + +%extend mfem::Array2D{ + void Assign(const T &a){ + *self = a; + } + void Assign(const mfem::Array2D &a){ + *self = a; + } + + void __setitem__(PyObject* param, const T v) { + if (PyTuple_Check(param)) { + PyErr_Clear(); + int i = PyInt_AsLong(PyTuple_GetItem(param, 0)); + int j = PyInt_AsLong(PyTuple_GetItem(param, 1)); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "Argument must be i, j"); + return; + } + T *arr = self -> GetRow(i); + arr[j] = v; + } + } + T __getitem__(PyObject* param) { + if (PyTuple_Check(param)) { + PyErr_Clear(); + int i = PyInt_AsLong(PyTuple_GetItem(param, 0)); + int j = PyInt_AsLong(PyTuple_GetItem(param, 1)); + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "Argument must be i, j"); + i = 0; + j = 0; + } + T *arr = self -> GetRow(i); + return arr[j]; + } + } +} + %template(intArray2D) mfem::Array2D; %template(doubleArray2D) mfem::Array2D; -/* Array< Array *> */ -IGNORE_ARRAY_METHODS(mfem::Array *) -INSTANTIATE_ARRAY2(Array *, Array, intArray, 1) +/* Array2D<* DenseMatrix>, Array2D<* SparseMatrix>, Array2D<* HypreParMatrix> */ + +IGNORE_ARRAY_METHODS(mfem::DenseMatrix *) +IGNORE_ARRAY_METHODS(mfem::SparseMatrix *) + +%template(densematArray2D) mfem::Array2D; +%template(sparsematArray2D) mfem::Array2D; +//%template(hypreparmatArray2D) mfem::Array2D; + + diff --git a/mfem/common/array_instantiation_macro.i b/mfem/common/array_instantiation_macro.i index aac07719..c684e8dd 100644 --- a/mfem/common/array_instantiation_macro.i +++ b/mfem/common/array_instantiation_macro.i @@ -325,6 +325,8 @@ INSTANTIATE_ARRAY2(XXX, YYY, YYY, USEPTR) %ignore mfem::Array2D::Print; %ignore mfem::Array2D::PrintGZ; %ignore mfem::Array2D::SaveGZ; +%ignore mfem::Array2D::Load; +%ignore mfem::Array2D::Save; %enddef diff --git a/test/test_blockmatrix.py b/test/test_blockmatrix.py index c78066ba..fe29711c 100644 --- a/test/test_blockmatrix.py +++ b/test/test_blockmatrix.py @@ -35,3 +35,7 @@ m.SetBlock(1, 0, mmat) print(m._offsets) print(m._linked_mat) + +from mfem.common.sparse_utils import sparsemat_to_scipycsr +print(m.CreateMonolithic()) +print(sparsemat_to_scipycsr(m.CreateMonolithic(), np.float64).todense()) From da23550ebf2652300644c2d8bfeb61448fd7f85c Mon Sep 17 00:00:00 2001 From: Syun'ichi Shiraiwa Date: Wed, 21 Aug 2024 17:53:30 -0400 Subject: [PATCH 2/2] working on memory handling. When Array is an array of MFEM object pointer, __setitem__should keep MFEM object from GCed.... --- mfem/common/array_setitem_typemap.i | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 mfem/common/array_setitem_typemap.i diff --git a/mfem/common/array_setitem_typemap.i b/mfem/common/array_setitem_typemap.i new file mode 100644 index 00000000..5ae2bb98 --- /dev/null +++ b/mfem/common/array_setitem_typemap.i @@ -0,0 +1,36 @@ +// +// this typemap is used together with %extend, which +// adds a class member taking int *pymfem_size +// +%define ARRAY_SETITEM(T) + %typemap(in) (int i, const T v) { + // generated by ARRAY_LISTTUPLE_INPUT(XXX, YYY) + if (!PyList_Check($input)) { + if (!PyTuple_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a list/tuple"); + return NULL; + } else { + is_tuple = true; + } + } + size = (is_tuple) ? PyTuple_Size($input) : PyList_Size($input); + $1 = (void *) & size; +} + +%typemap(argout) (void *List_or_Tuple, XXX *_unused ) { + for (int i = 0; i < size$argnum; i++) { + PyObject *s = (is_tuple$argnum) ? PyTuple_GetItem($input, i) : PyList_GetItem($input,i); + (* result)[i] = (XXX)YYY(s); + } +} + +%typemap(typecheck) (void *List_or_Tuple, XXX *_unused ) { + $1 = 0; + if (PyList_Check($input)){ + $1 = 1; + } + if (PyTuple_Check($input)){ + $1 = 1; + } +} +%enddef