src/python_access/numpy_array.rs

changeset 1
a4137aedcb3a
child 3
c3a4f4bb87f7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/python_access/numpy_array.rs	Thu Feb 26 09:32:12 2026 -0500
@@ -0,0 +1,151 @@
+/*!
+Python and C++ wrapper for Dolfinx Function<f64>
+*/
+
+use alg_tools::euclidean::wrap::{WrapGuard, WrapGuardMut, Wrapped};
+use alg_tools::types::Float;
+use nalgebra::{DMatrix, DMatrixView, DMatrixViewMut, Dyn};
+use ndarray::{Dimension, Ix1, Ix2};
+use numpy::{PyArray, PyArrayMethods, PyReadonlyArray, PyReadwriteArray, ToPyArray};
+use pyo3::prelude::*;
+
+/// A helper structure of dealing with dolfinx functions.
+/// `N` is the domain dimension, `O` the order, and `D` is the codomain dimension.
+#[allow(non_camel_case_types)]
+#[derive(Debug, Clone)]
+pub enum NumpyArray_f64<'py, D> {
+    PyWrapped {
+        /// Python object.
+        x: Bound<'py, PyArray<f64, D>>,
+    },
+    Nalgebra {
+        x: DMatrix<f64>,
+    },
+}
+
+#[allow(non_camel_case_types)]
+#[allow(unused)]
+pub type NumpyVector_f64<'py> = NumpyArray_f64<'py, Ix1>;
+
+#[allow(non_camel_case_types)]
+#[allow(unused)]
+pub type NumpyMatrix_f64<'py> = NumpyArray_f64<'py, Ix2>;
+
+impl<'a, 'py, D: Dimension> FromPyObject<'a, 'py> for NumpyArray_f64<'py, D> {
+    type Error = PyErr;
+
+    fn extract(x: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
+        Ok(NumpyArray_f64::PyWrapped { x: x.to_owned().cast_into()? })
+    }
+}
+
+impl<'py> IntoPyObject<'py> for NumpyArray_f64<'py, Ix1> {
+    type Target = PyArray<f64, Ix1>;
+    type Error = PyErr;
+    type Output = pyo3::Bound<'py, Self::Target>;
+
+    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
+        match self {
+            NumpyArray_f64::PyWrapped { x } => x.into_pyobject(py).map_err(From::from),
+            NumpyArray_f64::Nalgebra { x } => x.to_pyarray(py).reshape((x.len(),)),
+        }
+    }
+}
+
+impl<'py> IntoPyObject<'py> for NumpyArray_f64<'py, Ix2> {
+    type Target = PyArray<f64, Ix2>;
+    type Error = PyErr;
+    type Output = pyo3::Bound<'py, Self::Target>;
+
+    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
+        match self {
+            NumpyArray_f64::PyWrapped { x } => x.into_pyobject(py).map_err(From::from),
+            NumpyArray_f64::Nalgebra { x } => Ok(x.to_pyarray(py)),
+        }
+    }
+}
+
+#[allow(non_camel_case_types)]
+#[derive(Debug)]
+pub enum ArrayGuard<'a, 'py, D: Dimension, F: numpy::Element + Float = f64> {
+    PyWrapped {
+        /// Python object.
+        x: PyReadonlyArray<'py, F, D>,
+    },
+    Nalgebra {
+        x: &'a DMatrix<F>,
+    },
+}
+
+#[allow(non_camel_case_types)]
+#[derive(Debug)]
+pub enum ArrayGuardMut<'a, 'py, D: Dimension, F: numpy::Element + Float = f64> {
+    PyWrapped {
+        /// Python object.
+        x: PyReadwriteArray<'py, F, D>,
+    },
+    Nalgebra {
+        x: &'a mut DMatrix<F>,
+    },
+}
+
+macro_rules! impl_euclidean {
+    ($dim:ty) => {
+        impl<'a, 'py> WrapGuard<'a, f64> for ArrayGuard<'a, 'py, $dim, f64> where 'py : 'a {
+            type View<'b> = DMatrixView<'b, f64, Dyn, Dyn> where Self : 'b;
+
+            #[inline]
+            fn get_view(&self) -> Self::View<'_> {
+                match self {
+                    ArrayGuard::PyWrapped{ref x} => x.as_matrix(),
+                    ArrayGuard::Nalgebra{x} => x.as_view(),
+                }
+            }
+        }
+
+        impl<'a, 'py> WrapGuardMut<'a, f64> for ArrayGuardMut<'a, 'py, $dim, f64> where 'py : 'a {
+            type ViewMut<'b> = DMatrixViewMut<'b, f64, Dyn, Dyn> where Self : 'b;
+
+            #[inline]
+            fn get_view_mut(&mut self) -> Self::ViewMut<'_> {
+                match self {
+                    ArrayGuardMut::PyWrapped{ref x} => x.as_matrix_mut(),
+                    ArrayGuardMut::Nalgebra{x} => x.as_view_mut(),
+                }
+            }
+        }
+
+        impl<'py> Wrapped for NumpyArray_f64<'py, $dim> where Self : 'py {
+            type WrappedField = f64;
+            type Guard<'a> =  ArrayGuard<'a, 'py, $dim, f64> where Self : 'a;
+            type GuardMut<'a> =  ArrayGuardMut<'a, 'py, $dim, f64> where Self : 'a;
+            type UnwrappedOutput = DMatrix<f64>;
+            type WrappedOutput = Self;
+
+            #[inline]
+            fn get_guard(&self) -> Self::Guard<'_> {
+                match self {
+                    NumpyArray_f64::PyWrapped{ ref x } => ArrayGuard::PyWrapped{ x : x.readonly() },
+                    NumpyArray_f64::Nalgebra{ ref x } => ArrayGuard::Nalgebra{ x },
+                }
+            }
+
+            #[inline]
+            fn get_guard_mut(&mut self) -> Self::GuardMut<'_> {
+                match self {
+                    NumpyArray_f64::PyWrapped{ ref mut x } => ArrayGuardMut::PyWrapped{ x : x.readwrite() },
+                    NumpyArray_f64::Nalgebra{ ref mut x } => ArrayGuardMut::Nalgebra{ x },
+                }
+            }
+
+
+            fn wrap(x: Self::UnwrappedOutput) -> Self {
+                NumpyArray_f64::Nalgebra{ x }
+            }
+        }
+        alg_tools::wrap!(f64; NumpyArray_f64<'py, $dim> where 'py);
+    };
+}
+
+impl_euclidean!(Ix1);
+impl_euclidean!(Ix2);

mercurial