Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
31f97da
TL: added first Dahlquist and NonLinear solvers
tlunet Oct 17, 2025
c3e2415
TL: adapted fSolve to generic uShape
tlunet Oct 17, 2025
917737f
TL: minor details
tlunet Oct 17, 2025
0d11b27
TL: still trying stuff
tlunet Oct 19, 2025
9c70b69
TL: small testing on generic solver
tlunet Oct 20, 2025
ac86750
TL: almost there ...
tlunet Oct 20, 2025
1cd2d3e
TL: first working version
tlunet Oct 20, 2025
fb68b49
TL: finally done !
tlunet Oct 20, 2025
9d1619c
TL: added specialized nodeSolve for BE generic solver
tlunet Oct 21, 2025
3149526
TL: setup new structure
tlunet Oct 21, 2025
4a6b51a
TL: added ProtheroRobinson DiffOperator
tlunet Oct 21, 2025
9b5fe1a
TL: refactoring and some documentation
tlunet Oct 21, 2025
303c309
TL: implemented tests for dahlquist solvers
tlunet Oct 21, 2025
77fca0d
TL: added tests for diffops
tlunet Oct 21, 2025
d6646cb
TL: almost done with tests
tlunet Oct 22, 2025
93ee440
TL: finalized tests
tlunet Oct 22, 2025
04d7194
TL: python version rollout
tlunet Oct 22, 2025
04a746b
TL: started working on docs
tlunet Oct 22, 2025
22c9882
TL: documentation update
tlunet Oct 26, 2025
4365cbe
TL: finalized docstrings for new modules
tlunet Oct 27, 2025
c81ac98
TL: minor debuging
tlunet Oct 27, 2025
5ad4d11
TL: finalized devdocs
tlunet Oct 29, 2025
da87f41
TL: doc update
tlunet Oct 30, 2025
35cfd78
TL: finalized advanced tutorials
tlunet Oct 31, 2025
19e5064
TL: additional note on tutorial
tlunet Oct 31, 2025
27fe979
TL: regenerated notebooks
tlunet Oct 31, 2025
383f237
TL: beautifying
tlunet Nov 2, 2025
dc388d5
TL: regenerate notebooks
tlunet Nov 2, 2025
ba6a218
TL: trying a small update
tlunet Nov 2, 2025
8f95e69
TL: minor change
tlunet Nov 2, 2025
5290da1
TL: solved most of thomas's comments
tlunet Nov 3, 2025
4039b1e
TL: improved devdoc on DiffOp
tlunet Nov 3, 2025
5441d06
TL: added imex stability scripts for thomas
tlunet Nov 4, 2025
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
8 changes: 4 additions & 4 deletions .github/workflows/ci_pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python: ['3.9', '3.10', '3.11', '3.12', '3.13']
python: ['3.10', '3.11', '3.12', '3.13', '3.14']
defaults:
run:
shell: bash -l {0}
Expand All @@ -35,7 +35,7 @@ jobs:
./test.sh
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
if: github.repository_owner == 'Parallel-in-Time' && matrix.python == '3.11'
if: github.repository_owner == 'Parallel-in-Time' && matrix.python == '3.13'
with:
flags: smart-tests
verbose: true
Expand All @@ -47,10 +47,10 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.11
- name: Set up Python 3.13
uses: actions/setup-python@v3
with:
python-version: "3.11"
python-version: "3.13"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ $$

and many different **lower-triangular** approximations of the $Q$ matrix, named $Q_\Delta$,
which are key elements for Spectral Deferred Correction (SDC), or more general Iterated Runge-Kutta Methods.
It also contains **generic time-integration solvers** based on $Q$ and $Q_\Delta$ coefficients,
that can be used for quick testing and experiments.

[![DOI](https://zenodo.org/badge/804826743.svg)](https://zenodo.org/doi/10.5281/zenodo.11956478)

Expand Down Expand Up @@ -78,3 +80,8 @@ and the current [Development Roadmap](https://qmat.readthedocs.io/en/latest/devd
- Issues Tracker : https://github.com/Parallel-in-Time/qmat/issues
- Q&A : https://github.com/Parallel-in-Time/qmat/discussions/categories/q-a
- Project Proposals : https://github.com/Parallel-in-Time/qmat/discussions/categories/project-proposals

## Developers

- [Thibaut Lunet](https://github.com/tlunet)
- [Thomas Saupe (né Baumann)](https://github.com/brownbaerchen)
4 changes: 2 additions & 2 deletions docs/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ While we recommend the use of the latest version, below is the list of the curre

## Reporting a Vulnerability

If you see any vulnerability with this package, please open an
If you see any vulnerability with this package, please open an
[issue on the Github interface ...](https://github.com/Parallel-in-Time/qmat/issues),
so that is can be solved as quickly as possible by the developing community.
so that is can be solved as quickly as possible by our developing community.
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# -- Project information -----------------------------------------------------

project = 'QMat Package'
copyright = '2024 PinT Community'
copyright = '2025 PinT Community'
author = 'PinT Community'

# The short X.Y version
Expand Down Expand Up @@ -72,7 +72,7 @@
autoapi_dirs = ['../qmat']
autoapi_file_patterns = ['*.py']
autoapi_options = [
'members', 'undoc-members',
'members', 'undoc-members',
'show-inheritance-diagram',
'show-module-summary',
]
Expand Down Expand Up @@ -162,5 +162,5 @@
# -- Options for nbsphinx galleries
# Using _images/ is a hack to get relocated images which have been included in the pages
nbsphinx_thumbnails = {

}
12 changes: 9 additions & 3 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,19 @@ Current coverage is at 100%, so no untested line will be accepted 😇.

Chosen merge strategy is to squash commits $\Rightarrow$ you don't have to care about the number of commit included in your PR, so don't be scare of making mistakes before your PR is accepted 😉

> 🔔 Once your PR is accepted, please delete this branch from your fork and synchronize your `main` branch. When creating a new development branch later, ensure that you start from an up-to-date `main` branch of your fork.
> 🔔 Once your PR is accepted, please delete this branch from your fork and synchronize your `main` branch. When creating a new development branch later, ensure that you start from an up-to-date `main` branch of your fork.

In case you are interested in contributing but don't have any idea on what, checkout out current [development roadmap 🎯](./devdoc/roadmap.md) and [project proposals 🎓](https://github.com/Parallel-in-Time/qmat/discussions/categories/project-proposals)

## Base recipes

_A few base memo on how to develop this package ..._
_Some memos on how to develop this package ..._

- [General code structure](./devdoc/structure.md)
- [Code structure](./devdoc/structure.md)
- [Add a Runge-Kutta scheme](./devdoc/addRK.md)
- [Add a playground](./devdoc/addPlayground.md)
- [Add a differential operator](./devdoc/addDiffOp.md)
- [Add a $\phi$-based time-integrator](./devdoc/addPhiIntegrator.md)
- [Testing your changes](./devdoc/testing.md)
- [Update this documentation](./devdoc/updateDoc.md)
- [Version update pipeline](./devdoc/versionUpdate.md)
Expand All @@ -47,6 +50,9 @@ _A few base memo on how to develop this package ..._

devdoc/structure
devdoc/addRK
devdoc/addPlayground
devdoc/addDiffOp
devdoc/addPhiIntegrator
devdoc/testing
devdoc/updateDoc
devdoc/versionUpdate
Expand Down
95 changes: 95 additions & 0 deletions docs/devdoc/addDiffOp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Add a differential operator

📜 _Solvers implemented in {py:mod}`qmat.solvers.generic` can be used_
_with other {py:class}`DiffOp <qmat.solvers.generic.DiffOp>` classes_
_than those implemented in {py:mod}`qmat.solvers.generic.diffops`._

To add a new one, implement it at the end of the `diffops.py` module,
using the following template :

```python
@registerDiffOp
class Yoodlidoo(DiffOp):
r"""
Base description, in particular its equation :

.. math::

\frac{du}{dt} = ...

And some parameters description ...
"""
def __init__(self, params="value"):
# use some initialization parameters
u0 = ... # define your initial vector
super().__init__(u0)

def evalF(self, u, t, out:np.ndarray):
r"""
Evaluate :math:`f(u,t)` and store the result into `out`.

Parameters
----------
u : np.ndarray
Input solution for the evaluation.
t : float
Time for the evaluation.
out : np.ndarray
Output array in which is stored the evaluation.
"""
out[:] = ... # put the result into out
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this template is not entirely sufficient explanation. In particular because of some mixing of stuff.
If I understand correctly, the "differential operator" implements the $f$ in an equation $u_t=f$. But then this class defines initial conditions for the associated initial value problem and has a function evalF when to me it should be called only eval because the differential operator is already $f$.
I have not yet read the code this documents, but that is also the intended order for new contributers and I am pretty sure I would not be the only one to be confused.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree on solving the confusion, I'll improve the template. But eval is already a built-in python function, and the name should echo with the fSolve method. We could change to fEval maybe ... but it feels a bit weird

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, how set are you on the "differential operator" name? I would personally change that and then the other names are fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't find anything better at the moment. Problem is too generic and looks too close to pySDC. And at the end, we do need a class representing

$$ f(u,t) $$

a.k.a

$$ \frac{du}{dt} $$

which I imagined can be named a (time) "differential operator". I also thought about ODERightHandSide, but it didn't felt as simple and concise as DiffOp

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think problem is too generic. Yes pySDC has problems (pun intended) but so does the rest of the world. I think differential operator is also very generic, but I personally don't expect it to have properties like $f$.
I don't know what the perfect name here is, but maybe this is another sign that this belongs in a separate repository, not in the one that computes quadrature coefficients.


And that's all ! The `registerDiffOp` operator will automatically
- add your class in the `DIFFOPS` dictionary to make it generically available
- check if your class properly overrides the `evalF` function (import error if not)
- add your class to the [CI tests](./testing.md)

> 📣 Per default, all `DiffOp` classes must be instantiable with default parameters
> in order to run the tests (see the {py:func}`DiffOp.test <qmat.solvers.generic.DiffOp.test>`
> class method). But you can change that by overriding the `test` class method and put your own
> preset parameters for the test (checkout the
> {py:func}`ProtheroRobinson <qmat.solvers.generic.diffops.ProtheroRobinson>` class for an example).

Finally, the `DiffOp` class implements a default `fSolve` method, that solves :

$$
u - \alpha f(u, t) = rhs
$$

for any given $\alpha, t, rhs$.
It relies on generic non-linear root-finding solvers, namely `scipy.optimize.fsolve` for small problems
and `scipy.optimize.newton_krylov` for large scale problems.
You can also implement a more efficient approach tailored to your problem like this :

```python
@registerDiffOp
class Yoodlidoo(DiffOp):
# ...

def fSolve(self, a:float, rhs:np.ndarray, t:float, out:np.ndarray):
r"""
Solve :math:`u-\alpha f(u,t)=rhs` for given :math:`u,t,rhs`,
using `out` as initial guess and storing the final result into it.

Parameters
----------
a : float
The :math:`\alpha` coefficient.
rhs : np.ndarray
The right hand side.
t : float
Time for the evaluation.
out : np.ndarray
Input-output array used as initial guess,
in which is stored the solution.
"""
# TODO : your ultra-efficient implementation that will be
# way better than a generic call of scipy.optimize.fsolve
# or scipy.optimize.newton_krylov.
out[:] = ...
```

> 🔔 Note that `out` will be used as output for the solution,
> but its input value can also be used as initial guess for any
> iterative solver you may want to use.
44 changes: 44 additions & 0 deletions docs/devdoc/addPhiIntegrator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Add a $\phi$-based time-integrator

📜 _Additional time schemes can be added using the [$\phi$ formulation](../notebooks/14_phiIntegrator.ipynb)_
_to test other variants of $Q_\Delta$-coefficients free Spectral Deferred Correction._
_For that, you can implement a new {py:mod}`PhiSolver <qmat.solvers.generic.PhiSolver>` class in the {py:mod}`qmat.solvers.generic.integrators` module_.

Add your class at the end of the `qmat.solvers.generic.integrators.py` module using the following template :

```python
class Phidlidoo(PhiSolver):
r"""
Base description, in particular its definition :

.. math::

\phi(u_0, u_1, ..., u_{m}, u_{m+1}) =
...

And eventual parameters description ...
"""

def evalPhi(self, uVals, fEvals, out, t0=0):
m = len(uVals) - 1
assert m > 0
assert len(fEvals) in [m, m+1]

# TODO : integrators implementation
```

The first assertions are not mandatory, but ensure that the `evalPhi` is properly evaluated.

> 📣 New `PhiSolver` classes are not automatically tested, so you'll have to write
> some dedicated test for your new class in `tests.test_solvers.test_integrators.py`.
> Checkout those already implemented for `ForwardEuler` and `BackwardEuler`.

As for the {py:class}`DiffOp <qmat.solvers.generic.DiffOp>` class,
the {py:class}`PhiSolver <qmat.solvers.generic.PhiSolver>` implements a generic default
`phiSolve` method, that you can override by a more efficient specialized approach.

> 💡 Note that the model above inherits the `__init__` constructor of the `PhiSolver` class,
> so it can take any `DiffOp` class as parameter.
> If your time-integrator is specialized for some kind of differential operators
> (_e.g_ a semi-Lagrangian scheme for an advective problem),
> then you probably need to override the `__init__` method in your class too.
42 changes: 42 additions & 0 deletions docs/devdoc/addPlayground.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Add a playground

📜 _To add experimental scripts or usage examples, without testing everything : simply add your own **playground** in {py:mod}`qmat.playgrounds`._

1. create a folder with a _short & representative_ name, _e.g_ `yoodlidoo` (can also be your name for a personal playground),
2. put your script(s) in it, and document them as much as necessary so **anyone else can understand and use your code**,
3. create a `__init__.py` file in your playground folder with a short summary of your scripts in its docstring, _e.g_
```python
"""
- :class:`script1` : trying some stuff.
- :class:`script2` : yet another idea.
"""
```
4. add the item line corresponding to your playground in `qmat.playgrounds.__init__.py`, _e.g_
```python
"""
...

Current playgrounds
-------------------

- ...
- :class:`yoodlidoo` : some ideas to do stuff
"""
```
5. open a pull request against the `main` branch of `qmat`.

> 💡 If you don't want your playground to be integrated into the main branch of`qmat` (no proper documentation, code always evolving, ...),
> you can still add a **soft link to a playground in your fork** by modifying `qmat.playgrounds.__init__.py` :
> ```python
> """
> ...
>
> Current playgrounds
> -------------------
>
> - ...
> - `{name} <https://github.com/{userName}/qmat/tree/{branch}/qmat/playgrounds/{name}>`_ : some ideas ...
> """
> ```
> where `name` is your playground name, `userName` your GitHub username and `branch` the branch name on your fork you are working on
> (**do not use the `main` branch of your fork** ⚠️)
Loading