Fortran would not be my first choice for working with text, in any form! However, sometimes even numerical codes need to read data from configuration files. The easiest way to read a configuration file from a Fortran 90 routine is by using namelist I/O (I really need to add an example of that). If you’re stuck with INI files, I found an INI file parser written in Fortran buried in an index of free Fortran routine. I don’t even remember how I even found it, since it’s not well labeled and doesn’t come up in the first few pages of Google results, so I thought I’d better write a post about it in case I ever need such a thing in the future.
I’ve just released a self-contained Fortran module that solves a system of linear equations using the LU decomposition.
This module is based on code that was implemented and released on the Web by Jean-Pierre Moreau. His implementation was based on one of the Numerical Recipes books. I updated his code to a more strict Fortran 90 standard and added the necessary comments so that it can be built as a Python module using f2py. I replaced Jean-Pierre’s Fortran test program with a simpler, self-contained program. I also included a Python script that implements the same test case.
I created this module because sometimes a self-contained routine is more appropriate than a full library. I am compiling a library that implements a custom boundary condition for a proprietary computational fluid dynamics solver (CFD-ACE+). The library has to be written in Fortran, and it has to be built using a proprietary set of build scripts. I could either try to reverse-engineer the build process and to modify it to link to a shared library like LAPACK, or I could implement a self-contained solver. Since Pierre had already implemented the solver, I was able to slightly modify his code and get it working relatively quickly.
I have been optimizing some Fortran code that involved searching for an integer value in an unordered array (we know the value occurs only once). Since there is no intrinsic procedure to accomplish this, I thought I’d try a couple of approaches to see which was fastest. The simple answer is that, in this case, brute force beats elegance, even when the target value is near the end of the array.
Method 1: Brute force
Algorithm: use a do loop to iterate through the array until you find the target value. Exit the loop when you find the value.
do i = 1, num_elements if (array1(i) .eq. target_value) then loc = i exit endif end do
Results: CPU time required my PC: 0.048 sec
I’m using GNU Fortran (gfortran) to build several shared libraries, and then dynamically linking to them from a Fortran program. The process is a little different than what I’m used to for C libraries, so I thought I’d explain it. Unlike C, there is no need to #include header files when compiling code that relies on functions defined in an external library. Likewise, there is no need to use -l or -L linking flags to tell the linker about s hared libraries (at least when they’re in the same directory). In fact, the whole process requires a lot less command-line options than I had expected.
Building the Fortran shared libraries
I want to test a library called my_library. However, this library relies upon another library, which is called cfdrc_user_access. I want to compile a unit-test program that calls my library and makes sure it is working correctly.
gfortran -shared -fPIC -o cfdrc_user_access.so cfdrc_user_access.f90 gfortran -shared -fPIC -o cfdrc_user.so my_library.f90
Linking the shared libraries with a Fortran program
First, compile the program to an object file (.o), using the -c flag as shown on the first line. Then use gfortran to link the object file with the shared libraries created in the previous step:
gfortran -c blocking.f90 gfortran -o blocking blocking.o cfdrc_user.so cfdrc_user_access.so
Remember, unless the shared libraries are in a directory that’s already on your dynamic linker path, you will probably need to modify your LD_LIBRARY_PATH in order to run the program.
export LD_LIBRARY_PATH=/home/yourname/current_working_directory/ ./blocking
That worked for me–hopefully it helps you.
I have recently started using f2py to call Fortran from Python. I have found this useful for two reasons: speeding up Python scripts by calling compiled Fortran code, and using Python as a unit testing framework for Fortran modules. Unfortunately, the documentation for f2py is rather sparse, and may not be completely up to date. In this note, I will hopefully prevent you from wasting a lot of time figuring out how to pass array arguments, and return array results.
Passing array arguments is a critical when working with numerical algorithms. F2py handles this well, but it is difficult to figure it out how to do it correctly. Here is a simple example with some Fortran 90 routines:
module test contains subroutine foo (a) implicit none integer, intent(in) :: a print*, "Hello from Fortran!" print*, "a=",a end subroutine foo function bar (len_a, a) implicit none integer, intent(in) :: len_a real, dimension(len_a), intent(in) :: a real, dimension(len_a) :: bar !f2py depend(len_a) a, bar integer :: i real, dimension(len_a) :: b do i=1,len_a b(i) = 2.0*a(i) end do bar = b end function bar subroutine sub (a, len_a, a_out) implicit none real, dimension(len_a), intent(in) :: a integer, intent(in) :: len_a real, dimension(len_a), intent(out) :: a_out integer :: i do i=1,len_a a_out(i) = 2.0*a(i) end do end subroutine sub end module test
Function “foo” is quite straightforward. Function “bar” is a little more complex, because it accepts an array argument and returns an array. If you’re new to Fortran, it will seem strange to pass the length of the array along with the array, but you need that information to declare the output array. f2py needs to know that the input array a and the output array bar both depend on the argument len_a. The special comment line
!f2py depend(len_a) a, bar
is mandatory! It tells f2py that a depends on len_a. If you omit this comment or the corresponding one for, the function will not work correctly. You will get strange errors like
ValueError: failed to create intent(cache|hide)|optional array-- must have defined dimensions but got (0,)
Now look at the subroutine called sub. On the Fortran side, it has three arguments: two inputs and an output. However, Python only has functions, and all non-array arguments are passed by value. How do you reconcile this? When the Fortran subroutine is called from Python, the intent(out) variables are returned as a function result, or a tuple of results if there are more than one. Compare the Fortran code above with the Python call below to see what I mean.
This code can be compiled using the “fast and smart” method described in the docs:
f2py -c -m hello hello.f90
Here is the Python code that calls the Fortran routines:
#!/usr/bin/env python import hello from numpy import * a = arange(0.0, 10.0, 1.0) len_a = len(a) print "foo:" hello.test.foo(len_a) print "bar:" a_out = hello.test.bar(len_a, a) print a_out print "sub:" a_out = hello.test.sub(a, len_a) print a_out
You might also want to check out this rather complicated f2py example.