Most programming languages allow you to collect commonly-used code into procedures that can be reused by calling them from other sections of code.
Fortran has two forms of procedure:
call statementBoth subroutines and functions have access to variables in the parent scope by argument association;
unless the VALUE attribute is specified, this is similar to call by reference.
The subroutine input arguments, known as dummy arguments are specified in parentheses after the subroutine name; the dummy argument types and attributes are declared within the body of the subroutine just like local variables.
Example:
! Print matrix A to screen
subroutine print_matrix(n,m,A)
  implicit none
  integer, intent(in) :: n
  integer, intent(in) :: m
  real, intent(in) :: A(n,m)
  integer :: i
  do i=1,n
    print *,A(i,1:m)
  end do
end subroutine print_matrix
Note the additional intent attribute when declaring the dummy arguments; this optional attribute signifies to the compiler whether the argument
is ‘read-only’ (intent(in)) ‘write-only’ (intent(out)) or ‘read-write’ (intent(inout)) within the procedure.
In this example, the subroutine does not modify its arguments, hence all arguments are intent(in).
Tip: It is good practice to always specify the intent attribute for
dummy arguments; this allows the compiler to check for unintentional errors and provides self-documentation.
We can call this subroutine from a program using a call statement:
program call_sub
  implicit none
  
  real :: mat(10,20)
  
  mat(:,:) = 0.0
  call print_matrix(10,20,mat)
end program call_sub
Note: This example uses a so-called explicit-shape array argument since we have passed additional variables to describe
the dimensions of the array A; this will not be necessary if we place our subroutine in a module as described later.
! L2 Norm of a vector
function vector_norm(n,vec) result(norm)
  implicit none
  integer, intent(in) :: n
  real, intent(in) :: vec(n)
  real :: norm
  norm = sqrt(sum(vec**2))
end function vector_norm
Tip: In production code, the intrinsic function norm2 should be used.
To execute this function:
program run_fcn
  implicit none
  real :: v(9)
  real :: vector_norm
  
  v(:) = 9
  print *, 'Vector norm = ',vector_norm(9,v)
end program run_fcn
Tip: It is good programming practice for functions not to modify their arguments - i.e. all function arguments should be intent(in) - such
functions are known as pure functions. Use subroutines if your procedure needs to modify its arguments.
Fortran modules contain definitions that are made accessible to programs, procedures and other modules through the use statement.
They can contain data objects, type definitions, procedures and interfaces.
Tip: It is recommended to always place functions and subroutines within modules.
Example:
module my_mod 
  implicit none
  private                          ! All entities are module-private by default
  public public_var, print_matrix  ! Explicitly export public entities
  real, parameter :: public_var = 2
  integer :: private_var
  contains
    
    ! Print matrix A to screen
    subroutine print_matrix(A)
      real, intent(in) :: A(:,:)  ! An assumed-shape dummy argument
      integer :: i
      do i=1,size(A,1)
        print *,A(i,:)
      end do
    end subroutine print_matrix
end module my_mod
Note: Compare this print_matrix subroutine with that written outside of a module;
we no longer have to explicitly pass the matrix dimensions and can instead take
advantage of assumed-shape arguments since the module will generate the required
explicit interface for us. This results in a much simpler subroutine interface.
To use the module within a program:
program use_mod
  use my_mod
  implicit none
  real :: mat(10,10)
  mat(:,:) = public_var
  call print_matrix(mat)
end program use_mod
Example: explicit import list
  use my_mod, only: public_var
Example: aliased import
  use my_mod, only: printMat=>print_matrix
Note: Each module should be written in a separate .f90 source file. Modules need to be compiled prior to any program units that use them.