|
| 1 | +# Add a differential operator |
| 2 | + |
| 3 | +📜 _Solvers implemented in {py:mod}`qmat.solvers.generic` can be used_ |
| 4 | +_with other {py:class}`DiffOp <qmat.solvers.generic.DiffOp>` classes_ |
| 5 | +_than those implemented in {py:mod}`qmat.solvers.generic.diffops`._ |
| 6 | + |
| 7 | +To add a new one, implement it at the end of the `diffops.py` module, |
| 8 | +using the following template : |
| 9 | + |
| 10 | +```python |
| 11 | +@registerDiffOp |
| 12 | +class Yoodlidoo(DiffOp): |
| 13 | + r""" |
| 14 | + Base description, in particular its equation : |
| 15 | +
|
| 16 | + .. math:: |
| 17 | +
|
| 18 | + \frac{du}{dt} = ... |
| 19 | +
|
| 20 | + And some parameters description ... |
| 21 | + """ |
| 22 | + def __init__(self, params="value"): |
| 23 | + # use some initialization parameters |
| 24 | + u0 = ... # define your initial vector |
| 25 | + super().__init__(u0) |
| 26 | + |
| 27 | + def evalF(self, u, t, out:np.ndarray): |
| 28 | + r""" |
| 29 | + Evaluate :math:`f(u,t)` and store the result into `out`. |
| 30 | +
|
| 31 | + Parameters |
| 32 | + ---------- |
| 33 | + u : np.ndarray |
| 34 | + Input solution for the evaluation. |
| 35 | + t : float |
| 36 | + Time for the evaluation. |
| 37 | + out : np.ndarray |
| 38 | + Output array in which is stored the evaluation. |
| 39 | + """ |
| 40 | + out[:] = ... # put the result into out |
| 41 | +``` |
| 42 | + |
| 43 | +And that's all ! The `registerDiffOp` operator will automatically |
| 44 | +- add your class in the `DIFFOPS` dictionary to make it generically available |
| 45 | +- check if your class properly overrides the `evalF` function (import error if not) |
| 46 | +- add your class to the [CI tests](./testing.md) |
| 47 | + |
| 48 | +> 📣 Per default, all `DiffOp` classes must be instantiable with default parameters |
| 49 | +> in order to run the tests (see the {py:func}`DiffOp.test <qmat.solvers.generic.DiffOp.test>` |
| 50 | +> class method). But you can change that by overriding the `test` class method and put your own |
| 51 | +> preset parameters for the test (checkout the |
| 52 | +> {py:func}`ProtheroRobinson <qmat.solvers.generic.diffops.ProtheroRobinson>` class for an example). |
| 53 | +
|
| 54 | +Finally, the `DiffOp` class implements a default `fSolve` method, that solves : |
| 55 | + |
| 56 | +$$ |
| 57 | +u - \alpha f(u, t) = rhs |
| 58 | +$$ |
| 59 | + |
| 60 | +for any given $\alpha, t, rhs$. |
| 61 | +It relies on generic non-linear root-finding solvers, namely `scipy.optimize.fsolve` for small problems |
| 62 | +and `scipy.optimize.newton_krylov` for large scale problems. |
| 63 | +You can also implement a more efficient approach tailored to your problem like this : |
| 64 | + |
| 65 | +```python |
| 66 | +@registerDiffOp |
| 67 | +class Yoodlidoo(DiffOp): |
| 68 | + # ... |
| 69 | + |
| 70 | + def fSolve(self, a:float, rhs:np.ndarray, t:float, out:np.ndarray): |
| 71 | + r""" |
| 72 | + Solve :math:`u-\alpha f(u,t)=rhs` for given :math:`u,t,rhs`, |
| 73 | + using `out` as initial guess and storing the final result into it. |
| 74 | +
|
| 75 | + Parameters |
| 76 | + ---------- |
| 77 | + a : float |
| 78 | + The :math:`\alpha` coefficient. |
| 79 | + rhs : np.ndarray |
| 80 | + The right hand side. |
| 81 | + t : float |
| 82 | + Time for the evaluation. |
| 83 | + out : np.ndarray |
| 84 | + Input-output array used as initial guess, |
| 85 | + in which is stored the solution. |
| 86 | + """ |
| 87 | + # TODO : your ultra-efficient implementation that will be |
| 88 | + # way better than a generic call of scipy.optimize.fsolve |
| 89 | + # or scipy.optimize.newton_krylov. |
| 90 | + out[:] = ... |
| 91 | +``` |
| 92 | + |
| 93 | +> 🔔 Note that `out` will be used as output for the solution, |
| 94 | +> but its input value can also be used as initial guess for any |
| 95 | +> iterative solver you may want to use. |
0 commit comments