# Fortranlang: a Python package?

**URL:** <https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870>\
**Category:** Uncategorized\
**Created:** [February 28, 2022, 1:03am UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870 "2022-02-28T01:03:38Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![nicholaswogan](https://avatars.discourse-cdn.com/v4/letter/n/f1d935/32.png) [@nicholaswogan](https://fortran-lang.discourse.group/u/nicholaswogan)\
**Post date:** [February 28, 2022, 1:03am UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/1 "2022-02-28T01:03:38Z")

</div>

I have an idea to create a `fortranlang` python package (name TBD). The idea would to be to make high performance Python wrappers to some Fortran libraries, including Minpack, ODEPACK, and QUADPACK.

You might be thinking… "`scipy` already wraps these libraries???". Yes, Scipy does, but an issue with Scipy is that their wrappers are pretty slow, and can not be called within `numba` compiled functions (numba is a python compiler). It is possible to make much faster python wrappers using `ctypes` (although these wrappers are less flexible). These wrappers can be called from within numba compiled functions. Therefore, you can get massive speedups over scipy.

For example, I’ve put together the [numbalsoda](https://github.com/Nicholaswogan/numblsoda) python package, which wraps the LSODA routine in ODEPACK. Right now the package uses a C++ version of LSODA because ODEPACK isn’t modernized quite yet (see progress by @jacobwilliams [here](https://github.com/jacobwilliams/odepack)). But I’d like to switch to a Fortran once a modernized ODEPACK is available. `numbalsoda` is up to ~100x faster than scipy’s wrappers of LSODA ([benchmark here](https://github.com/Nicholaswogan/numblsoda/tree/main/benchmark)).

I think this would be (1) a very useful and popular Python package and (2) raise awareness in the scientific community for how useful Fortran can be.

Wondering people’s thoughts! All brainstorming welcome.

---

<div class="post-metadata">

**Author:** ![everythingfunctional](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/everythingfunctional/32/176_2.png) [@everythingfunctional](https://fortran-lang.discourse.group/u/everythingfunctional)\
**Post date:** [February 28, 2022, 2:21am UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/2 "2022-02-28T02:21:49Z")

</div>

I tend to prefer smaller, well focused libraries. But perhaps that’s not a major concern in Python? And perhaps the \*PACK libraries aren’t all that well focused to begin with? Mostly just food for thought, but I wouldn’t initially jump to combining multiple Fortran libraries into a single Python package.

---

<div class="post-metadata">

**Author:** ![CRquantum](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/crquantum/32/730_2.png) [@CRquantum](https://fortran-lang.discourse.group/u/CRquantum)\
**Post date:** [February 28, 2022, 7:59am UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/3 "2022-02-28T07:59:25Z")

</div>

Very nice!

> [@nicholaswogan](#):
>
> `numbalsoda` is up to ~100x faster than scipy’s wrappers of LSODA

Eh, I mean, are you saying like for small ODE system, like just 3 ODEs or so, the C version LSODA is faster than the Fortran’s ODEPACK version of LSODA by 100x?  
I mean if both with -O3 -xHost optimization flag, C version and Fortran version seems should not have 100x difference, LOL.  
Or, is the 100x difference is mainly caused by Python?

In your opinion, in terms of speed, the new modernized ODEPACK .vs. current F77 version of ODEPACK, how much speedup can the modernized ODEPACK expect to get?

I used LSODA in the F77 ODEPACK for small system like 3 ODE system, its speed is comparable (about 30% slower than FLINT or so, seems not to bad) than some modern solver like FLINT by @prince_mahajan , [GitHub - princemahajan/FLINT: Fortran Library for numerical INTegration of differential equations](https://github.com/princemahajan/FLINT)  
If the modern version ODEPACK can be significantly faster than F77 version it would be great!

---

<div class="post-metadata">

**Author:** ![nicholaswogan](https://avatars.discourse-cdn.com/v4/letter/n/f1d935/32.png) [@nicholaswogan](https://fortran-lang.discourse.group/u/nicholaswogan)\
**Post date:** [February 28, 2022, 2:32pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/4 "2022-02-28T14:32:47Z")

</div>

The Fortran, C and C++ versions of lsoda are all almost identical in speed. The modernized version of ODEPACK will not change the speed at all.

---

<div class="post-metadata">

**Author:** ![awvwgk](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/awvwgk/32/154_2.png) [@awvwgk](https://fortran-lang.discourse.group/u/awvwgk)\
**Post date:** [February 28, 2022, 2:39pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/5 "2022-02-28T14:39:11Z")

</div>

I’m much in favor to provide language bindings for libraries we maintain under Fortran-lang. If done right it is not even noticeable that Fortran is used in Python script (apart from the speed, of course). I wouldn’t call the Python package `fortranlang` however.

For minpack there is an open issue for discussing Python bindings

> <https://github.com/fortran-lang/minpack/issues/43>
>
> We could provide Python bindings directly in this project. Dependent Python proj…ects would be able to just \`import minpack\` rather than wrapping the C API themselves.
> 
> Related to #14

Usually I put Python bindings in a subdirectory `python/` in my projects setup in a way that they can either be built directly with the main project or as a standalone against an existing installation.

* * *

My main issue is with `ctypes`, the handling is quite low-level and requires a lot of repetition, while you don’t get any useful error checking on the Python side. I usually go for wrapper generators like CFFI or SWIG or something which has more direct access to C like Cython.

---

<div class="post-metadata">

**Author:** ![nicholaswogan](https://avatars.discourse-cdn.com/v4/letter/n/f1d935/32.png) [@nicholaswogan](https://fortran-lang.discourse.group/u/nicholaswogan)\
**Post date:** [February 28, 2022, 4:33pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/6 "2022-02-28T16:33:28Z")

</div>

> [@awvwgk](#):
>
> My main issue is with `ctypes` , the handling is quite low-level and requires a lot of repetition, while you don’t get any useful error checking on the Python side. I usually go for wrapper generators like CFFI or SWIG or something which has more direct access to C like Cython.

The reason why I have used ctypes is because it is numba compatible. All Python code can be compiled and be very speedy. This sets it apart from Scipy. Cython is not numba compatible. CFFI is numba compatible, but I’ve never used it. Look very similar to ctypes? What is its advantage over ctypes?

---

<div class="post-metadata">

**Author:** ![awvwgk](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/awvwgk/32/154_2.png) [@awvwgk](https://fortran-lang.discourse.group/u/awvwgk)\
**Post date:** [February 28, 2022, 4:49pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/7 "2022-02-28T16:49:47Z")

</div>

CFFI has multiple modes, the ABI modes are similar to `ctypes`, but a bit more powerful because you have typedefs available while you only get `c_void_p` for all opaque handles in `ctypes`. Also, the dlopen step in `ctypes` is pretty fragile, because you must know where the library is you want to load and the Python module might not be installed in the same prefix as the library wrapped.

I’m mostly using the out-of-line API mode in CFFI, which allows to generate a fully functional extension module directly from a C header, meaning you don’t have to duplicate the header definition in the Python source code. With some extra effort you can even link the library you depend on statically into the extension module and are almost dependency free (useful for producing wheels).

---

<div class="post-metadata">

**Author:** ![nicholaswogan](https://avatars.discourse-cdn.com/v4/letter/n/f1d935/32.png) [@nicholaswogan](https://fortran-lang.discourse.group/u/nicholaswogan)\
**Post date:** [May 26, 2022, 1:45pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/8 "2022-05-26T13:45:27Z")

</div>

Just added a python wrapper to @jacobwilliams [dop853](https://github.com/jacobwilliams/dop853) ODE integrator, to [numbalsoda](https://github.com/Nicholaswogan/numblsoda).

This Python wrapper beats Julia’s best explicit ODE solvers on my test problem ([benchmarks here](https://github.com/Nicholaswogan/numblsoda/tree/main/benchmark)).

---

<div class="post-metadata">

**Author:** ![oscardssmith](https://avatars.discourse-cdn.com/v4/letter/o/b9e5f3/32.png) [@oscardssmith](https://fortran-lang.discourse.group/u/oscardssmith)\
**Post date:** [May 26, 2022, 2:14pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/9 "2022-05-26T14:14:28Z")

</div>

Have you measured the actual error of the different methods? When benchmarking different solvers, it’s generally a mistake to assume that specifying the same `rtol` and `atol` lead to comparable error.

---

<div class="post-metadata">

**Author:** ![nicholaswogan](https://avatars.discourse-cdn.com/v4/letter/n/f1d935/32.png) [@nicholaswogan](https://fortran-lang.discourse.group/u/nicholaswogan)\
**Post date:** [May 26, 2022, 4:02pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/10 "2022-05-26T16:02:15Z")

</div>

I have not done proper “work precision diagrams”. So ya, its possible that Julia is actually performing better.

---

<div class="post-metadata">

**Author:** ![oscardssmith](https://avatars.discourse-cdn.com/v4/letter/o/b9e5f3/32.png) [@oscardssmith](https://fortran-lang.discourse.group/u/oscardssmith)\
**Post date:** [May 26, 2022, 4:07pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/11 "2022-05-26T16:07:55Z")

</div>

Thanks for the benchmark though. I think there might be actual performance to gain. Almost half the time spent is spent on saving the output which is too high.

---

<div class="post-metadata">

**Author:** ![nicholaswogan](https://avatars.discourse-cdn.com/v4/letter/n/f1d935/32.png) [@nicholaswogan](https://fortran-lang.discourse.group/u/nicholaswogan)\
**Post date:** [May 26, 2022, 4:12pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/12 "2022-05-26T16:12:58Z")

</div>

Ya i think performance gains could be made to the `contd8` interpolation routine in `dop853`. `contd8` considers a single variable, but it could consider the interpolation of all variables at once. I think this would permit the compiler to make some additional optimizations.

---

<div class="post-metadata">

**Author:** ![jacobwilliams](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jacobwilliams/32/10_2.png) [@jacobwilliams](https://fortran-lang.discourse.group/u/jacobwilliams)\
**Post date:** [May 26, 2022, 5:15pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/13 "2022-05-26T17:15:06Z")

</div>

FYI: See here: [GitHub - princemahajan/FLINT: Fortran Library for numerical INTegration of differential equations](https://github.com/princemahajan/FLINT)

For some other benchmarks that were done with this.

---

<div class="post-metadata">

**Author:** ![nicholaswogan](https://avatars.discourse-cdn.com/v4/letter/n/f1d935/32.png) [@nicholaswogan](https://fortran-lang.discourse.group/u/nicholaswogan)\
**Post date:** [May 27, 2022, 11:39am UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/14 "2022-05-27T11:39:20Z")

</div>

These benchmarks make it look like FLINT outperforms @jacobwilliams version of dop853? This has not been my experience ([see here](https://github.com/princemahajan/FLINT/issues/3)). Although I haven’t done that much testing.

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [May 27, 2022, 10:36pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/15 "2022-05-27T22:36:34Z")

</div>

What makes FLINT faster than Julia’s differential equations? I thought they have some symbolic code compile time generation that makes it faster.

---

<div class="post-metadata">

**Author:** ![oscardssmith](https://avatars.discourse-cdn.com/v4/letter/o/b9e5f3/32.png) [@oscardssmith](https://fortran-lang.discourse.group/u/oscardssmith)\
**Post date:** [May 27, 2022, 11:35pm UTC](https://fortran-lang.discourse.group/t/fortranlang-a-python-package/2870/16 "2022-05-27T23:35:26Z")

</div>

Most of the especially fancy stuff is for large or stiff systems. When you have small nonstiff equations there’s not much you can do to speed up (even python’s Jax can compete for stuff like this). It’s also not really correct that FLINT is in general faster here. It is faster in the case with the specific type of callback used because DifferentialEquations.jl currently doesn’t yet have a way to specify a callback that you only want to hit once. For the one without callbacks, the algorithm Julia selects by default for this case (Vern8) is as fast any of the FLINT solvers.
