.. admonition:: Section Overview :class: Overview * **Tutorial:** 45 min **Objectives:** #. Learn basic modern fortran syntax and program structure. ============================= Fortran Programming Basics ============================= .. contents:: :local: :depth: 2 What we cover ------------------- - Fortran Program basics - Compile and run parallel Fortran code on Gadi - Live demo on profiling Fortran code with Gadi-supported tools Prerequisites and setup ======================= - Comfortable with the command line - Fortran compilers on Gadi: - GNU Fortran: ``gfortran`` through module ``gcc`` - Intel Fortran Classic: ``ifort`` through old ``intel-compiler/*`` modules - Intel Fortran ``ifx`` through intel-compiler-llvm/* modules - Parallel compiler wrapper ``mpif90`` through ``openmpi`` or ``intel-mpi`` module. Check installation:: gfortran --version # or ifort -V # or ifx -V Compile and run --------------- Minimal commands:: gfortran -Wall -Wextra -O2 hello.f90 -o hello ./hello On systems with multiple compilers, prefer explicit commands and flags. Use the ``.f90`` extension for all modern Fortran source files (90/95/2003/2008). Hello, Fortran ============== Create ``hello.f90``: .. code-block:: fortran program hello implicit none print *, "Hello, Fortran 95!" end program hello Key idea: ``implicit none`` disables implicit typing and catches many bugs at compile time. Without it, the default sets undeclared variables to type ``real`` or ``integer`` based on their names. Language basics =============== Source form ----------- - Free form source (``.f90``) is standard in F95. - Comments start with ``!``. - Indentation is for humans, not the compiler, but keep it consistent. Types and declarations ---------------------- Built-in numeric and logical types: .. code-block:: fortran integer :: i, n real :: x, y ! single precision real(kind=8) :: z ! double precision real(kind=16) :: w ! long double precision as in C logical :: convergence character(len=20) :: name Use ``parameter`` for constants (much like ``const`` in C/C++): .. code-block:: fortran integer, parameter :: wp = selected_real_kind(15,99) ! define work precision kind that has guaranteed 15 decimal digits with exponent range up to 99 real(kind=wp), parameter :: pi pi = 3.1415926535_wp ! _wp enforces the wp kind Operators (overview) -------------------- - Arithmetic: ``+ - * / **`` - Relational: ``== /= < <= > >=`` - Logical: ``.and. .or. .not.`` Input and output ---------------- List-directed I/O (simple and flexible): .. code-block:: fortran integer :: n print *, "Enter an integer:" read *, n print *, "You entered:", n Formatted I/O (controlled layout): .. code-block:: fortran real :: x x = 12.345 print '(A, F8.3)', "Value = ", x ! A for string, F8.3 for field width 8 with 3 decimals Control flow ============ If and case ----------- .. code-block:: fortran integer :: n read *, n if (n < 0) then print *, "negative" else if (n == 0) then print *, "zero" else print *, "positive" end if .. code-block:: fortran character(len=1) :: c read *, c select case (c) case ('y','Y') print *, "yes" case ('n','N') print *, "no" case default print *, "unknown" end select Loops ----- .. code-block:: fortran integer :: i, sum sum = 0 do i = 1, 10 sum = sum + i end do print *, "Sum 1..10 =", sum Use ``exit`` to break, ``cycle`` to continue: .. code-block:: fortran integer :: i do i = 1, 1000 if (i*i > 200) exit if (mod(i, 2) == 0) cycle print *, i end do 1D arrays and array features ========================= Declaring arrays ---------------- .. code-block:: fortran real :: a(5) ! fixed-size integer :: m, n parameter (m=3, n=4) real :: b(m, n) ! 2D array, column-major Array constructors and assignments ---------------------------------- .. code-block:: fortran real :: x(5) x = (/ 1.0, 2.0, 3.0, 4.0, 5.0 /) ! x = [1.0, 2.0, 3.0, 4.0, 5.0] in fortran 2003. x = x * 2.0 ! whole-array operation print *, x (/ ... /) and [ ... ] only create 1D arrays. Multidimensional Arrays (Matrices) ================================== Fortran is famously optimised for linear algebra and scientific computing. Unlike C or Python (where multidimensional arrays are often lists of lists), Fortran arrays are first-class citizens with built-in support for matrix arithmetic, slicing, and memory management. Declaration and Rank -------------------- In Fortran, the number of dimensions is called the **Rank**. Arrays can have up to 15 dimensions (in modern standards), though Rank-2 (Matrices) and Rank-3 (Cubes) are the most common. **Basic Syntax:** .. code-block:: fortran ! Syntax: type :: variable_name(dim1, dim2, ...) program matrix_demo implicit none ! A 3x3 Integer Matrix (Rank 2) integer :: matrix_A(3, 3) ! A 10x10x10 Real Cube (Rank 3) real :: tensor_B(10, 10, 10) ! Alternative declaration style (using dimension attribute) real, dimension(5, 5) :: matrix_C end program matrix_demo Column-Major Order (Crucial!) ----------------------------- .. warning:: **Fortran is Column-Major.** C and C++ are Row-Major. This means that in memory, columns are stored contiguously. If you have a matrix ``A(2,2)``: 1. ``A(1,1)`` is stored first. 2. ``A(2,1)`` is stored second (Next row, same column). 3. ``A(1,2)`` is stored third. **Performance Tip:** When looping over arrays, **always** iterate over the leftmost index (rows) first (innermost loop) and the rightmost index (columns) last (outermost loop). .. code-block:: fortran ! FAST (Correct Cache Usage) do j = 1, 1000 ! Columns (Outer) do i = 1, 1000 ! Rows (Inner - changing fastest) A(i, j) = 0.0 end do end do ! SLOW (Cache Misses) do i = 1, 1000 do j = 1, 1000 A(i, j) = 0.0 end do end do Initialisation -------------- Because array constructors ``[...]`` create 1D arrays, you often use the intrinsic ``reshape`` function to mold data into a matrix. .. code-block:: fortran integer :: A(2, 3) ! 1. Create a list of 6 numbers ! 2. Reshape it into 2 Rows and 3 Columns ! Note: Fills column 1, then column 2... A = reshape( [1, 2, 3, 4, 5, 6], shape=[2,3] ) ! Result: ! 1 3 5 ! 2 4 6 Accessing Elements and Slicing ------------------------------ Fortran indices start at **1** by default. .. code-block:: fortran real :: A(4, 4) ! Access single element (Row 2, Col 3) print *, A(2, 3) **Array Slicing (Sections)** You can access whole rows, columns, or sub-matrices using the colon ``:`` operator. .. code-block:: fortran ! Whole Row 2 print *, A(2, :) ! Whole Column 3 print *, A(:, 3) ! Sub-matrix (Top-left 2x2 corner) print *, A(1:2, 1:2) ! Stride: Rows 1 to 4, step 2 (Rows 1 and 3) print *, A(1:4:2, :) Matrix Arithmetic vs. Element-wise ---------------------------------- Standard operators in Fortran are **Element-wise**. For true linear algebra, you must use intrinsic functions. .. code-block:: fortran real :: A(2,2), B(2,2), C(2,2) ! 1. Element-wise Multiplication ! C(i,j) = A(i,j) * B(i,j) C = A * B ! 2. Matrix Multiplication (Linear Algebra) ! Row x Column dot products C = matmul(A, B) ! 3. Transpose (Swap rows and cols) C = transpose(A) ! 4. Summation print *, sum(A) ! Sum of all elements print *, sum(A, dim=1) ! Sum down rows (returns a row vector) print *, sum(A, dim=2) ! Sum across columns (returns a column vector) Dynamic Allocation ------------------ If you do not know the matrix size at compile time, use ``allocatable``. .. code-block:: fortran program dynamic_matrix implicit none integer, allocatable :: matrix(:, :) ! Rank 2, unknown size integer :: rows, cols, ierr print *, "Enter dimensions:" read *, rows, cols ! Allocate memory allocate( matrix(rows, cols) ) ! Use the matrix matrix = 0 print *, "Matrix size:", size(matrix) ! Free memory (Optional: happens automatically at end of program) deallocate(matrix) end program dynamic_matrix Summary Table ------------- +------------------+------------------------------+---------------------------+ | Operation | Fortran Syntax | Meaning | +==================+==============================+===========================+ | Indexing | ``A(i, j)`` | Row ``i``, Col ``j`` | +------------------+------------------------------+---------------------------+ | Whole Row | ``A(i, :)`` | All columns in row ``i`` | +------------------+------------------------------+---------------------------+ | Whole Col | ``A(:, j)`` | All rows in col ``j`` | +------------------+------------------------------+---------------------------+ | Multiplication | ``A * B`` | Element-wise | +------------------+------------------------------+---------------------------+ | Dot Product | ``matmul(A, B)`` | Matrix Math | +------------------+------------------------------+---------------------------+ Intrinsic procedures (basics) ------------------------------- .. code-block:: fortran real :: a(4), s a = [ 1.0, -2.0, 3.0, -4.0 ] s = sum(a) ! -2.0 print *, minval(a), maxval(a), sum(abs(a)) Fortran has many Intrinsic procesures. The most impressive ones are for array operations, and linear algebra. Saving you from writing big loops. The most powerful concept in Fortran intrinsics is that most mathematical functions are **Elemental**. This means they operate on a single number **OR** element-wise on an entire array. **The C Way:** .. code-block:: c // C requires a loop for(int i=0; i