PyMFEM Python Bindings for MFEM

repository·master·Indexed 43 days ago

https://github.com/mfem/pymfem

Python bindings for MFEM, a high-performance parallel finite element method (FEM) library. PyMFEM enables complex finite element simulations in Python with C++ performance, featuring support for Numba JIT-compiled coefficients, MPI parallelization, and integration with Jupyter notebooks via pyglvis for inline visualization.

Tokens
9.6K
Snippets
33
Records
44
Agent score
55%

What's inside PyMFEM

  1. Implement custom coefficients using Python classes

    master

    To use a Python function as a coefficient in MFEM, you must inherit from the appropriate PyMFEM coefficient classes and implement the EvalValue(self, x) method.

    Available Classes:

    • mfem.PyCoefficient: For scalar coefficients.
    • mfem.PyCoefficientT: Time-dependent scalar coefficients.
    • mfem.VectorPyCoefficient: For vector coefficients.
    • mfem.VectorPyCoefficientT: Time-dependent vector coefficients.

    Implementation Pattern:

    class MyCoefficient(mfem.PyCoefficient):
        def EvalValue(self, x):
            return 0.01  # Must return a float
    
    class MyVectorCoefficient(mfem.VectorPyCoefficient):
        def EvalValue(self, x):
            return [0., 0., np.cos(x[2])] # Must return a list/array

    Constant Coefficients: MatrixConstantCoefficient and VectorConstantCoefficient support natural Python objects (lists/nested lists) as input. The input is converted via np.array(x, dtype=float) internally.

    class Jt(mfem.VectorPyCoefficient):
        def EvalValue(self, x):
            return [0.,0., np.cos(np.abs(x[2]-0.03)/0.03*np.pi/2)]
    
    class Sigma(mfem.PyCoefficient):
        def EvalValue(self, x):
            return 0.01
    
    Cof_Jt = Jt(3)
    dd = mfem.VectorFEBoundaryTangentLFIntegrator(Cof_Jt)
  2. Define variable diffusion coefficients using Numba JIT

    master

    To represent a variable diffusion coefficient $\alpha(x)$ instead of a constant, you must use a function decorated with @mfem.jit.scalar to ensure it is Numba-JIT compiled for performance within the MFEM operators.

    @mfem.jit.scalar
    def alpha(x):
        return x+1.0
  3. Build PyMFEM with CUDA support

    master

    To build with CUDA support, you must have CUDA installed and nvcc available in your PATH. You can specify CUDA compute capability using --cuda-arch.

    Options:

    • --with-cuda: Build MFEM with CUDA.
    • --with-cuda-hypre: Build Hypre with CUDA support.
    • --cuda-arch=<arch>: Specify the CUDA compute capability (e.g., 80 for A100, 75 for Turing).

    Example using pip syntax:

    pip install . -C"with-cuda=Yes" -C"with-cuda-hypre=Yes" -C"cuda-arch=80"
  4. Clean PyMFEM build artifacts

    master

    If you need to reset your environment or clear build files, use the following commands to remove build directories, external dependencies, and wrapper code.

    $ rm -rf build    # clean build directory
    $ rm -rf external # clean external dependencies + wrapper code
    $ git clean -f    # clean files under mfem/_ser and mfem/_par
  5. Build PyMFEM from source with MPI (Parallel version)

    master

    To build a parallel version of MFEM (linked with MPI and other features), you must clone the repository and use the pip install command with specific configuration flags passed via -C.

    $ git clone https://github.com/mfem/PyMFEM.git
    $ cd PyMFEM
    
    # Build it from local source with MPI
    $ pip install ./ -C"with-parallel=Yes" --verbose
  6. Install PyMFEM via pip (Serial version)

    master

    To install the serial version of MFEM and PyMFEM, use pip. Note that binary installs are currently only available on Linux platforms for Python versions 3.8 through 3.12.

    pip install mfem
  7. Step-by-step build for PyMFEM development

    master

    When developing (e.g., editing *.i files), you can avoid full rebuilds by using specific flags to build components incrementally.

    Workflow:

    1. Clean the environment:

      python setup.py clean --all
    2. Build external libraries only:

      pip install . -C"ext-only=Yes" --verbose
    3. Generate SWIG wrappers (skipping externals):

      pip install . -C"skip-ext=Yes" -C"swig=Yes" --verbose
    4. Final build (after editing wrappers): Once you are satisfied with the *.cxx and *.py files, build the final package skipping both externals and SWIG:

      pip install . -C"skip-ext=Yes" -C"skip-swig=Yes" --verbose

    Development Flags:

    • --swig: Run SWIG only.
    • --skip-swig: Build without running SWIG.
    • --skip-ext: Skip building external libraries.
    • --ext-only: Build external libraries and exit.
    pip install . -C"skip-ext=Yes" -C"skip-swig=Yes" --verbose
  8. JIT compile Python coefficients with Numba

    master

    Function coefficients written in Python can be Just-In-Time (JIT) compiled using Numba for performance. You can use mfem.jit decorators or the NumbaFunction class.

    Using @mfem.jit decorators

    Decorators can be applied to functions to create scalar, vector, or matrix coefficients.

    • @mfem.jit.scalar(td=False, ...)
    • @mfem.jit.vector(vdim=None, shape=None, ...)
    • @mfem.jit.matrix(height=None, width=None, ...)

    Decorator Arguments:

    • td: Time-dependence (False for stationary, True for time-dependent).
    • complex: If True, returns a complex coefficient (internally creates real and imaginary parts).
    • interface: 'simple' (returns by value, Pythonic) or 'c++' (returns by parameter, like C++).
    • shape: The shape of the return value (e.g., shape=(3,)).
    • vdim: Length of vector coefficient.
    • dependency: A tuple of other coefficients that this function depends on.

    Example: JIT Vector Coefficient

    @mfem.jit.vector(shape=(3,))
    def f_exact(x):
        return np.array([(1 + kappa**2)*sin(kappa * x[1]),
                         (1 + kappa**2)*sin(kappa * x[2]),
                         (1 + kappa**2)*sin(kappa * x[0])])
    
    x.ProjectCoefficient(f_exact)

    Example: Complex Coefficient

    @mfem.jit.scalar(complex=True)
    def c12(ptx):
        return ptx[0] + 1j*ptx[1]
    
    x.ProjectCoefficient(c12.real)
    x.ProjectCoefficient(c12.imag)
    >>> @mfem.jit.scalar()
    >>> def c12(ptx):
    >>>     return s_func0(ptx[0], ptx[1], ptx[2])
    
    >>> @mfem.jit.vector(shape=(3,))
    >>> def f_exact(x):
    >>>     return np.array((1 + kappa**2)*sin(kappa * x[1]),
    >>>                     (1 + kappa**2)*sin(kappa * x[2]),
    >>>                     (1 + kappa**2)*sin(kappa * x[0]))
    
    >>> x.ProjectCoefficient(f_exact)
  9. Build PyMFEM with advanced dependencies (SuiteSparse, GSlib, libCEED)

    master

    You can enable support for various mathematical libraries during the build process:

    • SuiteSparse: Use --with-suitesparse. Requires SuiteSparse to be installed separately. Point to its location using --suitesparse-prefix=<location>. (Note: This also enables building metis in serial).
    • GSlib: Use --with-gslib. This option automatically downloads and builds GSlib.
    • libCEED: Use --with-libceed. This option automatically downloads and builds libCEED.
    • LAPACK: Use --with-lapack. Specify library locations using --blas-libraries=<location> and --lapack-libraries=<location>.
  10. Use Jupyter notebooks for PyMFEM examples

    master

    PyMFEM provides Jupyter notebook versions of its examples. These notebooks allow for interactive exploration and include inline visualization of finite element results using pyglvis.

    To view these examples, you can access them directly in Google Colab or run them locally in a Jupyter environment. Note that inline visualization requires pyglvis to be installed.

    https://colab.research.google.com/github/mfem/pymfem/blob/main/examples/jupyter/ex1.ipynb