Skip to content
Volume F · The TensorCore.si Library

Fortran

The original language of scientific computing.

Fortran (FORmula TRANslation) was the first widely used high-level language, and it is still a leader in numerical computing. Weather forecasts, climate models, physics simulations and the BLAS and LAPACK linear algebra routines inside NumPy and many ML libraries all have deep Fortran roots.

Prologue

Why learn Fortran?

Supercomputers still run huge amounts of Fortran, and modern Fortran is far cleaner than its reputation suggests.

  • Array maths built in: whole-array operations without loops.
  • Speed: compilers have optimised Fortran for over 60 years.
  • HPC and GPUs: coarrays, OpenMP, OpenACC and CUDA Fortran for parallel work.
Prologue

Set up and run your first program

Install gfortran (part of GCC). The Fortran Package Manager (fpm) makes projects easy.

terminal
sudo apt install gfortran
gfortran hello.f90 -o hello
./hello
hello.f90
program hello
  implicit none
  character(len=*), parameter :: name = "Ada"
  print *, "Hello, AI! Welcome to Fortran, ", name, "."
end program hello
TipAlways write implicit none so every variable must be declared.
Chapter 1

Variables and types

Declare variables at the top of a program unit. parameter makes a constant. Use real(8) or the iso_fortran_env kinds for double precision.

variables.f90
program variables
  use iso_fortran_env, only: dp => real64
  implicit none
  integer, parameter :: layers = 32
  real(dp) :: params, lr
  params = 8.03e9_dp
  lr = 3.0e-4_dp
  print '(A, I0)', "Layers: ", layers
  print '(A, F6.2, A)', "FP16 size: ", params * 2 / 1e9_dp, " GB"
end program variables
Chapter 2

Control flow

do loops and if blocks end with end do and end if. select case handles multi-way choices.

control.f90
program control
  implicit none
  integer :: epoch, bits
  do epoch = 1, 3
    print *, "epoch", epoch
  end do
  bits = 8
  select case (bits)
  case (32);      print *, "FP32"
  case (16);      print *, "FP16"
  case (8);       print *, "FP8"
  case default;   print *, "other"
  end select
end program control
Chapter 3

Arrays: Fortran’s superpower

Arrays are first-class. You can add, multiply and slice whole arrays, and functions like sum, maxval and matmul are built in. Arrays start at index 1 by default.

arrays.f90
program arrays
  implicit none
  real :: x(5) = [1., 2., 3., 4., 5.]
  real :: a(2,3), b(3,2), c(2,2)
  print *, x * 2 + 1           ! element-wise
  print *, sum(x), maxval(x)
  print *, x(2:4)              ! slice
  a = reshape([1.,2.,3.,4.,5.,6.], [2,3])
  b = transpose(a)
  c = matmul(a, b)
  print *, c
end program arrays
Chapter 4

Functions, subroutines and modules

Modules group procedures and data. intent(in) and intent(out) document how arguments are used and help the compiler optimise.

procedures.f90
module model_math
  implicit none
contains
  pure function params(layers, width) result(p)
    integer, intent(in) :: layers, width
    integer(8) :: p
    p = 12_8 * layers * int(width, 8)**2
  end function params

  subroutine relu(x)
    real, intent(inout) :: x(:)
    where (x < 0) x = 0
  end subroutine relu
end module model_math

program main
  use model_math
  real :: v(4) = [-1., 2., -3., 4.]
  print *, params(32, 4096)
  call relu(v); print *, v
end program main
Chapter 5

Parallel loops

do concurrent tells the compiler iterations are independent. With OpenMP (-fopenmp) or nvfortran (-stdpar=gpu) the same loop can run on many cores or a GPU.

saxpy.f90
program saxpy
  implicit none
  integer, parameter :: n = 10000000
  real, allocatable :: x(:), y(:)
  integer :: i
  allocate(x(n), y(n))
  x = 1.0; y = 2.0
  do concurrent (i = 1:n)
    y(i) = 2.5 * x(i) + y(i)
  end do
  print *, y(1), y(n)          ! 4.5 4.5
end program saxpy
! gfortran -O3 -fopenmp saxpy.f90     |  nvfortran -stdpar=gpu saxpy.f90
Part II · AI with Fortran

AI with Fortran

Fortran's biggest AI role is hidden: BLAS and LAPACK, which do matrix maths for NumPy, SciPy and many ML libraries, began in Fortran. Scientists now combine Fortran simulations with neural networks, for example ML-based physics in weather and climate models, using libraries like neural-fortran or calling PyTorch models through FTorch.

The essential libraries

neural-fortranTrain and run neural networks in Fortran.
FTorchCall PyTorch models from Fortran.
BLAS / LAPACKThe linear algebra under NumPy.
f2pyCall Fortran from Python (part of NumPy).

Gradient descent from scratch

Fit y = 3x + 0.5 with whole-array operations, no inner loops needed.

gradient.f90
program gradient
  implicit none
  integer, parameter :: n = 100
  real :: x(n), y(n), err(n), w = 0, b = 0, lr = 0.1
  integer :: i, step
  x = [(-1.0 + 2.0 * (i - 1) / (n - 1), i = 1, n)]
  y = 3 * x + 0.5
  do step = 1, 500
    err = w * x + b - y
    w = w - lr * 2 * sum(err * x) / n
    b = b - lr * 2 * sum(err) / n
  end do
  print '(A, F5.2, A, F5.2)', "w = ", w, "  b = ", b
end program gradient
Part III · Build an AI agent

Fortran as an AI agent tool

The practical way to put Fortran in an agent is to wrap a fast Fortran routine with f2py and let a Python agent call it as a tool, which is exactly how scientific codes are joined to LLM tools today.

Your goal→Model plans→Tool call→Your code runs the tool→Result back to model→Final answer
agent.py
# physics.f90 -> python -m numpy.f2py -c physics.f90 -m physics
#   subroutine projectile(v, angle, dist)
#     real(8), intent(in) :: v, angle
#     real(8), intent(out) :: dist
#     dist = v**2 * sin(2 * angle * 3.141592653589793d0 / 180) / 9.81d0
#   end subroutine
import json, physics
from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
tools = [{"type": "function", "function": {"name": "projectile", "description": "Range in metres of a projectile",
    "parameters": {"type": "object", "properties": {"v": {"type": "number"}, "angle": {"type": "number"}},
                   "required": ["v", "angle"]}}}]
messages = [{"role": "user", "content": "How far does a ball launched at 20 m/s and 45 degrees travel?"}]
for _ in range(5):
    msg = client.chat.completions.create(model="llama3.1", messages=messages, tools=tools).choices[0].message
    messages.append(msg)
    if not msg.tool_calls:
        print(msg.content); break
    for c in msg.tool_calls:
        dist = physics.projectile(**json.loads(c.function.arguments))
        messages.append({"role": "tool", "tool_call_id": c.id, "content": f"{dist:.2f} m"})

f2py turns the intent(out) argument into a return value, so the call returns the distance directly.

Run it locallyInstall Ollama, run ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.
Part IV · Your path

Fortran learning roadmap

Tick items off as you go. Your progress is saved in this browser.

Beginner

Intermediate

Advanced

Part IV · Your path

Projects to build

Heat equationSimulate heat spreading along a rod.
Matrix benchmarkCompare loops, matmul and BLAS.
Python bridgeSpeed up a NumPy script with f2py.
Reference

Fortran cheat sheet

TaskSyntax
Declareinteger :: n
Constantreal, parameter :: pi = 3.14159
Loopdo i = 1, n ... end do
Array opy = 2*x + 1
Slicex(2:5)
Matmulc = matmul(a, b)
Reference

Common mistakes

  • Forgetting implicit none makes variables starting with i–n integers automatically.
  • Arrays are 1-indexed and stored column-major (the opposite of C and NumPy's default).
  • Old fixed-form code (.f, columns 7–72) looks very different from modern free-form (.f90).
Reference

Where to go next

On TensorCore.si: C volume, Julia volume.

Keyboard: [ previous language · ] next language · / search the library