Program to numerically solve 3 ODE's

One resource is the fortran-lang tutorial: Organising code structure - Fortran Programming Language

If available to you, I would recommend the latest edition of “Modern Fortran explained” by Metcalf, Reid & Cohen, chapter 5 - Program units and procedures.

A second option would be “Guide to Fortran 2008 Programming” by Walter Brainerd: Guide to Fortran 2008 Programming | SpringerLink. Perhaps you can access the digital version with your university account.

The keyword contains is simply used to collect internal subprograms (subroutines and functions) in a main program or module:

program main
  implicit none
  
  ! ... declarations ...

  ! ... main program unit commands ...

contains

  ! ... internal subprograms ...

  subroutine runge(...)

  end subroutine

  function dydt(t,y)

  end function

end program

Instead of placing the procedures in the main program, you can place them in a module:

module flow_solver_routines
  implicit none

  ! ... declarations ...

contains

  ! ... internal subprograms ...

  subroutine runge(...)

  end subroutine

  function dydt(t,y)

  end function

end module  

that you then use in the main program as follows:

program main
  use flow_solver_routines, only: runge, dydt
  implicit none

  ! ...

  call runge(dydt,tstart,tend,y)

end program

In fact even subroutines and functions can have procedures nested in their own contains section.

On the other hand, your old program used so-called external subprograms, i.e. subprograms that are not located within a program unit or module. External procedures were the norm in F77, but since F90 modules are the preferred approach to organize your (sub)programs.

When using internal subprograms the compiler can check you are calling the function or subroutine correctly since the interface is visible. Internal subprograms also have access to the objects in their host program, which can be useful for many things.

2 Likes