-
Notifications
You must be signed in to change notification settings - Fork 4
Adding solvers for quick experiments #21
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
31f97da
c3e2415
917737f
0d11b27
9c70b69
ac86750
1cd2d3e
fb68b49
9d1619c
3149526
4a6b51a
9b5fe1a
303c309
77fca0d
d6646cb
93ee440
04d7194
04a746b
22c9882
4365cbe
c81ac98
5ad4d11
da87f41
35cfd78
19e5064
27fe979
383f237
dc388d5
ba6a218
8f95e69
5290da1
4039b1e
5441d06
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,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 | ||
| ``` | ||
|
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 think this template is not entirely sufficient explanation. In particular because of some mixing of stuff.
Member
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. Agree on solving the confusion, I'll improve the template. But
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. Well, how set are you on the "differential operator" name? I would personally change that and then the other names are fine.
Member
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. I didn't find anything better at the moment. a.k.a which I imagined can be named a (time) "differential operator". I also thought about
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 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 |
||
|
|
||
| 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. | ||
| 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. |
| 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** ⚠️) |
Uh oh!
There was an error while loading. Please reload this page.