Wu Sun
Last updated: 2022-02-11
This is a simple cheatsheet to aid scientific programmers who work at the interfaces of both languages. It is by no means an exhaustive list. (I have yet to explore some advanced features in the Fortran 2008 and newer standards.)
Make Fortran Modern Again!
This work is licensed under the Creative Commons Attribution 4.0 International License.
Fortran 2008 | Python 3 | |
Top-level constructs | ||
the main program |
program my_program
...
end program |
Not required. Use __main__() if needed. |
modules |
module my_module
...
end module my_module |
A source file is a module. |
subroutines |
subroutine my_subroutine
...
end subroutine my_subroutine |
Functions that have side effects. |
functions |
function f(x) result(res)
res = ...
end function f |
def my_function(x):
...
return res |
submodules |
module main_module
...
contains
<submodule statements>
end module main_module |
Use folders, __init__.py , and import statement to manage submodules. |
import statement |
use my_module
use my_module, only : fun1, var1
use my_module, only : new_var => var |
from my_module import *
from my_module import fun1, var1
from my_module import var as new_var |
call subroutines and functions |
call my_subroutine(args)
my_function(args) |
my_function(args) |
abort a program |
stop |
exit() |
inline comments |
! This is a comment |
# This is a comment |
line continuation | & |
\ |
include external source files |
include 'source_file_name' |
Not supported. Use module import. |
Control flow patterns | ||
if construct |
if <logical expr> then
...
else if <logical expr> then
...
else
...
end if |
if <logical expr>:
...
elif <logical expr>:
...
else:
... |
case construct |
select case <expr>
case <value>
...
case <value>
...
case default
...
end select |
Structural pattern matching, supported since Python 3.10:
match <expr>:
case <pattern>:
...
case <pattern>:
...
case _:
... |
do construct |
do start_value, end_value, step
...
end do |
for i in range(start, end, step):
... |
do while construct |
do while <logical expr>
...
end do |
while <logical expr>:
... |
break from a loop |
exit |
break |
leave this iteration and continue to the next iteration |
cycle |
continue |
Data types | ||
declaration |
integer(kind=kind_number) :: n = 0
real(kind=kind_number) :: x = 0. |
n = 0
x = 0. |
named constants |
integer, parameter :: answer = 42
real(8), parameter :: pi = 4d0 * atan(1d0) |
Not supported in Python. Names are bindings. |
complex number |
complex :: z = (1., -1.) |
z = 1 - 1j |
string |
character(len=10) :: str_fixed_length
character(len=:), allocatable :: str_var_length |
string = "this is a string" |
pointer |
real, pointer :: p
real, target :: r
p => r |
No built-in support. May invoke from Python C API. (Why would you need it in Python anyway?) |
boolean |
.true.
.false. |
True
False |
logical operators |
.not.
.and.
.or.
.eqv.
.neqv. |
not
and
or |
equal to |
==, .eq. |
== |
not equal to |
/=, .ne. |
!= <> is deprecated in Python 3.
|
greater than |
>, .gt. |
> |
less than |
<, .lt. |
< |
greater than or equal to |
>=, .ge. |
>= |
less than or equal to |
<=, .ge. |
<= |
array declaration |
real(8), dimension(3) :: a = [1., 2., 3.] |
import numpy as np
a = np.array([1., 2., 3.]) |
string array declaration |
character(len=20), dimension(3, 4) :: char_arr |
char_arr = np.chararray((3, 4), itemsize=20) |
elementwise array operations |
a op b op can be +, -, *, /, **, =, == , etc.This is supported since the Fortran 90 standard. |
Supported through numpy.ndarray type. |
first element |
a(1) |
a[0] |
slicing |
a(1:5) a(5) .
|
a[0:5] a[5] .
|
slicing with steps |
a(1:100:2) |
a[0:100:2] |
size |
size(a) |
a.size |
shape |
shape(a) |
a.shape |
shape along a dimension |
size(a, dim) |
a.shape[dim] |
Type conversion | ||
to integer by truncation |
int() |
int() |
to integer by rounding |
nint() |
int(round()) |
integer to float |
real(a[, kind]) |
float() |
complex to real |
real(z[, kind]) |
z.real |
to complex |
cmplx(x [, y [, kind]]) |
complex() |
to boolean |
logical() |
bool() |
Derived data types | ||
definition |
type Point
real(8) :: x, y
end type Point |
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y |
instantiation |
type(Point) :: point1 = Point(-1., 1.) |
point1 = Point(-1., 1.) |
get attributes |
point1%x
point1%y |
point1.x
point1.y |
array of derived type |
type(Point), dimension(:), allocatable :: point_arr |
No built-in support. You may need to subtype the NumPy array. (Why not use a structured array instead of an array of structure?) |
type bound procedures (aka class method) | Assume that Circle has a type bound procedure (subroutine) print_area .
type(Circle) :: c
call c%print_area |
Assume that Circle has a class method print_area() .
c = Circle()
c.print_area() |
Built-in mathematical functions | ||
functions with the same names |
abs(), cos(), cosh(), exp(), floor(), log(),
log10(), max(), min(), sin(), sinh(), sqrt(),
sum(), tan(), tanh() |
Have the same name in NumPy. |
functions with different names |
acos()
aimag()
asin()
atan()
atan2(x, y)
ceiling()
conjg(z)
modulo()
call random_number() |
np.arccos()
z.imag
np.arcsin()
np.arctan()
np.arctan2(x, y)
np.ceil()
np.conjugate(z), z.conjugate()
np.mod(), %
np.random.random_sample() |
Built-in string functions | ||
string length |
len() |
len() |
string to ASCII code |
iachar() |
ord() |
ASCII code to string |
achar() |
chr() |
string slicing | Same as 1D array slicing. | Same as 1D array slicing. |
find the position of a substring |
index(string, substring) |
string.index(substring) |
string concatenation |
"hello" // "world" |
"hello" + "world"
"hello" "world"
("hello" "world") |
Array constructs | ||
where construct |
where a > 0
b = 0
elsewhere
b = 1
end where |
For NumPy arrays,
b[a > 0] = 0
b[a <= 0] = 1 filter() or list comprehension.
|
forall construct |
real, dimension(10, 10) :: a = 0
int :: i, j
...
forall (i = 1:10, j = 1:10, i <= j)
a(i, j) = i + j
end forall |
import itertools
import numpy as np
a = np.zeros((10, 10))
for i, j in itertools.product(range(10), range(10)):
if i <= j:
a[i, j] = i + j forall construct in Python. There are definitely other (and more Pythonic) ways of doing the same thing.
|
Other built-in subroutines | ||
CPU time |
call cpu_time() |
import time
time.time() |
command line arguments |
call command_argument_count()
call get_command()
call get_command_argument() |
For basic parsing, use sys.argv . For more advanced use, see the built-in argparse module. |
Input/output | ||
print fmt, <output list> |
print() |
|
read from the command prompt |
read fmt, <input list> |
input(prompt) |
open a file |
open(unit, file, ...) |
f = open(file, mode='r', ...) |
read from a file |
read(unit, fmt, ...) <input list> |
f.read(size)
f.readline() |
write to a file |
write(unit, fmt, ...) <output list> |
f.write() |
close a file |
close(unit, ...) |
f.close() |
file inquiry |
inquire(unit, ...) |
Use the file utilities provide by the os module. |
backspace in a file |
backspace(unit, ...) |
f.seek(-1, 1) |
end of file (EOF) |
endfile(unit, ...) |
f.read() == '' |
return to the start of a file |
rewind(unit, ...) |
f.seek(0) |