# Interfacing with Fortran from Python using 'iso\_c\_binding'

**URL:** <https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886>\
**Category:** Help\
**Created:** [May 31, 2023, 7:44am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886 "2023-05-31T07:44:20Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![abhi](https://avatars.discourse-cdn.com/v4/letter/a/b487fb/32.png) [@abhi](https://fortran-lang.discourse.group/u/abhi)\
**Post date:** [May 31, 2023, 7:44am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/1 "2023-05-31T07:44:20Z")

</div>

Hi there.  
I am trying to learn how to interface with Fortran from Python using ‘iso\_c\_binding’. To test interoperability, I wrote a simple Fortran module to calculate the sum and mean of a 1D array, which is given below:

```auto
module module_calculate_stats
    use iso_fortran_env
    use iso_c_binding
    implicit none

    contains
        subroutine calculate_sum(array, array_sum) bind(C)
            real(kind=c_float), intent(in), dimension(:)::array
            real(kind=c_float), intent(out)::array_sum
            array_sum=sum(array)
        end subroutine calculate_sum

        subroutine calculate_mean(array, array_mean) bind(C)
            real(kind=c_float), intent(in), dimension(:)::array
            real(kind=c_float), intent(out)::array_mean
            array_mean=sum(array)/size(array)
        end subroutine calculate_mean

end module module_calculate_stats

```

I have successfully called the module subroutines from another Fortran program. The module was compiled into a shared library using the following command:

`gfortran --shared module_calculate_stats.f90 -o module_calculate_stats.so -fPIC`

Now, onto the Python program that calls the Fortran module:

```auto
import ctypes as ct

import numpy as np

if __name__ ==' __main__':

    fort_lib=ct.CDLL('./module_calculate_stats.so')
    fort_lib.calculate_sum.argtypes=[
            ct.POINTER(ct.c_float),]
    fort_lib.calculate_sum.restype=ct.c_float

    total=ct.c_float(-1)
    array=np.array(
            [1, 2, 3, 4, 5, 6], dtype=ct.c_float, order='F')
    array_ptr=array.ctypes.data_as(ct.POINTER(ct.c_float))

    fort_lib.calculate_sum(array_ptr, ct.byref(total))
    print(total)

```

When I run the Python program, I either get a `segmentation fault (core dumped)` or `Internal Error: Invalid type in descriptor`.  
What am I doing wrong and how do I fix it?

---

<div class="post-metadata">

**Author:** ![egio](https://avatars.discourse-cdn.com/v4/letter/e/dbc845/32.png) [@egio](https://fortran-lang.discourse.group/u/egio)\
**Post date:** [May 31, 2023, 9:39am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/2 "2023-05-31T09:39:39Z")

</div>

Well you have to pass explicitly the size of the array, in Fortran:

```fortran
        subroutine calculate_mean(array, array_mean, n) bind(C)
            real(kind=c_float), intent(in), dimension(n)::array
            real(kind=c_float), intent(out)::array_mean
            integer(c_int), value :: n
            array_mean=sum(array)/n
        end subroutine calculate_mean

```

And in Python I suggest to use:

```python
from numpy.ctypeslib import ndpointer
...
fort_lib.calculate_sum.argtypes=[
            ndpointer(dtype=ct.c_float),
            ct.POINTER(ct.c_float),
            ct.c_int]
...

def my_mean(arr):
    arr = np.ascontiguousarray(arr, dtype=ct.c_float)
    mean = ct.c_float(0.0)
    n = arr.size
    fort_lib.calculate_sum(array, mean, n)
    return mean.value

```

I haven’t checked the code so there may be some small errors, but this is the idea.

---

<div class="post-metadata">

**Author:** ![egio](https://avatars.discourse-cdn.com/v4/letter/e/dbc845/32.png) [@egio](https://fortran-lang.discourse.group/u/egio)\
**Post date:** [May 31, 2023, 9:52am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/3 "2023-05-31T09:52:26Z")

</div>

This is a complete working example:

```fortran
module module_calculate_stats
    use iso_fortran_env
    use iso_c_binding
    implicit none

    contains
        subroutine calculate_sum(array, array_sum, n) bind(C)
            integer(c_int), value :: n
            real(kind=c_float), intent(in), dimension(n)::array
            real(kind=c_float), intent(out)::array_sum
            array_sum=sum(array)
        end subroutine calculate_sum

        subroutine calculate_mean(array, array_mean, n) bind(C)
            integer(c_int), value :: n
            real(kind=c_float), intent(in), dimension(n)::array
            real(kind=c_float), intent(out)::array_mean
            array_mean=sum(array)/n
        end subroutine calculate_mean

end module module_calculate_stats

```

And the Python part:

```python
import ctypes as ct
import numpy as np
from numpy.ctypeslib import ndpointer

fort_lib=ct.CDLL('./module_calculate_stats.so')

fort_lib.calculate_sum.argtypes=[
            ndpointer(dtype=ct.c_float),
            ct.POINTER(ct.c_float),
            ct.c_int]
fort_lib.calculate_sum.restype=None

def my_mean(arr):
    arr = np.ascontiguousarray(arr, dtype=ct.c_float)
    mean = ct.c_float(0.0)
    n = arr.size
    fort_lib.calculate_sum(arr, mean, n)
    return mean.value

print(my_mean([1,2,3,4,5]))

```

The actual call to the Fortran library should always be hided inside a python function, as you have to check that all the arguments are at least contiguous etc.

---

<div class="post-metadata">

**Author:** ![HugoMVale](https://avatars.discourse-cdn.com/v4/letter/h/e19adc/32.png) [@HugoMVale](https://fortran-lang.discourse.group/u/HugoMVale)\
**Post date:** [May 31, 2023, 11:48am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/4 "2023-05-31T11:48:47Z")

</div>

Perhaps the examples provided here can help: [fortran-in-python/src/example-ctypes at main · HugoMVale/fortran-in-python · GitHub](https://github.com/HugoMVale/fortran-in-python/tree/main/src/example-ctypes)

---

<div class="post-metadata">

**Author:** ![hkvzjal](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/hkvzjal/32/3055_2.png) [@hkvzjal](https://fortran-lang.discourse.group/u/hkvzjal)\
**Post date:** [May 31, 2023, 12:25pm UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/5 "2023-05-31T12:25:06Z")

</div>

Here another micro example that could help out [https://github.com/scipy/scipy/issues/18118#issuecomment-1557557290](https://github.com/scipy/scipy/issues/18118#issuecomment-1557557290)

---

<div class="post-metadata">

**Author:** ![abhi](https://avatars.discourse-cdn.com/v4/letter/a/b487fb/32.png) [@abhi](https://fortran-lang.discourse.group/u/abhi)\
**Post date:** [June 1, 2023, 6:32am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/6 "2023-06-01T06:32:54Z")

</div>

Thank you for your help. It did help me in fixing the issue.  
Is there any reason you used the `value` argument for the `n` variable, couldn’t it have been `intent(in)` like the `array` variable?

---

<div class="post-metadata">

**Author:** ![abhi](https://avatars.discourse-cdn.com/v4/letter/a/b487fb/32.png) [@abhi](https://fortran-lang.discourse.group/u/abhi)\
**Post date:** [June 1, 2023, 6:35am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/7 "2023-06-01T06:35:48Z")

</div>

Another question I have with your answer is, do I have to specify the array size to the Fortran module? As I have seen in many examples, you can just use `:` for dynamically allocated arrays.  
And in my Fortran program that calls the subroutines, I used a dynamic array and did not pass the size to the subroutine.

---

<div class="post-metadata">

**Author:** ![ricriv](https://avatars.discourse-cdn.com/v4/letter/r/f17d59/32.png) [@ricriv](https://fortran-lang.discourse.group/u/ricriv)\
**Post date:** [June 1, 2023, 7:07am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/8 "2023-06-01T07:07:14Z")

</div>

Here is what Steve Lionel wrote on this topic [python - Passing array to function with assumed-shape - Stack Overflow](https://stackoverflow.com/a/40710156/3676517)

---

<div class="post-metadata">

**Author:** ![HugoMVale](https://avatars.discourse-cdn.com/v4/letter/h/e19adc/32.png) [@HugoMVale](https://fortran-lang.discourse.group/u/HugoMVale)\
**Post date:** [June 1, 2023, 7:54am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/9 "2023-06-01T07:54:14Z")

</div>

For consistency, `n` should preferably have `intent(in)`.  
The attribute `value` is a matter of choice, but requires _consistent_ handling because fortran passes arguments by reference and C by value:

- if you add `value`, you can pass the argument “normally” in python.
- if you do not add `value`, then you need to pass by reference in python.

Two examples below.

[fortran-in-python/example\_ctypes.py at main · HugoMVale/fortran-in-python · GitHub](https://github.com/HugoMVale/fortran-in-python/blob/main/src/example-ctypes/example_ctypes.py)

```python
from ctypes import CDLL, c_int, c_double, byref, POINTER
import numpy as np
import os

# %% Import dll
here = os.path.dirname(os.path.realpath( __file__ ))
mathtools = CDLL(os.path.join(here, './fortran/mathtools.dll'))

# %% intproduct (args passed by reference)

a = 3
b = 4
result = mathtools.intproduct(byref(c_int(a)), byref(c_int(b)))
print("intproduct: ", result)

# %% intproduct (args passed by value)

a = 3
b = 4
result = mathtools.intproduct_byvalue(c_int(a), c_int(b))
print("intproduct_byvalue: ", result)

```

[fortran-in-python/mathtools.f90 at main · HugoMVale/fortran-in-python · GitHub](https://github.com/HugoMVale/fortran-in-python/blob/main/src/example-ctypes/fortran/mathtools.f90)

```fortran
 integer(c_int) function intproduct(a, b) result(res) bind(c)
    !! Product of two integers directly in C types
    integer(c_int), intent(in) :: a, b
    res = a*b
 end function

 integer(c_int) function intproduct_byvalue(a, b) result(res) bind(c)
    !! Product of two integers directly in C types
    integer(c_int), value, intent(in) :: a, b
    res = a*b
 end function

```

---

<div class="post-metadata">

**Author:** ![egio](https://avatars.discourse-cdn.com/v4/letter/e/dbc845/32.png) [@egio](https://fortran-lang.discourse.group/u/egio)\
**Post date:** [June 1, 2023, 8:07am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/10 "2023-06-01T08:07:55Z")

</div>

Yes it could. No real reason, just a stylistic preference.  
Strictly speaking when you pass a scalar variable with the **value** attribute its value may be passed directly on a register of the CPU, while if you use an **intent(in)** you pass the address of the variable on a register of the CPU, so you have to dereference that address. But the difference is negligible, so it is just a stylistic preference.  
As I’m using procedure that should appear as a C procedure I stick to the C way of writing and way of passing arguments.  
If I were calling Fortran from Fortran I would have used a variable with **intent(in)** as this is the way one writes in Fortran.

Of course there is a difference in Fortran between a variable with the **value** attribute and one with the **intent(in)** attribute.

---

<div class="post-metadata">

**Author:** ![Idir](https://avatars.discourse-cdn.com/v4/letter/i/77aa72/32.png) [@Idir](https://fortran-lang.discourse.group/u/Idir)\
**Post date:** [September 5, 2023, 9:22am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/11 "2023-09-05T09:22:02Z")

</div>

hi @egio ,

I tried your example but I got the following error: AttributeError: function ‘calculate\_sum’ not found.

Do you have any idea of the origin of the problem ?

Thank you .

---

<div class="post-metadata">

**Author:** ![egio](https://avatars.discourse-cdn.com/v4/letter/e/dbc845/32.png) [@egio](https://fortran-lang.discourse.group/u/egio)\
**Post date:** [September 5, 2023, 11:41am UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/12 "2023-09-05T11:41:51Z")

</div>

I need to see your actual python and Fortran code, and how you compile the source code.  
Remember that you should create a shared library, compiling typically the source with the option `-shared` and `-fpic` look at:  
[Managing libraries (static and dynamic libraries) — Fortran Programming Language](https://fortran-lang.org/en/learn/building_programs/managing_libraries/)

---

<div class="post-metadata">

**Author:** ![Idir](https://avatars.discourse-cdn.com/v4/letter/i/77aa72/32.png) [@Idir](https://fortran-lang.discourse.group/u/Idir)\
**Post date:** [September 5, 2023, 12:14pm UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/13 "2023-09-05T12:14:51Z")

</div>

Fortran code:  
[Calc\_Stats.f90](https://fortran-lang.discourse.group/uploads/short-url/4Zo8cFDlwUCsM119Nwn2Ujs8UWn.f90) (750 Bytes)

Python code:

> **Summary**
>
> import ctypes as ct  
> import numpy as np  
> from numpy.ctypeslib import ndpointer
> 
> fort\_lib=ct.CDLL(‘./Calc\_stats.dll’)
> 
> fort\_lib.calculate\_sum.argtypes=[  
> ndpointer(dtype=ct.c\_float),  
> ct.POINTER(ct.c\_float),  
> ct.c\_int]  
> fort\_lib.calculate\_sum.restype=None
> 
> fort\_lib.calculate\_mean.argtypes=[  
> ndpointer(dtype=ct.c\_float),  
> ct.POINTER(ct.c\_float),  
> ct.c\_int]  
> fort\_lib.calculate\_mean.restype=None
> 
> def my\_sum(arr):  
> arr = np.ascontiguousarray(arr, dtype=ct.c\_float)  
> som = ct.c\_float(0.0)  
> n = arr.size  
> fort\_lib.calculate\_sum(arr, mean, n)  
> return som.value
> 
> def my\_mean(arr):  
> arr = np.ascontiguousarray(arr, dtype=ct.c\_float)  
> mean = ct.c\_float(0.0)  
> n = arr.size  
> fort\_lib.calculate\_mean(arr, mean, n)  
> return mean.value
> 
> print(my\_sum([1,2,3,4,5]))  
> print(my\_mean([1,2,3,4,5]))

I use IFORT to create my DLL :

- $ ifort -c Calc\_Stats.f90

- $ ifort -dll -exe:Calc\_Stats.dll Calc\_Stats.obj

---

<div class="post-metadata">

**Author:** ![egio](https://avatars.discourse-cdn.com/v4/letter/e/dbc845/32.png) [@egio](https://fortran-lang.discourse.group/u/egio)\
**Post date:** [September 5, 2023, 12:46pm UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/14 "2023-09-05T12:46:54Z")

</div>

In windows you have to change your source like:

```fortran
module module_calculate_stats
    use iso_fortran_env
    use iso_c_binding
    implicit none

    contains
        subroutine calculate_sum(array, array_sum, n) bind(C)
        !DEC$ ATTRIBUTES DLLEXPORT :: calculate_sum
            integer(c_int), value :: n
            real(kind=c_float), intent(in), dimension(n)::array
            real(kind=c_float), intent(out)::array_sum
            array_sum=sum(array)
        end subroutine calculate_sum

        subroutine calculate_mean(array, array_mean, n) bind(C)
        !DEC$ ATTRIBUTES DLLEXPORT :: calculate_mean
            integer(c_int), value :: n
            real(kind=c_float), intent(in), dimension(n)::array
            real(kind=c_float), intent(out)::array_mean
            array_mean=sum(array)/n
        end subroutine calculate_mean

end module module_calculate_stats

```

Note the `!DEC$ ATTRIBUTES DLLEXPORT :: calculate_...`.  
See: [https://community.intel.com/t5/Intel-Fortran-Compiler/Creating-dll-from-fortran-file/m-p/1182026](https://community.intel.com/t5/Intel-Fortran-Compiler/Creating-dll-from-fortran-file/m-p/1182026)

---

<div class="post-metadata">

**Author:** ![Idir](https://avatars.discourse-cdn.com/v4/letter/i/77aa72/32.png) [@Idir](https://fortran-lang.discourse.group/u/Idir)\
**Post date:** [September 5, 2023, 12:52pm UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/15 "2023-09-05T12:52:38Z")

</div>

@egio thank you.

---

<div class="post-metadata">

**Author:** ![mskocic](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mskocic/32/3378_2.png) [@mskocic](https://fortran-lang.discourse.group/u/mskocic)\
**Post date:** [September 5, 2023, 5:10pm UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/16 "2023-09-05T17:10:08Z")

</div>

If you use gfortran on windows (msys2) you can pass the option --export-all-symbol to the linker.

```auto
gfortran -o Calc_Stats.dll -Wl,--out-implib= Calc_Stats.dll.a,--export-all-symbols,--enable-auto-import, -Wl Calc_Stats.o

```

---

<div class="post-metadata">

**Author:** ![Christophe](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/christophe/32/1906_2.png) [@Christophe](https://fortran-lang.discourse.group/u/Christophe)\
**Post date:** [May 6, 2024, 2:00pm UTC](https://fortran-lang.discourse.group/t/interfacing-with-fortran-from-python-using-iso-c-binding/5886/17 "2024-05-06T14:00:39Z")

</div>

Hello, I have a similar question :

I try to transmit a function defined in a python3 to Fortran and I have to use Cython in order to do it.

PS: Just need a one way transmission from python to fortran
