docs(pythonInterface): added docs to serif.mfem and serif.polytrope
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
/**
|
||||
* @file PyCoefficient.h
|
||||
* @brief Defines pybind11 trampoline classes for mfem::Coefficient and mfem::VectorCoefficient.
|
||||
*
|
||||
* These trampoline classes allow Python classes to inherit from mfem::Coefficient
|
||||
* and mfem::VectorCoefficient, enabling Python-defined coefficients to be used
|
||||
* within the C++ MFEM library.
|
||||
*/
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/functional.h> // Needed for std::function
|
||||
@@ -8,20 +16,147 @@
|
||||
namespace py = pybind11;
|
||||
using namespace mfem;
|
||||
|
||||
/**
|
||||
* @namespace serif::pybind
|
||||
* @brief Contains pybind11 helper classes and trampoline classes for interfacing C++ with Python.
|
||||
*/
|
||||
namespace serif::pybind {
|
||||
// --- Trampoline for the abstract Coefficient base class ---
|
||||
/**
|
||||
* @brief Trampoline class for mfem::Coefficient.
|
||||
*
|
||||
* This class allows Python classes to inherit from mfem::Coefficient and override
|
||||
* its virtual methods. This is essential for creating custom coefficients in Python
|
||||
* that can be used by MFEM's C++ backend.
|
||||
*
|
||||
* @see mfem::Coefficient
|
||||
*
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import mfem.ser_ext as mfem
|
||||
*
|
||||
* class MyPythonCoefficient(mfem.Coefficient):
|
||||
* def __init__(self):
|
||||
* super().__init__() # Call the base C++ constructor
|
||||
*
|
||||
* def Eval(self, T, ip):
|
||||
* # T is an mfem.ElementTransformation
|
||||
* # ip is an mfem.IntegrationPoint
|
||||
* # Example: return a constant value
|
||||
* return 1.0
|
||||
*
|
||||
* def SetTime(self, t):
|
||||
* # Optionally handle time-dependent coefficients
|
||||
* super().SetTime(t) # Call base class method
|
||||
* print(f"Time set to: {t}")
|
||||
*
|
||||
* # Using the Python coefficient
|
||||
* py_coeff = MyPythonCoefficient()
|
||||
* # py_coeff can now be passed to MFEM functions expecting an mfem::Coefficient
|
||||
* @endcode
|
||||
*/
|
||||
class PyCoefficient : public Coefficient {
|
||||
public:
|
||||
using Coefficient::Coefficient;
|
||||
using Coefficient::Coefficient; /**< Inherit constructors from mfem::Coefficient. */
|
||||
|
||||
/**
|
||||
* @brief Evaluate the coefficient at a given IntegrationPoint in an ElementTransformation.
|
||||
*
|
||||
* This method is called by MFEM when the value of the coefficient is needed.
|
||||
* If a Python class inherits from PyCoefficient, it *must* override this method.
|
||||
*
|
||||
* @param T The element transformation.
|
||||
* @param ip The integration point.
|
||||
* @return The value of the coefficient at the given point.
|
||||
*
|
||||
* @note This method forwards the call to the Python override.
|
||||
* PYBIND11_OVERRIDE_PURE is used in the .cpp file to handle this.
|
||||
*/
|
||||
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
|
||||
|
||||
/**
|
||||
* @brief Set the current time for time-dependent coefficients.
|
||||
*
|
||||
* This method is called by MFEM to update the time for time-dependent coefficients.
|
||||
* Python classes inheriting from PyCoefficient can override this method to implement
|
||||
* time-dependent behavior.
|
||||
*
|
||||
* @param t The current time.
|
||||
*
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
* PYBIND11_OVERRIDE is used in the .cpp file to handle this.
|
||||
*/
|
||||
void SetTime(real_t t) override;
|
||||
};
|
||||
|
||||
// --- Trampoline for the abstract VectorCoefficient base class ---
|
||||
/**
|
||||
* @brief Trampoline class for mfem::VectorCoefficient.
|
||||
*
|
||||
* This class allows Python classes to inherit from mfem::VectorCoefficient and override
|
||||
* its virtual methods. This is essential for creating custom vector-valued coefficients
|
||||
* in Python that can be used by MFEM's C++ backend.
|
||||
*
|
||||
* @see mfem::VectorCoefficient
|
||||
*
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import mfem.ser_ext as mfem
|
||||
* import numpy as np
|
||||
*
|
||||
* class MyPythonVectorCoefficient(mfem.VectorCoefficient):
|
||||
* def __init__(self, dim):
|
||||
* super().__init__(dim) # Call the base C++ constructor, pass vector dimension
|
||||
* self.dim = dim
|
||||
*
|
||||
* def Eval(self, V, T, ip):
|
||||
* # V is an mfem.Vector (output parameter, must be filled)
|
||||
* # T is an mfem.ElementTransformation
|
||||
* # ip is an mfem.IntegrationPoint
|
||||
* # Example: return a constant vector [1.0, 2.0, ...]
|
||||
* for i in range(self.dim):
|
||||
* V[i] = float(i + 1)
|
||||
*
|
||||
* def SetTime(self, t):
|
||||
* super().SetTime(t)
|
||||
* print(f"VectorCoefficient time set to: {t}")
|
||||
*
|
||||
* # Using the Python vector coefficient
|
||||
* vec_dim = 2
|
||||
* py_vec_coeff = MyPythonVectorCoefficient(vec_dim)
|
||||
* # py_vec_coeff can now be passed to MFEM functions expecting an mfem::VectorCoefficient
|
||||
* @endcode
|
||||
*/
|
||||
class PyVectorCoefficient : public VectorCoefficient {
|
||||
public:
|
||||
using VectorCoefficient::VectorCoefficient;
|
||||
using VectorCoefficient::VectorCoefficient; /**< Inherit constructors from mfem::VectorCoefficient. */
|
||||
|
||||
/**
|
||||
* @brief Evaluate the vector coefficient at a given IntegrationPoint in an ElementTransformation.
|
||||
*
|
||||
* This method is called by MFEM when the value of the vector coefficient is needed.
|
||||
* If a Python class inherits from PyVectorCoefficient, it *must* override this method.
|
||||
* The result should be stored in the output Vector @p V.
|
||||
*
|
||||
* @param V Output vector to store the result. Its size should match the coefficient's dimension.
|
||||
* @param T The element transformation.
|
||||
* @param ip The integration point.
|
||||
*
|
||||
* @note This method forwards the call to the Python override.
|
||||
* PYBIND11_OVERRIDE_PURE is used in the .cpp file to handle this.
|
||||
*/
|
||||
void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) override;
|
||||
|
||||
/**
|
||||
* @brief Set the current time for time-dependent vector coefficients.
|
||||
*
|
||||
* This method is called by MFEM to update the time for time-dependent vector coefficients.
|
||||
* Python classes inheriting from PyVectorCoefficient can override this method to implement
|
||||
* time-dependent behavior.
|
||||
*
|
||||
* @param t The current time.
|
||||
*
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
* PYBIND11_OVERRIDE is used in the .cpp file to handle this.
|
||||
*/
|
||||
void SetTime(real_t t) override;
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
/**
|
||||
* @file PyMatrix.h
|
||||
* @brief Defines a pybind11 trampoline class for mfem::Matrix.
|
||||
*
|
||||
* This trampoline class allows Python classes to inherit from mfem::Matrix,
|
||||
* enabling Python-defined matrices to be used within the C++ MFEM library,
|
||||
* including overriding methods from its base class mfem::Operator.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mfem.hpp"
|
||||
@@ -9,7 +17,103 @@ namespace serif::pybind {
|
||||
* @brief A trampoline class for mfem::Matrix.
|
||||
*
|
||||
* This class allows Python classes to inherit from mfem::Matrix and correctly
|
||||
* override its virtual functions, including those inherited from mfem::Operator.
|
||||
* override its virtual functions, including those inherited from its base,
|
||||
* mfem::Operator. This is useful for creating custom matrix types in Python
|
||||
* that can interact seamlessly with MFEM's C++ components.
|
||||
*
|
||||
* @see mfem::Matrix
|
||||
* @see mfem::Operator
|
||||
* @see PyOperator
|
||||
*
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import mfem.ser_ext as mfem
|
||||
* import numpy as np
|
||||
*
|
||||
* class MyPythonMatrix(mfem.Matrix):
|
||||
* def __init__(self, size=0):
|
||||
* super().__init__(size) # Call base C++ constructor
|
||||
* if size > 0:
|
||||
* # Example: Initialize with some data if size is provided
|
||||
* # Note: Direct data manipulation might be complex due to
|
||||
* # C++ ownership. This example is conceptual.
|
||||
* # For a real-world scenario, you might manage data in Python
|
||||
* # and use Eval or Mult to reflect its state.
|
||||
* self._py_data = np.zeros((size, size))
|
||||
* else:
|
||||
* self._py_data = None
|
||||
*
|
||||
* # --- mfem.Matrix pure virtual overrides ---
|
||||
* def Elem(self, i, j):
|
||||
* # This is problematic for direct override for write access
|
||||
* # due to returning a reference.
|
||||
* # Typically, you'd manage data and use it in Mult/GetRow etc.
|
||||
* # For read access (const version), it's more straightforward.
|
||||
* if self._py_data is not None:
|
||||
* return self._py_data[i, j]
|
||||
* raise IndexError("Matrix data not initialized or index out of bounds")
|
||||
*
|
||||
* # const Elem version for read access
|
||||
* # def GetElem(self, i, j): # A helper in Python if Elem is tricky
|
||||
* # return self._py_data[i,j]
|
||||
*
|
||||
* def Inverse(self):
|
||||
* # Return an mfem.MatrixInverse object
|
||||
* # This is a simplified example; a real inverse is complex.
|
||||
* print("MyPythonMatrix.Inverse() called, returning dummy inverse.")
|
||||
* # For a real implementation, you'd compute and return an actual
|
||||
* # mfem.MatrixInverse or a Python-derived version of it.
|
||||
* # This might involve creating a new PyMatrix representing the inverse.
|
||||
* identity_inv = mfem.DenseMatrix(self.Width())
|
||||
* for i in range(self.Width()):
|
||||
* identity_inv[i,i] = 1.0
|
||||
* return mfem.MatrixInverse(identity_inv) # Example
|
||||
*
|
||||
* # --- mfem.Matrix regular virtual overrides ---
|
||||
* def Finalize(self, skip_zeros=1):
|
||||
* super().Finalize(skip_zeros) # Call base
|
||||
* print(f"MyPythonMatrix.Finalize({skip_zeros}) called.")
|
||||
*
|
||||
* # --- mfem.Operator virtual overrides ---
|
||||
* def Mult(self, x, y):
|
||||
* # x is mfem.Vector (input), y is mfem.Vector (output)
|
||||
* if self._py_data is not None:
|
||||
* x_np = x.GetDataArray()
|
||||
* y_np = np.dot(self._py_data, x_np)
|
||||
* y.SetSize(self._py_data.shape[0])
|
||||
* y.Assign(y_np)
|
||||
* else:
|
||||
* # Fallback to base class if no Python data
|
||||
* # super().Mult(x,y) # This might not work as expected if base is abstract
|
||||
* # or if the C++ mfem.Matrix itself doesn't have data.
|
||||
* # For a sparse matrix, this would call its sparse Mult.
|
||||
* # For a dense matrix, it would use its data.
|
||||
* # If this PyMatrix is purely Python defined, it must implement Mult.
|
||||
* raise NotImplementedError("Mult not implemented or data not set")
|
||||
* print("MyPythonMatrix.Mult called.")
|
||||
*
|
||||
* # Using the Python Matrix
|
||||
* mat_size = 3
|
||||
* py_mat = MyPythonMatrix(mat_size)
|
||||
* py_mat._py_data = np.array([[1,2,3],[4,5,6],[7,8,9]], dtype=float)
|
||||
*
|
||||
* x_vec = mfem.Vector(mat_size)
|
||||
* x_vec.Assign(np.array([1,1,1], dtype=float))
|
||||
* y_vec = mfem.Vector(mat_size)
|
||||
*
|
||||
* py_mat.Mult(x_vec, y_vec)
|
||||
* print("Result y:", y_vec.GetDataArray())
|
||||
*
|
||||
* # inv_op = py_mat.Inverse() # Be cautious with dummy implementations
|
||||
* # print("Inverse type:", type(inv_op))
|
||||
*
|
||||
* # Note: Overriding Elem(i,j) to return a C++ reference from Python
|
||||
* # for write access (mfem::real_t&) is complex and often not directly feasible
|
||||
* # in a straightforward way with pybind11 for typical Python data structures.
|
||||
* # Python users would typically interact via methods like Set, Add, or by
|
||||
* # providing data that the C++ side can access (e.g., via GetData).
|
||||
* # The const version of Elem (read-only) is more manageable.
|
||||
* @endcode
|
||||
*/
|
||||
class PyMatrix : public mfem::Matrix {
|
||||
public:
|
||||
@@ -17,24 +121,132 @@ namespace serif::pybind {
|
||||
using mfem::Matrix::Matrix;
|
||||
|
||||
// --- Trampolines for new mfem::Matrix pure virtual methods ---
|
||||
/**
|
||||
* @brief Access element (i,j) for read/write.
|
||||
* Pure virtual in mfem::Matrix. Must be overridden in Python.
|
||||
* @param i Row index.
|
||||
* @param j Column index.
|
||||
* @return Reference to the matrix element.
|
||||
* @note Returning a C++ reference from Python for write access can be complex.
|
||||
* Consider alternative data management strategies in Python.
|
||||
* PYBIND11_OVERRIDE_PURE is used in the .cpp file.
|
||||
*/
|
||||
mfem::real_t& Elem(int i, int j) override;
|
||||
|
||||
/**
|
||||
* @brief Access element (i,j) for read-only.
|
||||
* Pure virtual in mfem::Matrix. Must be overridden in Python.
|
||||
* @param i Row index.
|
||||
* @param j Column index.
|
||||
* @return Const reference to the matrix element.
|
||||
* @note PYBIND11_OVERRIDE_PURE is used in the .cpp file.
|
||||
*/
|
||||
const mfem::real_t& Elem(int i, int j) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the inverse of the matrix.
|
||||
* Pure virtual in mfem::Matrix. Must be overridden in Python.
|
||||
* The caller is responsible for deleting the returned MatrixInverse object.
|
||||
* @return Pointer to an mfem::MatrixInverse object.
|
||||
* @note PYBIND11_OVERRIDE_PURE is used in the .cpp file.
|
||||
*/
|
||||
mfem::MatrixInverse* Inverse() const override;
|
||||
|
||||
// --- Trampoline for new mfem::Matrix regular virtual methods ---
|
||||
void Finalize(int) override;
|
||||
/**
|
||||
* @brief Finalize matrix assembly.
|
||||
* For sparse matrices, this typically involves finalizing the sparse structure.
|
||||
* Can be overridden in Python.
|
||||
* @param skip_zeros See mfem::SparseMatrix::Finalize documentation.
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
void Finalize(int skip_zeros) override;
|
||||
|
||||
// --- Trampolines for inherited mfem::Operator virtual methods ---
|
||||
// These must be repeated here to allow Python classes inheriting from
|
||||
// Matrix to override methods originally from the Operator base class.
|
||||
|
||||
/**
|
||||
* @brief Perform the operator action: y = A*x.
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* If not overridden, mfem::Matrix's default implementation is used.
|
||||
* @param x The input vector.
|
||||
* @param y The output vector (result of A*x).
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
|
||||
/**
|
||||
* @brief Perform the transpose operator action: y = A^T*x.
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* @param x The input vector.
|
||||
* @param y The output vector (result of A^T*x).
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
void MultTranspose(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
|
||||
/**
|
||||
* @brief Perform the action y += a*(A*x).
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* @param x The input vector.
|
||||
* @param y The vector to which a*(A*x) is added.
|
||||
* @param a Scalar multiplier (defaults to 1.0).
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
void AddMult(const mfem::Vector &x, mfem::Vector &y, const mfem::real_t a = 1.0) const override;
|
||||
|
||||
/**
|
||||
* @brief Perform the action y += a*(A^T*x).
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* @param x The input vector.
|
||||
* @param y The vector to which a*(A^T*x) is added.
|
||||
* @param a Scalar multiplier (defaults to 1.0).
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
void AddMultTranspose(const mfem::Vector &x, mfem::Vector &y, const mfem::real_t a = 1.0) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the gradient operator (Jacobian) at a given point x.
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* For a linear matrix operator, the gradient is typically the matrix itself.
|
||||
* @param x The point at which to evaluate the gradient (often unused for linear operators).
|
||||
* @return A reference to the gradient operator.
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
mfem::Operator& GetGradient(const mfem::Vector &x) const override;
|
||||
|
||||
/**
|
||||
* @brief Assemble the diagonal of the operator.
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* @param diag Output vector to store the diagonal entries.
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
void AssembleDiagonal(mfem::Vector &diag) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the prolongation operator.
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* @return A const pointer to the prolongation operator, or nullptr if not applicable.
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
const mfem::Operator* GetProlongation() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the restriction operator.
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* @return A const pointer to the restriction operator, or nullptr if not applicable.
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
const mfem::Operator* GetRestriction() const override;
|
||||
|
||||
/**
|
||||
* @brief Recover the FEM solution.
|
||||
* Inherited from mfem::Operator. Can be overridden in Python.
|
||||
* @param X The reduced solution vector.
|
||||
* @param b The right-hand side vector.
|
||||
* @param x Output vector for the full FEM solution.
|
||||
* @note PYBIND11_OVERRIDE is used in the .cpp file.
|
||||
*/
|
||||
void RecoverFEMSolution(const mfem::Vector &X, const mfem::Vector &b, mfem::Vector &x) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/**
|
||||
* @file PyOperator.h
|
||||
* @brief Defines a pybind11 trampoline class for mfem::Operator.
|
||||
*
|
||||
* This trampoline class allows Python classes to inherit from mfem::Operator,
|
||||
* enabling Python-defined operators to be used within the C++ MFEM library.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mfem.hpp"
|
||||
@@ -6,13 +13,72 @@
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
/**
|
||||
* @namespace serif::pybind
|
||||
* @brief Contains pybind11 helper classes and trampoline classes for interfacing C++ with Python.
|
||||
*/
|
||||
namespace serif::pybind {
|
||||
|
||||
/**
|
||||
* @brief A trampoline class for mfem::Operator.
|
||||
* * This class allows Python classes to inherit from mfem::Operator and correctly
|
||||
* @brief Trampoline class for mfem::Operator.
|
||||
*
|
||||
* This class allows Python classes to inherit from mfem::Operator and correctly
|
||||
* override its virtual functions. When a virtual function is called from C++,
|
||||
* the trampoline ensures the call is forwarded to the Python implementation if one exists.
|
||||
* This is crucial for integrating Python-defined linear or non-linear operators
|
||||
* into MFEM's C++-based solvers and algorithms.
|
||||
*
|
||||
* @see mfem::Operator
|
||||
*
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import mfem.ser_ext as mfem
|
||||
* import numpy as np
|
||||
*
|
||||
* class MyPythonOperator(mfem.Operator):
|
||||
* def __init__(self, size):
|
||||
* super().__init__(size) # Call the base C++ constructor
|
||||
* # Or super().__init__() if default constructing and setting height/width later
|
||||
* self.matrix = np.random.rand(size, size) # Example: store a dense matrix
|
||||
*
|
||||
* # Must override Mult
|
||||
* def Mult(self, x, y):
|
||||
* # x is an mfem.Vector (input)
|
||||
* # y is an mfem.Vector (output, y = A*x)
|
||||
* # Ensure y is correctly sized if not already
|
||||
* if y.Size() != self.Height():
|
||||
* y.SetSize(self.Height())
|
||||
*
|
||||
* # Example: y = self.matrix * x
|
||||
* # This is a conceptual illustration. For actual matrix-vector products
|
||||
* # with numpy, you'd convert mfem.Vector to numpy array or iterate.
|
||||
* x_np = x.GetDataArray() # Get a numpy view if configured
|
||||
* y_np = np.dot(self.matrix, x_np)
|
||||
* y.Assign(y_np) # Assign result back to mfem.Vector
|
||||
* print("MyPythonOperator.Mult called")
|
||||
*
|
||||
* # Optionally override other methods like MultTranspose, GetGradient, etc.
|
||||
* def MultTranspose(self, x, y):
|
||||
* if y.Size() != self.Width():
|
||||
* y.SetSize(self.Width())
|
||||
* # Example: y = self.matrix.T * x
|
||||
* x_np = x.GetDataArray()
|
||||
* y_np = np.dot(self.matrix.T, x_np)
|
||||
* y.Assign(y_np)
|
||||
* print("MyPythonOperator.MultTranspose called")
|
||||
*
|
||||
* # Using the Python operator
|
||||
* op_size = 5
|
||||
* py_op = MyPythonOperator(op_size)
|
||||
*
|
||||
* x_vec = mfem.Vector(op_size)
|
||||
* x_vec.Assign(np.arange(op_size, dtype=float))
|
||||
* y_vec = mfem.Vector(op_size)
|
||||
*
|
||||
* py_op.Mult(x_vec, y_vec)
|
||||
* print("Result y:", y_vec.GetDataArray())
|
||||
* # py_op can now be passed to MFEM functions expecting an mfem::Operator
|
||||
* @endcode
|
||||
*/
|
||||
class PyOperator : public mfem::Operator {
|
||||
public:
|
||||
@@ -22,25 +88,123 @@ namespace serif::pybind {
|
||||
|
||||
// --- Trampoline declarations for all overridable virtual functions ---
|
||||
|
||||
// Pure virtual function (MANDATORY override)
|
||||
/**
|
||||
* @brief Perform the operator action: y = A*x.
|
||||
*
|
||||
* This is a pure virtual function in mfem::Operator and **must** be overridden
|
||||
* by any Python class inheriting from PyOperator.
|
||||
*
|
||||
* @param x The input vector.
|
||||
* @param y The output vector (result of A*x).
|
||||
* @note This method forwards the call to the Python override.
|
||||
* PYBIND11_OVERRIDE_PURE is used in the .cpp file to handle this.
|
||||
*/
|
||||
void Mult(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
|
||||
// Regular virtual functions (RECOMMENDED overrides)
|
||||
/**
|
||||
* @brief Perform the transpose operator action: y = A^T*x.
|
||||
*
|
||||
* Optional override. If not overridden, MFEM's base implementation
|
||||
* (which may raise an error or be a no-op) will be used.
|
||||
*
|
||||
* @param x The input vector.
|
||||
* @param y The output vector (result of A^T*x).
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
* PYBIND11_OVERRIDE is used in the .cpp file to handle this.
|
||||
*/
|
||||
void MultTranspose(const mfem::Vector &x, mfem::Vector &y) const override;
|
||||
|
||||
/**
|
||||
* @brief Perform the action y += a*(A*x).
|
||||
*
|
||||
* Optional override.
|
||||
*
|
||||
* @param x The input vector.
|
||||
* @param y The vector to which a*(A*x) is added.
|
||||
* @param a Scalar multiplier (defaults to 1.0).
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
*/
|
||||
void AddMult(const mfem::Vector &x, mfem::Vector &y, const mfem::real_t a = 1.0) const override;
|
||||
|
||||
/**
|
||||
* @brief Perform the action y += a*(A^T*x).
|
||||
*
|
||||
* Optional override.
|
||||
*
|
||||
* @param x The input vector.
|
||||
* @param y The vector to which a*(A^T*x) is added.
|
||||
* @param a Scalar multiplier (defaults to 1.0).
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
*/
|
||||
void AddMultTranspose(const mfem::Vector &x, mfem::Vector &y, const mfem::real_t a = 1.0) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the gradient operator (Jacobian) at a given point x.
|
||||
*
|
||||
* For non-linear operators, this method should return the linearization (Jacobian)
|
||||
* of the operator at the point `x`. The returned Operator is owned by this
|
||||
* Operator and should not be deleted by the caller.
|
||||
* Optional override.
|
||||
*
|
||||
* @param x The point at which to evaluate the gradient.
|
||||
* @return A reference to the gradient operator.
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
*/
|
||||
Operator& GetGradient(const mfem::Vector &x) const override;
|
||||
|
||||
/**
|
||||
* @brief Assemble the diagonal of the operator.
|
||||
*
|
||||
* For discrete operators (e.g., matrices), this method should compute and store
|
||||
* the diagonal entries of the operator in the vector `diag`.
|
||||
* Optional override.
|
||||
*
|
||||
* @param diag Output vector to store the diagonal entries.
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
*/
|
||||
void AssembleDiagonal(mfem::Vector &diag) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the prolongation operator.
|
||||
*
|
||||
* Used in multilevel methods (e.g., AMG). Returns a pointer to the prolongation
|
||||
* operator (interpolation from a coarser level to this level).
|
||||
* The returned Operator is typically owned by this Operator.
|
||||
* Optional override.
|
||||
*
|
||||
* @return A const pointer to the prolongation operator, or nullptr if not applicable.
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
*/
|
||||
const mfem::Operator* GetProlongation() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the restriction operator.
|
||||
*
|
||||
* Used in multilevel methods (e.g., AMG). Returns a pointer to the restriction
|
||||
* operator (projection from this level to a coarser level).
|
||||
* Typically, this is the transpose of the prolongation operator.
|
||||
* The returned Operator is typically owned by this Operator.
|
||||
* Optional override.
|
||||
*
|
||||
* @return A const pointer to the restriction operator, or nullptr if not applicable.
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
*/
|
||||
const mfem::Operator* GetRestriction() const override;
|
||||
|
||||
/**
|
||||
* @brief Recover the FEM solution.
|
||||
*
|
||||
* For operators that are part of a system solve (e.g., static condensation),
|
||||
* this method can be used to reconstruct the full finite element solution `x`
|
||||
* from a reduced solution `X` and the right-hand side `b`.
|
||||
* Optional override.
|
||||
*
|
||||
* @param X The reduced solution vector.
|
||||
* @param b The right-hand side vector.
|
||||
* @param x Output vector for the full FEM solution.
|
||||
* @note This method forwards the call to the Python override if one exists.
|
||||
*/
|
||||
void RecoverFEMSolution(const mfem::Vector &X, const mfem::Vector &b, mfem::Vector &x) override;
|
||||
};
|
||||
|
||||
} // namespace serif::pybind::mfem
|
||||
} // namespace serif::pybind
|
||||
@@ -1,33 +1,307 @@
|
||||
/**
|
||||
* @file bindings.h
|
||||
* @brief Declares functions to register MFEM core library components with pybind11.
|
||||
*
|
||||
* This header file lists the functions responsible for creating Python bindings
|
||||
* for various parts of the MFEM library. Each function typically registers
|
||||
* a set of related classes, enums, or functionalities to a pybind11::module,
|
||||
* which is expected to be a submodule named `mfem` within the main `serif` Python module.
|
||||
*
|
||||
* @see /Users/tboudreaux/Programming/SERiF/src/python/bindings.cpp for how these are used.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
/**
|
||||
* @brief Registers all core MFEM bindings to the given Python submodule.
|
||||
*
|
||||
* This function serves as the main entry point for exposing MFEM functionalities
|
||||
* to Python. It calls various other `register_*_bindings` and `bind_*_enum`
|
||||
* functions to populate the `mfem_submodule`.
|
||||
*
|
||||
* @param mfem_submodule The pybind11 module (typically `serif.mfem`) to which
|
||||
* MFEM bindings will be added.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # Now mfem.Operator, mfem.Vector, mfem.Mesh, etc., are accessible.
|
||||
* vec = mfem.Vector(10)
|
||||
* print(vec.Size())
|
||||
* @endcode
|
||||
*/
|
||||
void register_mfem_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::Operator and related classes.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # Assuming PyOperator trampoline is bound
|
||||
* # op = mfem.Operator() # Or a derived class like mfem.DenseMatrix
|
||||
* @endcode
|
||||
*/
|
||||
void register_operator_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::Matrix and its derived classes (e.g., mfem::DenseMatrix, mfem::SparseMatrix).
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* mat = mfem.DenseMatrix(2, 2)
|
||||
* mat[0,0] = 1.0
|
||||
* mat[0,1] = 2.0
|
||||
* mat[1,0] = 3.0
|
||||
* mat[1,1] = 4.0
|
||||
* mat.Print()
|
||||
* @endcode
|
||||
*/
|
||||
void register_matrix_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::Vector.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* vec = mfem.Vector(5)
|
||||
* vec[0] = 1.5
|
||||
* print(vec.Size(), vec[0])
|
||||
* @endcode
|
||||
*/
|
||||
void register_vector_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::Array.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* arr_int = mfem.intArray(5) # Assuming intArray is a typedef or specific binding
|
||||
* arr_int[0] = 10
|
||||
* print(arr_int.Size(), arr_int[0])
|
||||
* @endcode
|
||||
*/
|
||||
void register_array_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Binds the mfem::AssemblyLevel enum.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # level = mfem.AssemblyLevel.LEGACY # Or other enum values
|
||||
* # print(level)
|
||||
* @endcode
|
||||
*/
|
||||
void bind_assembly_level_enum(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::BilinearForm and related functionalities.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # Assuming FiniteElementSpace (fes) is created
|
||||
* # bform = mfem.BilinearForm(fes)
|
||||
* # bform.AddDomainIntegrator(mfem.MassIntegrator()) # Assuming MassIntegrator is bound
|
||||
* # bform.Assemble()
|
||||
* # A = bform.SpMat()
|
||||
* @endcode
|
||||
*/
|
||||
void register_bilinear_form_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::MixedBilinearForm and related functionalities.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # Assuming trial_fes and test_fes are FiniteElementSpaces
|
||||
* # mbform = mfem.MixedBilinearForm(trial_fes, test_fes)
|
||||
* # mbform.AddDomainIntegrator(mfem.VectorFEMassIntegrator()) # Example
|
||||
* # mbform.Assemble()
|
||||
* @endcode
|
||||
*/
|
||||
void register_mixed_bilinear_form_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::Table.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* table = mfem.Table()
|
||||
* # ... use table methods ...
|
||||
* @endcode
|
||||
*/
|
||||
void register_table_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::Mesh.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* mesh = mfem.Mesh.MakeCartesian1D(10) # Example constructor
|
||||
* print(mesh.Dimension(), mesh.GetNE())
|
||||
* @endcode
|
||||
*/
|
||||
void register_mesh_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::BasisType enum and related constants.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* basis_type = mfem.BasisType.GaussLobatto
|
||||
* print(basis_type)
|
||||
* @endcode
|
||||
*/
|
||||
void register_basis_type_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::FiniteElementCollection base class.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # fec = mfem.FiniteElementCollection() # Typically use derived classes
|
||||
* @endcode
|
||||
*/
|
||||
void register_finite_element_collection_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::H1_FECollection.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* order = 1
|
||||
* dim = 2
|
||||
* fec = mfem.H1_FECollection(order, dim)
|
||||
* print(fec.GetName())
|
||||
* @endcode
|
||||
*/
|
||||
void register_H1_FECollection_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::RT_FECollection.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* order = 1
|
||||
* dim = 2
|
||||
* fec = mfem.RT_FECollection(order-1, dim) # RT_FECollection uses p-1 for order p
|
||||
* print(fec.GetName())
|
||||
* @endcode
|
||||
*/
|
||||
void register_RT_FECollection_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::ND_FECollection (Nedelec finite elements).
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* order = 1
|
||||
* dim = 3
|
||||
* fec = mfem.ND_FECollection(order, dim)
|
||||
* print(fec.GetName())
|
||||
* @endcode
|
||||
*/
|
||||
void register_ND_FECollection_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Binds the mfem::Ordering::Type enum.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* ordering = mfem.Ordering.byNODES
|
||||
* print(ordering)
|
||||
* @endcode
|
||||
*/
|
||||
void bind_ordering_enum(pybind11::module &mfem_submodule);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::FiniteElementSpace.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* mesh = mfem.Mesh.MakeCartesian1D(5)
|
||||
* fec = mfem.H1_FECollection(1, mesh.Dimension())
|
||||
* fes = mfem.FiniteElementSpace(mesh, fec)
|
||||
* print(fes.GetNDofs())
|
||||
* @endcode
|
||||
*/
|
||||
void register_finite_element_space_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::Coefficient, mfem::VectorCoefficient and related classes/trampolines.
|
||||
* @param m The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* const_coeff = mfem.ConstantCoefficient(2.5)
|
||||
* # vec_coeff = mfem.VectorConstantCoefficient(mfem.Vector([1.0, 2.0]))
|
||||
*
|
||||
* # Using a Python-derived coefficient (if PyCoefficient trampoline is bound)
|
||||
* class MyCoeff(mfem.Coefficient):
|
||||
* def Eval(self, T, ip):
|
||||
* return 1.0
|
||||
* my_c = MyCoeff()
|
||||
* @endcode
|
||||
*/
|
||||
void register_coefficient_bindings(pybind11::module &m);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::ElementTransformation.
|
||||
* @param m The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # ElementTransformation objects are usually obtained from Mesh or FiniteElementSpace
|
||||
* # mesh = mfem.Mesh.MakeCartesian1D(1)
|
||||
* # el_trans = mesh.GetElementTransformation(0)
|
||||
* # print(el_trans.ElementNo)
|
||||
* @endcode
|
||||
*/
|
||||
void register_eltrans_bindings(pybind11::module &m);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::IntegrationRule and mfem::IntegrationPoint.
|
||||
* @param m The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* # Get a standard integration rule
|
||||
* ir = mfem.IntRules.Get(mfem.Geometry.SEGMENT, 3) # Order 3 for a segment
|
||||
* for i in range(ir.GetNPoints()):
|
||||
* ip = ir.IntPoint(i)
|
||||
* # print(f"Point {i}: coords {ip.x}, weight {ip.weight}")
|
||||
* @endcode
|
||||
*/
|
||||
void register_intrule_bindings(pybind11::module &m);
|
||||
|
||||
/**
|
||||
* @brief Registers mfem::GridFunction.
|
||||
* @param mfem_submodule The `serif.mfem` Python submodule.
|
||||
* @par Python Usage Example:
|
||||
* @code{.py}
|
||||
* import serif.mfem as mfem
|
||||
* mesh = mfem.Mesh.MakeCartesian1D(5)
|
||||
* fec = mfem.H1_FECollection(1, mesh.Dimension())
|
||||
* fes = mfem.FiniteElementSpace(mesh, fec)
|
||||
* gf = mfem.GridFunction(fes)
|
||||
* gf.Assign(0.0) # Set all values to 0
|
||||
* print(gf.Size())
|
||||
* @endcode
|
||||
*/
|
||||
void register_grid_function_bindings(pybind11::module &mfem_submodule);
|
||||
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
/**
|
||||
* @file bindings.h
|
||||
* @brief Declares the function to register polytrope module C++ components with pybind11.
|
||||
*
|
||||
* This file contains the declaration for `register_polytrope_bindings`, which is responsible
|
||||
* for creating Python bindings for classes and functions within the `serif::polytrope` C++
|
||||
* namespace. These bindings will be accessible in Python under the `serif.polytrope` submodule.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
/**
|
||||
* @brief Registers C++ classes and functions from the `serif::polytrope` namespace to Python.
|
||||
*
|
||||
* This function takes a pybind11::module object, representing the `serif.polytrope` Python submodule,
|
||||
* and adds bindings for various components like `PolytropeOperator`, `PolySolver`, etc.
|
||||
* This allows these C++ components to be instantiated and used directly from Python.
|
||||
*
|
||||
* @param polytrope_submodule The pybind11 module (typically `serif.polytrope`) to which
|
||||
* the polytrope C++ bindings will be added.
|
||||
*
|
||||
* @par Python Usage Example:
|
||||
* After these bindings are registered and the Python module is imported:
|
||||
* @code{.py}
|
||||
* from serif.polytrope import PolySolver
|
||||
* polytrope = PolySolver(1.5, 1)
|
||||
* polytrope.solve()
|
||||
* @endcode
|
||||
*/
|
||||
void register_polytrope_bindings(pybind11::module &polytrope_submodule);
|
||||
|
||||
Reference in New Issue
Block a user