4.1.4. Program Structure¶
4.1.4.1. Modular Programming¶
4.1.4.1.1. Modules¶
Breaks up a task into small steps
Prevents code having to be re-written, if we are just using the same again in another program
Modules usually contain variables, parameters, functions and subroutines that are for the same purpose, e.g. a module for integration might contain the midpoint rule, the trapezoid rule and simpson’s rule. This helps to add meaning to what is being programmed.
4.1.4.1.2. Programs¶
Usually used for testing the functions and subroutines of a module
Programs are often used for input-output operations, e.g. read/write to/from files or screen
The executable file (.exe) is usually given the same name as the program
4.1.4.1.3. Functions¶
Functions return only one value
Functions can be passed as values to other functions or subroutines
4.1.4.1.4. Subroutines¶
Allow multiple returned values by modifying input arguments
Can’t be passed as arguments to other functions or subroutines (although I haven’t tried this - I’m not sure what it would mean)
4.1.4.1.5. Steps¶
There might be several steps as the program goes from simple to complex:
For internal subroutines/functions (for simple programs):
Write a subroutine/function under contains as part of the main program.
Use the internal subroutine/function e.g.
To use a function:
y = fun_quadratic(a, b)
To use a subroutine:
call sub_euler(x, y, z)
For external subroutines/functions (for simple programs):
Write an external subroutine/function under end program in the same file or in a different file to the main program (perhaps as the first step before writing a module)
Declare a subroutine using the use statement within the main program, e.g.
use sub_euler
Declare a function using the external attribute in the declaration in the main program, e.g.
real(kind=8), external :: fun_quadratic
Use the subroutine/function by name as if it were internal
To modularise a subroutine/function (for complex programs - e.g. to collect similar parts):
Write a module which contains the subroutine/function
Declare the subroutine/function’s use in the main program, e.g.
use sub_euler, only: first_order
Use the subroutine/function by name as if it were internal
Pass a function as an argument to a subroutine - this may allow the subroutine to be independent of the function passed to it, e.g. integration subroutines apply to all kinds of functions, e.g.
Use
solve(fun_specific, x, y)
in the main program (i.e. send a specific function such as a quadratic)The subroutine the function is passed could declare a more general argument list, e.g.
subroutine solve(fun_general, x, y)
(i.e. it can recieve any kind of function)
real(kind=8), external :: fun_general
(to declare that the function is external)
Probably can’t pass subroutines as arguments, as they usually aren’t single values.
4.1.4.2. Program¶
Code |
Meaning |
---|---|
program pro_integrate
use mod_euler, lname => mod_1
use mod_runga_kutta, only: fun_quadratic, fun_quartic
implicit none
interface
real function fun_cubic(a, b, c)
real, intent(in) :: a, b, c
end function fun_cubic
end interface
! declaration and initialisation
! program body statements
stop 'message'
contains
! internal subroutines or functions
end program pro_integrate
|
Program Structure
|
4.1.4.2.1. Use Explicit Imports, Not Implicit Imports¶
Avoid:
use mod_integrator
Instead say what you are using:
use mod_integrator, only: midpoint
4.1.4.3. Module¶
Code |
Meaning |
---|---|
module mod_runge_kutta
use mod_quadrature
implicit none
private
public :: fun_quadratic, fun_quartic
interface
real function fun_cubic(a, b, c)
real, intent(in) :: a, b, c
end function fun_cubic
end interface
! declaration and initialisation
real(kind=8) :: pi
contains
! internal subroutines or functions
end module mod_runge_kutta
|
Module Structure - Put external subroutines and functions (i.e. external to program) within modules. Then call them via
|
|
Module Variable - Declare a module variable in a module and initialise it in a subroutine. This allows the program to initialise the module variable only once. Modules that use a module variable must save the value from the initialisation (or it may revert to the default value, whatever that is).
|
4.1.4.4. Subroutine¶
Code |
Meaning |
---|---|
subroutine sub_momentum_equation(nx, x, u, error, nu)
implicit none
integer, intent(in) :: nx
real(kind=8), allocatable, dimension(:) :: x
real(kind=8), intent(out) :: u
integer, intent(inout) :: error
real(kind=8), optional :: nu
if(present(nu))
! block
return
else
! block
return
end if
end subroutine sub_momentum_equation
|
Subroutine Structure - Subroutines differ from functions in that they are allowed to have more than one output. It does this by modifying it’s input values (it doesn’t actually return a new value). Subroutines may also have no output.
|
4.1.4.5. Function¶
Code |
Meaning |
---|---|
real(kind=8) function fun_quadratic(a, b, c, x)
implicit none
real(kind=8), intent(in) :: a, b, c, x
if(c .ne. 0) then
fun_quadratic = a*x**2 + b*x + c
return
else
fun_quadratic = a*x**2 + b*x
return
end if
end function fun_quadratic
|
Function Structure 1 - Functions differ from subroutines, in that they can only have one output. Functions return a new value, not among the input arguments.
|
function fun_quadratic(a, b, c, x)
implicit none
real(kind=8), intent(in) :: a, b, c, x
real(kind=8) :: fun_quadratic
! block
end function fun_quadratic
|
Function Structure 2: Notice that the output variable is declared with other variables in this form. Intent is implicit.
|
recursive function fun_recursion(a, b, c, x) result(y)
implicit none
real(kind=8), intent(in) :: a, b, c, x
real(kind=8) :: y
! block
end function fun_quadratic
|
Function Structure 3: “Recursive Function”
|
integer :: fun_increment
integer :: x
fun_increment(x) = x + 1
|
Function Structure 4: “Statement Function”
|
4.1.4.6. Interface¶
I haven’t used interfaces, but here are some definitions.
Code |
Meaning |
---|---|
interface
! external subroutine or functions
end interface
|
Interface Structure 1 - These are found where a program or a module must use external subroutines or functions (similar to |
interface
! external subroutines or functions
module procedure list
end interface
|
Interface Structure 2
|
interface operator op
! external subroutines or functions
module procedure list
end interface
|
Interface Structure 3
|
interface assignment (=)
! external subroutines or functions
module procedure list
end interface
|
Interface Structure 4
|