I am creating a Python module in Fortran using f2py
. I would like produce an error (including error message) in the Python program if an error is encountered in the Fortran module. Consider the following example:
Fortran code (test.f):
subroutine foo(a,m)
integer :: m,i
integer, dimension(m) :: a
!f2py intent(in) :: m
!f2py intent(in,out) :: a
!f2py intent(hide), depend(a) :: m=shape(a)
do i = 1,m
if ( a(i) .eq. 0 ) then
print*, 'ERROR HERE..?'
end if
a(i) = a(i)+1
end do
end subroutine
This very simple program adds 1
to each element of a
. But should produce an error if a(i)
equal to zero. The accompanying Python code:
import test
print test.foo(np.array([1,2],dtype='uint32'))
print test.foo(np.array([0,2],dtype='uint32'))
The output is now:
[2 3]
ERROR HERE..?
[1 3]
But I want the Python program to hold on the error. Please help.
Answer
The stop
command in Fortran does exactly this. Consider the updated Fortran code:
subroutine foo(a,m)
integer :: m,i
integer, dimension(m) :: a
!f2py intent(in) :: m
!f2py intent(in,out) :: a
!f2py intent(hide), depend(a) :: m=shape(a)
do i = 1,m
if ( a(i) .eq. 0 ) then
print*, 'Error from Fortran'
stop
end if
a(i) = a(i)+1
end do
end subroutine
The output is now:
[2 3]
Error from Fortran
I.e. the Python code does not continue after the error.
I've suggested to the numpy
community to add add an extra f2py "enhancement" (raise_python_exception
) which makes it possible to define a string variable in Fortran that if non-empty will cause Python to raise an exception once the function returns.
So in Fortran you would write something like:
subroutine calc_dq(q, temp, dq, error_mesg)
!f2py raise_python_exception error_mesg
real, intent(in) :: q, temp
real, intent(out) :: dq
character(len=100), intent(out) :: error_mesg
if (.not. init_called()) then
error_mesg = "`init` hasn't been called."
else
call q_flux_function(q, temp, dq)
endif
end subroutine calc_dq
And called from Python the content of the error_mesg
variable is used as the content of the exception:
In [2]: calc_dq(1.0, 300.)
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-8-c0ce0cb9cda1> in <module>()
----> 1 calc_dq(1.0, 300.)
Exception: `init` hasn't been called.
I think this is quite a convenient way of raising exceptions from Fortran as it allows the exception message to be easily defined. I have put my suggestion on github.
f2py
does provide some statements that can be used to raise exceptions. See details here:
http://cens.ioc.ee/projects/f2py2e/usersguide/#statements
In particular, look at callstatement
which describes how to add f2py_success = 0
which will trigger an exception.
I'm not sure this will help you with debugging the internals of the fortran library, but at least it is a start.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With