Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
e5ed12d
Initial implementation by Angel Boada.
cpaolini May 26, 2026
b2fe6c5
feat: implement mimetic operator classes and grid generation utilitie…
cpaolini May 31, 2026
5deb8d8
feat: add Grid utility class for 1D-3D mesh generation and correspond…
cpaolini Jun 6, 2026
3989e7f
feat: implement Grid utility class for 1D-3D mesh generation and add …
cpaolini Jun 11, 2026
038dc52
feat: implement Grid and Divergence classes with associated unit tests
cpaolini Jun 14, 2026
a76c4aa
feat: implement Gradient operator for 1D, 2D, and 3D grids with assoc…
cpaolini Jun 15, 2026
a73f32d
feat: add CI workflow for automated builds, testing, and documentatio…
cpaolini Jun 15, 2026
5c38db2
feat: implement Grid class to manage 1D, 2D, and 3D coordinate meshes
cpaolini Jun 15, 2026
1576bf9
feat: implement unified Laplacian operator for 1D and 2D grids with a…
cpaolini Jun 18, 2026
87e2799
test: add unit tests for Laplacian matrix shape and constant field ev…
cpaolini Jun 19, 2026
47232a8
feat: implement Laplacian operator for 1D and 2D grids and add corres…
cpaolini Jun 19, 2026
c6df51b
feat: implement Divergence and Gradient operators for multidimensiona…
cpaolini Jun 19, 2026
adbacc0
feat: implement 2D Curl operator and add comprehensive Laplacian and …
cpaolini Jun 22, 2026
0c9174f
test: add unit tests for Laplacian operator including matrix shapes a…
cpaolini Jun 24, 2026
663b3d8
feat: implement base BoundaryCondition class and RobinBoundaryConditi…
cpaolini Jun 24, 2026
5924a31
feat: implement base grid, vector calculus operators, and boundary co…
cpaolini Jul 6, 2026
6a7e52a
Merge branch 'pymole-feature-add-1d-operators' of https://github.com/…
cpaolini Jul 6, 2026
88ab978
feat: add BoundaryCondition base class and implement 1D Robin boundar…
cpaolini Jul 8, 2026
b4ef90c
test: add unit tests for Curl operator functionality and dimension va…
cpaolini Jul 8, 2026
605e04d
test: add unit tests for gradient operator functionality and shape va…
cpaolini Jul 23, 2026
f5bfcc9
test: add unit tests for Gradient, Divergence, and Laplacian operators
cpaolini Aug 5, 2026
843c339
test: add unit tests for Laplacian operator matrix construction and p…
cpaolini Aug 5, 2026
fd4a227
Add new directory
cpaolini Aug 12, 2026
7440a91
Add new hierarchy
cpaolini Aug 12, 2026
b29252b
Move files into new hierarchy
cpaolini Aug 12, 2026
849e258
Update src/pymole/__init__.py
cpaolini Aug 12, 2026
b876a0c
Update pyproject.toml
cpaolini Aug 12, 2026
c18138e
Add editable install for Python package
cpaolini Aug 12, 2026
59b5448
Create README.md for pymole Python interface
cpaolini Aug 12, 2026
a41ceb7
Add GitHub Actions workflow for Python documentation
cpaolini Aug 12, 2026
d35a670
Add Sphinx and theme to requirements
cpaolini Aug 12, 2026
dee3518
Update directory path for dependency installation
cpaolini Aug 12, 2026
67a800c
Remove cd command in documentation build step
cpaolini Aug 12, 2026
277d274
Modify Python docs workflow to trigger on all branches
cpaolini Aug 12, 2026
fa40d5d
Modify Python workflow to install dependencies
cpaolini Aug 12, 2026
6dc9e36
Add pwd command to Python documentation workflow
cpaolini Aug 12, 2026
ac4ead0
Update workflow to install docs requirements in python dir
cpaolini Aug 12, 2026
87f1fd6
Add pwd commands to documentation build step
cpaolini Aug 12, 2026
08f8bb5
Add Sphinx configuration for documentation
cpaolini Aug 12, 2026
8ffa8e8
Add initial documentation structure for mole
cpaolini Aug 12, 2026
cd1fdac
Create .gitkeep
cpaolini Aug 12, 2026
8451f77
Update publish directory in Python docs workflow
cpaolini Aug 12, 2026
d654b88
Create .gitkeep
cpaolini Aug 12, 2026
5d70636
Update documentation title for pymole module
cpaolini Aug 12, 2026
365e875
Update deployment condition for documentation
cpaolini Aug 12, 2026
97d8234
Remove obsolete directory
cpaolini Sep 13, 2026
5d67e32
Update python/README.md
cpaolini Sep 20, 2026
da91615
Update python/pyproject.toml
cpaolini Sep 20, 2026
8dc7d0f
Delete python/LICENSE
cpaolini Sep 20, 2026
e01cee3
Undo changes to examples/matlab_octave/elliptic1D.m
cpaolini Sep 20, 2026
2f8c020
Delete examples/python/simple_operators_check.py
cpaolini Sep 20, 2026
c58a934
feat: add core pymole python package modules and mimetic operators
cpaolini Sep 20, 2026
8216723
feat: add pymole Python package with grid, boundary condition, and mi…
cpaolini Sep 20, 2026
ec50ffc
feat: add core mimetic operators, grid, and boundary condition module…
cpaolini Sep 20, 2026
59d9719
feat: add pymole Python package with mimetic operators and grid classes
cpaolini Sep 20, 2026
6178fb4
feat: add pymole Python package with mimetic operators and grid classes
cpaolini Sep 21, 2026
b051f2c
feat: add core pymole package modules including Grid, Curl, and Robin…
cpaolini Sep 23, 2026
12c5cd0
feat: add core pymole python package modules for grids, boundary cond…
cpaolini Sep 23, 2026
20e4070
feat: add RobinBoundaryCondition class for multi-dimensional grid sup…
cpaolini Sep 23, 2026
49b638e
chore: remove file
cpaolini Sep 23, 2026
3dcfc73
feat: add grid, mimetic operators, and boundary condition modules to …
cpaolini Sep 23, 2026
6a3a9f5
feat: add pymole python package with mimetic operators, boundary cond…
cpaolini Sep 23, 2026
115b398
feat: add pymole python package for mimetic operators, grids, and bou…
cpaolini Sep 24, 2026
131e329
feat: add Python modules for pymole mimetic operators, grids, and bou…
cpaolini Sep 24, 2026
d91a329
feat: add pymole python package with mimetic operators, boundary cond…
cpaolini Sep 24, 2026
3027ed9
feat: add pymole Python library with mimetic operators, documentation…
cpaolini Sep 24, 2026
7e7f2f3
feat: add pymole library operators, boundary conditions, and model pr…
cpaolini Sep 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/scripts/filter_compiled_sources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""
Filter a list of candidate C/C++ source files down to only those that
actually appear in compile_commands.json (i.e. files CMake really
compiles). This automatically excludes old_version/ and any other
directory not wired into the CMake build, with no hardcoded paths.

Usage:
python3 filter_compiled_sources.py <compile_commands.json> <raw_files.txt> <filtered_files.txt>
"""
import json
import os
import sys


def main():
if len(sys.argv) != 4:
print("Usage: filter_compiled_sources.py <compile_commands.json> <raw_files.txt> <filtered_files.txt>")
sys.exit(2)

compile_commands_path, raw_files_path, filtered_files_path = sys.argv[1:4]

with open(compile_commands_path) as f:
compiled = {os.path.realpath(entry["file"]) for entry in json.load(f)}

with open(raw_files_path) as f:
candidates = [line.strip() for line in f if line.strip()]

kept = [c for c in candidates if os.path.realpath(c) in compiled]
skipped = [c for c in candidates if os.path.realpath(c) not in compiled]

if skipped:
print(f"Skipping {len(skipped)} file(s) not in compile_commands.json:")
for s in skipped:
print(f" - {s}")

with open(filtered_files_path, "w") as f:
f.write("\n".join(kept))


if __name__ == "__main__":
main()
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,42 @@ jobs:
path: |
doc/sphinx/build/html/
doc/sphinx/build/latex/*.pdf

Python-unit-tests:
runs-on: ubuntu-latest

strategy:
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements*.txt', '**/pyproject.toml') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.python-version }}-

- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install pytest numpy scipy
python -m pip install -e ./python
pwd

- name: Run tests
run: |
pytest python/tests
56 changes: 56 additions & 0 deletions .github/workflows/python-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Python Documentation

on:
pull_request:
branches:
- '**'
push:
branches:
- '**'
tags: '*'

permissions:
contents: write
pull-requests: read
statuses: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
docbuild:
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v6

- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install pytest numpy scipy
python -m pip install -e ./python
pwd
cd python
pwd
if [ -f docs/requirements.txt ]; then pip install -r docs/requirements.txt; fi

- name: Build documentation
run: |
pwd
cd python
pwd
sphinx-build -W --keep-going -b html docs docs/_build/html

- name: Deploy documentation
if: github.event_name == 'push'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: python/docs/_build/html
65 changes: 65 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# pymole: Python interface for [MOLE](https://github.com/csrc-sdsu/mole)

## Description

This is an implementation written in Python for the MOLE package. The source files for the operators are located at ```src/``` and examples can be found in ```examples/```. This is a WIP implementation; currently (as of August 11, 2026), only the 1D and 2D operators are available.

## Installation

pymole is not yet available in the Python Package Index (PyPI). For now, this repository needs to be cloned locally in order to use the library in Python.

## Python 3

The pymole library requires Python 3. You can check your Python version by running the command `python --version` or `python3 --version` in your terminal. If you do not have Python 3 installed, you can install it by following the instructions at [python.org](https://www.python.org/downloads/).

If your operating system comes with Python 2 pre-installed, you may need to use `python3` instead of `python` in the commands below. In this case, you can also use the `python3` command to access your Python 3 installation.

## Using pymole

In order to use the pymole library, first navigate to the location where the repository has been cloned to. From here, you can access the library via the command line.

### Dependencies

MOLE requires the following packages to be installed:

- numpy: [installation instructions](https://numpy.org/install/)

python -m pip install --user numpy

- pytest: [installation instructions](https://docs.pytest.org/en/stable/getting-started/installation.html)

python -m pip install --user pytest

- scipy: [installation instructions](https://docs.scipy.org/doc/scipy/reference/building_scipy.html)

python -m pip install --user scipy

- matplotlib: [installation instructions](https://matplotlib.org/stable/users/installing.html)

python -m pip install --user matplotlib

### From the command line

In the repository root, `mole`, use the following command to install the Python MOLE module:

```sh
python -m pip install --user ./python
```

## Running the test suite

To run the unit tests, first install the MOLE module as described above, then run the command `python -m pytest python/tests` from the same root directory `mole`). The results of the unit tests should be displayed to your console.

## Examples

The MOLE library contains examples demonstrating how to use the operators, in a broad range of partial differential equations (PDEs). More information on the mathematical content can be found in the [main MOLE documentation](https://mole-docs.readthedocs.io/en/main/examples/index.html).

Currently, the following examples are available in the MOLE Python package.

- Elliptic Problems
- 1D Examples
- `elliptic1D`: A script that solves the 1D Poisson's equation with Robin boundary conditions using mimetic operators. Invoke as

```sh
python python/examples/elliptic1D.py
```
71 changes: 71 additions & 0 deletions python/build/lib/pymole/BoundaryCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from abc import ABC, abstractmethod

import numpy as np
from scipy import sparse

from .gradient import Gradient

class BoundaryCondition(ABC):
@abstractmethod
def apply(self):
"""Subclasses must implement this."""
raise NotImplementedError

def isImplemented(self) -> bool:
"""Returns True if the boundary condition is implemented."""
return self.apply != BoundaryCondition.apply

@classmethod
def hasImplemented(cls, bc) -> bool:
"""Returns True if the boundary condition is implemented."""
return bc.apply != BoundaryCondition.apply

def __init__(self, grid, accuracy_order: int = 2):
self.grid = grid
self.accuracy_order = accuracy_order

if self.grid.ndim not in (1, 2, 3):
raise ValueError(
f"BoundaryCondition currently supports 1D, 2D, and 3D grids. "
f"Got ndim={self.grid.ndim}"
)

self._configure_dimensions()
self._matrix = None

def _configure_dimensions(self) -> None:
if self.grid.ndim == 1:
self.m = self.grid.num_cells
self.n = None
self.o = None
elif self.grid.ndim == 2:
self.m, self.n = self.grid.num_cells
self.o = None
else:
self.m, self.n, self.o = self.grid.num_cells

@property
def matrix(self):
if self._matrix is None:
self._matrix = self.apply()
return self._matrix

def _spacing_for_dimension(self, axis: int) -> float:
spacing = self.grid.spacing
if self.grid.ndim == 1:
return spacing
if self.grid.ndim == 2:
return spacing[axis]
return spacing[axis]

def _build_1d_robin_matrix(self, size: int, dx: float, a: float, b: float):
A = sparse.lil_matrix((size + 2, size + 2), dtype=float)
A[0, 0] = a
A[-1, -1] = a

B = sparse.lil_matrix((size + 2, size + 1), dtype=float)
B[0, 0] = -b
B[-1, -1] = b

G = Gradient(self.grid, self.accuracy_order).matrix
return (A + B @ G).tocsr()
19 changes: 19 additions & 0 deletions python/build/lib/pymole/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from .grid import Grid
from .curl import Curl
from .divergence import Divergence
from .gradient import Gradient
from .laplacian import Laplacian
from .boundary_condition import BoundaryCondition
from .robin_boundary_condition import RobinBoundaryCondition

__version__ = "0.1.1"
__all__ = [
"BoundaryCondition",
"Curl",
"Divergence",
"Gradient",
"Grid",
"Laplacian",
"RobinBoundaryCondition",
]

33 changes: 33 additions & 0 deletions python/docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import os
import sys

# Add the project source directory to sys.path so autodoc can import it.
# Adjust this path if your package lives somewhere else.
sys.path.insert(0, os.path.abspath(".."))

# -- Project information -----------------------------------------------------

project = "mole"
copyright = "2026"
author = ""

# -- General configuration --------------------------------------------------

extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
"sphinx.ext.viewcode",
]

templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

# -- Options for HTML output ------------------------------------------------

html_theme = "alabaster"
#html_static_path = ["_static"]
8 changes: 8 additions & 0 deletions python/docs/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Documentation for pymole, the Python MOLE module
================================================

Welcome to the pymole documentation.

.. toctree::
:maxdepth: 2
:caption: Contents:
2 changes: 2 additions & 0 deletions python/docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sphinx
sphinx-rtd-theme
50 changes: 50 additions & 0 deletions python/examples/elliptic1D.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest rewriting this example in a more Pythonic way, rather than mirroring how the MATLAB examples in the library are written (it applies to other examples as well).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aboada Yes, this task will be done after this PR is approved and merged for the TOMS paper. This example will be extended to implement "The Model Problem" from the article Castillo and Yasuda, Linear Systems Arising for Second-Order Mimetic Divergence and Gradient Discretizations, Journal of Mathematical Modelling and Algorithms (2005) 4: 67–82, DOI: 10.1007/s10852-004-3523-1.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an open issue for it? If so, could you share it? Thanks!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea Angel, I created a separate issue (#474) and assigned it to @cpaolini for follow up

@aboada aboada Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to have the definition of the problem stated somewhere (this may apply to other examples in this PR)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aboada Yes, this model problem is defined in section 7.4 of our TOMS paper.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add then a comment with the reference for readability purposes?

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
SPDX-License-Identifier: GPL-3.0-or-later
© 2008-2024 San Diego State University Research Foundation (SDSURF).
See LICENSE file or https://www.gnu.org/licenses/gpl-3.0.html for details.
"""

import numpy as np
import sys
import shutil
import matplotlib.pyplot as plt

from pymole import Grid, Gradient, Divergence, Laplacian, RobinBoundaryCondition

@aboada aboada Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review unused imports in this file. This may be applicable to other files as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aboada Lines in elliptic1D.py to define PYTHONPATH explicitly have been removed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still see Gradient, Divergence defined but unused in this context.


west = 0 # Domain's limits
east = 1

k = 6 # Operator's order of accuracy
m = 2 * k + 1 # Minimum number of cells to attain the desired accuracy

grid = Grid.generate(west, east, shape=m + 1)

L = Laplacian(grid, accuracy_order=k).matrix

terminal_width, _ = shutil.get_terminal_size()
np.set_printoptions(linewidth=terminal_width, suppress=True)

BC = RobinBoundaryCondition(grid, k, dirichlet_coefficient=1.0, neumann_coefficient=1.0)
L_BC = L + BC.matrix

x = np.r_[
west,
np.arange(
west + grid.spacing / 2,
east - grid.spacing / 2 + grid.spacing / 2,
grid.spacing,
),
east,
]
U = np.exp(x)[:, None]
U[0] = 0 # West BC
U[-1] = 2 * np.exp(1) # East BC
U = np.linalg.inv(L_BC.toarray()) @ U

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use scipy.sparse.linalg.spsolve as opposed to inverting the matrix?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aboada Yes, this task will be done after this PR is approved and merged for the TOMS paper. This example will be extended to implement "The Model Problem" from the article Castillo and Yasuda, Linear Systems Arising for Second-Order Mimetic Divergence and Gradient Discretizations, Journal of Mathematical Modelling and Algorithms (2005) 4: 67–82, DOI: 10.1007/s10852-004-3523-1.

@aboada aboada Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this detail (scipy.sparse.linalg.spsolve) captured in an issue for future work?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this message in the open issue: #474 (comment)


plt.plot(x, U, "o", label="Approximated")
plt.plot(x, np.exp(x), label="Analytical")
plt.legend(loc="upper left")
plt.title("Poisson's equation with Robin BC")
plt.xlabel("x")
plt.ylabel("u(x)")
plt.show()
Loading
Loading