Repository navigation
Pymole feature add 1d operators #463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e5ed12d
b2fe6c5
5deb8d8
3989e7f
038dc52
a76c4aa
a73f32d
5c38db2
1576bf9
87e2799
47232a8
c6df51b
adbacc0
0c9174f
663b3d8
5924a31
6a7e52a
88ab978
b4ef90c
605e04d
f5bfcc9
843c339
fd4a227
7440a91
b29252b
849e258
b876a0c
c18138e
59b5448
a41ceb7
d35a670
dee3518
67a800c
277d274
fa40d5d
6dc9e36
ac4ead0
87f1fd6
08f8bb5
8ffa8e8
cd1fdac
8451f77
d654b88
5d70636
365e875
97d8234
5d67e32
da91615
8dc7d0f
e01cee3
2f8c020
c58a934
8216723
ec50ffc
59d9719
6178fb4
b051f2c
12c5cd0
20e4070
49b638e
3dcfc73
6a3a9f5
115b398
131e329
d91a329
3027ed9
7e7f2f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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() |
| 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 |
| 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 | ||
| ``` |
| 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() |
| 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", | ||
| ] | ||
|
|
| 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"] |
| 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: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| sphinx | ||
| sphinx-rtd-theme |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aboada Lines in elliptic1D.py to define PYTHONPATH explicitly have been removed.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this detail (
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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