Fortran Guidelines#
Coding style#
When modifying an existing file, try to maintain consistency with its original style. If the code you add looks drastically different from the original code, it may be difficult for readers to follow. Try to avoid this. As a general guideline, we recommend the following code formatting style:
give space for breathing:
good
dx = 0.5 * fac * (a - b)
bad
dx=1/2*fac*(a-b)
Note that in performance critical sections, please use multiplication by 0.5 rather than divide by 2 for floating-points.
use consistent 2-space indents:
good
if (i == 1) then
print *,'great'
endif
bad
if(i == 1)then
print *,'not so great'
endif
start your code with an indent:
good
subroutine vbspl()
implicit none
..
bad
subroutine vbspl
implicit none
..
The line beginning should only be used for very important sections, as it makes the line very prominent to read. For example, only use it for function descriptions, important comments, or file headers. For comments, see also next point…
exception, module definitions start at beginning:
good
module models
integer :: count
end module
bad
module models
integer :: count
end module
comment, comment, comment your code:
good
! gets associated values
fg = vbspl(4,2)
! find values
gt = fg
bad
fg = vbspl(4,2)
Note we prefer indenting the comments as well to make it easier for reading the code, e.g., when inside multiple if-then statements. Putting the comment at the beginning breaks the flow.
comment, comment, comment your functions:
good
subroutine blah_blah_function()
! calculates TI gradient based on a conjugate gradient method
!
! based on: Tarantola, inverse problem theory, 2005.
! section 6.22.7 conjugate directions, page 217.
! formula for alpha_n based on Polak & Ribiere (1969)
!
! note: we use a preconditioner F_0 = 1, thus lambda_n = gamma_n in (6.322)
! and use gamma_n as the smoothed kernel (for bulk_c, bulk_betav,..).
..
bad
subroutine blah_blah_function()
! computation step
..
Note that we haven’t been very strict in adopting a doxygen-readable function declaration.
use double-colons for parameter declarations:
good
integer :: i,j,k
bad
integer i,j,k
use separators between subroutines:
good
..
end subroutine
!
!----------------------------------------------------------
!
subroutine get_color(icolor)
..
bad
..
end subroutine
subroutine get_color(icolor)
..
F2PY Troubleshooting#
Warning
AVNI used F2PY to wrap legacy
Python code by building from source code using the numpy.distutils
. This
requires restricting the versions to numpy<=1.22
and setuptools<60.0
in
setup.py
following this
link.
Ultimately, AVNI will be migrated to use the latest version of the setuptools
package. :::
The purpose of the F2PY
– Fortran to Python interface generator– utility is to
provide a connection between Python and Fortran. F2PY
is a part of NumPy
(numpy.f2py
) and also available as a standalone command line tool. We store
legacy Fortran code in the avni/f2py
folder. A way to troubleshoot F2PY
issues involves the following steps:
Copy all of the source code to a single directory
Make sure that the code will actually compile without f2py (either with a makefile or with a simple script)
Use f2py to create a python signature file (
.pyf
file).
See the makefile attached below which will compile all of the code, and generate
the file avni_forward.pyf
. The .pyf
file can be used to figure out what
problems are going on. In our case, there were a number of subroutines that were
not being properly translated to the signature file. These subroutines are
called “unknown_subroutine” in the signature file. For example, the signature
file complained about a subroutine in rayseq.f
:
subroutine unknown_subroutine ! in rayseq.f
integer :: iprtlv
common /plevel/ iprtlv
end subroutine unknown_subroutine
Since it wasn’t really giving us any reasons why the subroutine was unknown, it was a little hard to figure out how to fix. It turns out the problem (in this case) was that the subroutine definition in rayseq.f exceeded the fortran character limit of 72. So to fix it, we just added a continuation line to the source code:
diff rayseq.f ../ALLCODES/rayseq.f
1c1,2
< SUBROUTINE RAYSEQ (NP,NS,NN,ISS,IRR,ICNSx,ICNR,ICN,ISEQ,idirseg,NSEG)
---
> SUBROUTINE RAYSEQ (NP,NS,NN,ISS,IRR,ICNSx,ICNR,ICN,ISEQ,
> #idirseg,NSEG)
There were a number of other source files that we had to modify, but as far as
we remember, the only changes we made were to fix character limit issues. Once
there were no more problems in the python signature file, we copied the source
codes back to their respective directories, and everything worked fine with
pip
. We can’t say that this method will work for troubleshooting other F2PY
issues.
# makefile
#LOBJ = ./objects
LOBJ = ./
FFLAGS = -ffixed-line-length-none -fPIC -O3 -fbounds-check
SRCS = tt_predict.f acosd.f asind.f atand.f bffi.f bullen.f cagcrays_pm.f closfl.f conv2geocen.f cosd.f dacosd.f dbsplrem.f dcosd.f ddelaz.f ddelazgc.f \
delaz.f delazgc.f DiffTime.f drspleder.f drspledr.f drsple.f drspln.f dsind.f dxt.f evemb.f evemdr.f evemell.f evem.f fdrays.f fqs.f \
get_branch.f getcmt5.f getcmtbyname.f getcmtdatetime.f getflpos.f get_ishflag.f getptab.f julday.f legndr.f lpyr.f monday.f openfl.f \
pdaz.f prange.f psvrayin.f qtauall.f qtau.f qtauzero.f rayseq.f reademb.f reademfl.f readnbn.f readptab.f sind.f swap4of4.f tadder.f \
tand.f vbspl.f wgint.f wgray.f ylm.f
OBJS = tt_predict.o acosd.o asind.o atand.o bffi.o bullen.o cagcrays_pm.o closfl.o conv2geocen.o cosd.o dacosd.o dbsplrem.o dcosd.o ddelaz.o ddelazgc.o \
delaz.o delazgc.o DiffTime.o drspleder.o drspledr.o drsple.o drspln.o dsind.o dxt.o evemb.o evemdr.o evemell.o evem.o fdrays.o fqs.o \
get_branch.o getcmt5.o getcmtbyname.o getcmtdatetime.o getflpos.o get_ishflag.o getptab.o julday.o legndr.o lpyr.o monday.o openfl.o \
pdaz.o prange.o psvrayin.o qtauall.o qtau.o qtauzero.o rayseq.o reademb.o reademfl.o readnbn.o readptab.o sind.o swap4of4.o tadder.o \
tand.o vbspl.o wgint.o wgray.o ylm.o
F2PY = f2py
F77 = gfortran
F90 = fortran
CC = gcc
avni_forward.so: $(OBJS) avni_forward.pyf
$(F2PY) -c avni_forward.pyf $(OBJS)
avni_forward.pyf: $(SRCS)
$(F2PY) --overwrite-signature -m avni_forward -h avni_forward.pyf $(SRCS)
clean:
$(RM) $(LOBJ)/*.o $(LOBJ)/*.pyf ./avni_forward.so
$(LOBJ)/%.o: %.f
$(F77) $(FFLAGS) -c $*.f -o $(LOBJ)/$*.o