Declaring and Using Subroutines in Fortran

In Fortran, subroutines are a fundamental way to modularize code. They allow programmers to encapsulate specific tasks into reusable blocks, improving readability, maintainability, and scalability of programs. Unlike functions, subroutines perform tasks but do not return values directly; instead, they may modify their arguments or produce output via other means.

This post provides a complete guide to declaring, using, and managing subroutines, including examples, passing arguments, intent specification, modular programming, and best practices.

1. Introduction to Subroutines

A subroutine is a named block of code designed to perform a specific task. Subroutines:

  • Improve code reusability
  • Enhance readability by reducing repeated code
  • Can modify arguments or perform output operations
  • Are invoked using the call statement

Basic Syntax

subroutine subroutine_name(arguments)
! Declaration of arguments
! Body of subroutine
end subroutine subroutine_name

Invoking a Subroutine

call subroutine_name(arguments)

2. Simple Example: Greeting Subroutine

Example 1: Subroutine with Character Input

program main
call greet("Fortran")
end program main subroutine greet(name)
character(len=*), intent(in) :: name
print *, "Hello,", name
end subroutine greet

Explanation:

  • greet is a subroutine that prints a greeting
  • intent(in) specifies that the argument is input only
  • call greet("Fortran") invokes the subroutine from the main program

3. Passing Arguments

Subroutines can take multiple arguments, including integers, real numbers, logicals, and arrays.

Example 2: Sum of Two Numbers

program main
integer :: a, b, result
a = 5
b = 7
call add_numbers(a, b, result)
print *, "Sum:", result
end program main subroutine add_numbers(x, y, sum)
integer, intent(in) :: x, y
integer, intent(out) :: sum
sum = x + y
end subroutine add_numbers

Explanation:

  • x and y are input arguments
  • sum is an output argument
  • The subroutine calculates the sum and returns it via sum

4. Using Intent Attributes

The intent attribute clarifies how arguments are used:

  • intent(in) – Read-only input
  • intent(out) – Output from subroutine
  • intent(inout) – Both input and output

Example 3: Incrementing a Number

program main
integer :: value
value = 10
call increment(value)
print *, "Incremented value:", value
end program main subroutine increment(number)
integer, intent(inout) :: number
number = number + 1
end subroutine increment

Explanation:

  • intent(inout) allows modification of the argument
  • The main program sees the updated value after the subroutine call

5. Subroutines with Arrays

Subroutines can process arrays to perform element-wise operations or aggregation.

Example 4: Doubling Array Elements

program main
integer :: arr(5)
integer :: i
arr = (/1,2,3,4,5/)
call double_array(arr)
print *, "Doubled array:"
do i = 1, 5
    print *, arr(i)
end do
end program main subroutine double_array(array)
integer, intent(inout) :: array(:)
integer :: i
do i = 1, size(array)
    array(i) = array(i) * 2
end do
end subroutine double_array

Explanation:

  • array(:) indicates a one-dimensional array of arbitrary size
  • Each element is doubled using a loop
  • Shows array processing inside subroutines

6. Modular Programming with Subroutines

Subroutines can be grouped into modules, which enhances organization and allows reuse across multiple programs.

Example 5: Using a Module

module math_utils
contains
subroutine square(x, result)
    real, intent(in) :: x
    real, intent(out) :: result
    result = x**2
end subroutine square
end module math_utils program main
use math_utils
real :: num, sq
num = 3.0
call square(num, sq)
print *, "Square of", num, "is", sq
end program main

Explanation:

  • math_utils module contains reusable subroutine square
  • Main program uses use math_utils to access the subroutine
  • Modular design improves maintainability

7. Subroutines with Optional Arguments

Fortran allows optional arguments in subroutines, which can be omitted when calling.

Example 6: Optional Greeting

program main
call greet("Fortran")
call greet("World", "Good morning")
end program main subroutine greet(name, salutation)
character(len=*), intent(in) :: name
character(len=*), intent(in), optional :: salutation
if (present(salutation)) then
    print *, salutation, ",", name
else
    print *, "Hello,", name
end if
end subroutine greet

Explanation:

  • optional allows subroutine flexibility
  • present checks if the argument was provided

8. Keyword Arguments in Subroutines

Subroutines support keyword arguments, improving readability and allowing arguments in any order.

Example 7: Keyword Arguments

program main
call display_values(b=20, a=10)
end program main subroutine display_values(a, b)
integer, intent(in) :: a, b
print *, "a =", a, ", b =", b
end subroutine display_values

Explanation:

  • Call uses keywords to specify arguments
  • Enhances clarity and reduces errors in long argument lists

9. Subroutines Calling Other Subroutines

Subroutines can call other subroutines to create structured and hierarchical code.

Example 8: Nested Subroutine Calls

program main
call main_task()
end program main subroutine main_task()
print *, "Starting main task..."
call subtask()
end subroutine main_task subroutine subtask()
print *, "Executing subtask..."
end subroutine subtask

Explanation:

  • main_task calls subtask
  • Demonstrates modular, hierarchical design

10. Best Practices for Subroutines

  1. Use meaningful names – Describe the task clearly
  2. Specify intent – Avoid accidental modification of inputs
  3. Keep subroutines focused – Each subroutine should perform one task
  4. Use modules for reusability – Organize subroutines for multiple programs
  5. Document inputs and outputs – Clarifies usage for others
  6. Use optional and keyword arguments – Increases flexibility
  7. Avoid global variables – Pass data via arguments instead

11. Practical Applications

Subroutines are essential for:

  • Mathematical computations – Sum, product, matrix operations
  • Data processing – Array transformations, filtering
  • Simulation control – Modular tasks for physics or engineering simulations
  • User interface tasks – Printing messages or formatted outputs
  • Modular programming – Grouping related routines into modules

12. Advanced Example: Temperature Conversion

program temperature_conversion
real :: celsius, fahrenheit
celsius = 25.0
call convert_to_fahrenheit(celsius, fahrenheit)
print *, celsius, "Celsius is", fahrenheit, "Fahrenheit"
end program temperature_conversion subroutine convert_to_fahrenheit(c, f)
real, intent(in) :: c
real, intent(out) :: f
f = c * 9.0 / 5.0 + 32.0
end subroutine convert_to_fahrenheit

Explanation:

  • Subroutine performs temperature conversion
  • Main program receives converted value through output argument

13. Subroutines with Multiple Arrays

Subroutines can manipulate multiple arrays for matrix or vector operations.

Example 9: Element-wise Array Sum

program main
integer :: A(5), B(5), C(5)
integer :: i
A = (/1,2,3,4,5/)
B = (/5,4,3,2,1/)
call sum_arrays(A, B, C)
print *, "Sum of arrays:"
do i = 1, 5
    print *, C(i)
end do
end program main subroutine sum_arrays(arr1, arr2, result)
integer, intent(in) :: arr1(:), arr2(:)
integer, intent(out) :: result(size(arr1))
integer :: i
do i = 1, size(arr1)
    result(i) = arr1(i) + arr2(i)
end do
end subroutine sum_arrays

Explanation:

  • Demonstrates array manipulation in subroutines
  • Subroutine handles element-wise computation for input arrays

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *