! 4. Procedures.					   File: procedure4.f90
!------------------------------------------------------------------------------!

PROGRAM procedures
	IMPLICIT NONE

	! This program illustrates how programs can be modularised by 
	! the use of PROCEDURES: FUNCTIONS (INTRINSIC and EXTERNAL) 
	! and SUBROUTINES

	! variable declarations
	REAL :: x,y_1,y_2,y_3,y_4,phi
	REAL, PARAMETER :: pi=3.1415926
	REAL, INTRINSIC :: CMPLX, SIN, COS
	REAL, EXTERNAL :: sinc

	! example of a subroutine
	CALL welcome

	! inputs using a subroutine
	CALL input(x)
	
	! example of intrinsic functions (ABS,SQRT,SIN):
	y_1 = ABS(x)
	y_2 = SQRT(y_1)
	y_3 = SIN(y_2*x/y_1)

	! example of an external function (sinc):
	y_4 = 2.0*sinc(pi/4.0) + y_1

	! example of a subroutine:
	CALL potential(1.0,2.5,phi)

	! output using a subroutine
	CALL output(y_3,y_4,phi)

END PROGRAM procedures


SUBROUTINE welcome
	IMPLICIT NONE

	PRINT *,'Welcome to this introduction to procedures'
	PRINT *
	PRINT *,'Observe how simple the main program unit appears'
	PRINT *

END SUBROUTINE welcome


REAL FUNCTION sinc(x)
	IMPLICIT NONE

	! function to calculate the sinc function: (sin(x)/x)**2

	! dummy argument declaration
	REAL, INTENT(IN) :: x

	sinc = (SIN(x)/x)**2

END FUNCTION sinc


SUBROUTINE input(x)
	IMPLICIT NONE

	! subroutine to read in input variables

	! dummy argument declaration
	REAL, INTENT(OUT) :: x

	PRINT *, 'Specify a value for x'
	READ *,x

END SUBROUTINE input


SUBROUTINE potential(z,r,pot)
	IMPLICIT NONE

	! this subroutine calculates the potential of a point charge 
	! with charge ze at a distance r (phi = ze/(4 pi eps r))
	! dummy argument declarations
	REAL, INTENT(IN) :: z,r
	REAL, INTENT(OUT) :: pot

	! local variable declarations
	REAL, PARAMETER :: e=1.6022e-19,pi=3.1415926,eps=8.8542e-12
	REAL, PARAMETER :: constant=e/(4.0*pi*eps)

	! calculate the potential
	pot = constant*z/r

END SUBROUTINE potential


SUBROUTINE output(x_1,x_2,x_3)
	IMPLICIT NONE

	! this subroutine prints out the values of x_1,x_2,x_3 

	! dummy argument declarations
	REAL, INTENT(IN) :: x_1,x_2,x_3

	! outputs
	PRINT *,'The first value is ',x_1
	PRINT *
	PRINT *,'The second value is ',x_2
	PRINT *
	PRINT *,'The third value is ',x_3

END SUBROUTINE output


!! 1.	Henceforth we must think "modular" when designing our Fortran programs.
!!	A top-down approach to program construction has been suggested in 
!!	which the program is broken up in successive stages, using pseudocode,
!!	until we reach a point where the final Fortran code is easily written.
!!	As an aid to this, most modern programming languages make provision 
!!	for PROCEDURES/SUBPROGRAMS/MODULES. They allow us to organize programs
!!	in clear, logical, hierarchic fashion.
!!
!!	THE USE OF PROCEDURES IS FUNDAMENTAL TO GOOD PROGRAMMING PRACTICE!!!
!!	MAKE FULL USE OF THEIR POSSIBILITIES.
!!
!!	They have the advantage of (i) allowing one procedure to be written 
!!	independently from the rest of the program (ii) being easier to 
!!	debug since you are working with smaller units (iii) being used
!!	in other programs without rewriting or retesting (iv) being used 
!!	several times within the same program without repetition (v) making
!!	for more easily read code (vi ) producing programs which are shorter 
!!	and therefore simpler.

!! 2.	Program Units.
!!
!!	All of our programs to date have been monolithic, consisting of one body
!!	of code. Henceforth we will break programs into PROGRAM UNITS. All 
!!	programs must contain a MAIN PROGRAM UNIT. These have the structure:
!!
!!		PROGRAM name
!!			...
!!			specification statements	(e.g. declarations)
!!			...
!!			executable statements
!!			...
!!		END PROGRAM name
!!
!!	In the above example the MAIN PROGRAM is called 'procedures'. The
!!	previous examples have all contained a MAIN PROGRAM and nothing more.
!! 
!!	The intrinsic functions ABS,SQRT,SIN are used in the above program.
!!	These are part of the Fortran language. See next section for a 
!! 	selection of the most commonly encountered intrinsic functions. 
!!	A full set is given as an appendix in the textbook. 
!!
!!	In addition, programs may also have zero or more SUBPROGRAM UNITS. 
!!	These may be:
!!
!!	(a) FUNCTION SUBPROGRAMS.  Fortran permits the user to construct 
!!	his own EXTERNAL functions (see 'sinc' above and session: function6.f90)
!!
!!	(b) SUBROUTINES. 'welcome, input, potential and output' are all
!!	subroutine subprograms. See also session: subroutine7.f90. 
!!
!!	The structure of each of these UNITS is essentially the same except
!!	for their first line. It is an important concept that each program
!!	unit is completely independent of any other; they are unaware of each 
!!	other. The only link between a "calling program" and a subprogram is 
!!	through the name of the subprogram and the arguments and/or function
!!	value. This is called the INTERFACE
!!
!!	(c) MODULES. We defer discussion of these until session: modules8.f90
!!
!!	It is good programming practice to keep the main program unit simple
!!	and relatively short. Any detailed calculation should be relegated to 
!!	a subprogram. Observe, in the above example, how the calculation of 
!!	the potential and the output are replaced in the main program unit by 
!!	two CALL statements.
!!
!!	All UNITS whether they be FUNCTION SUBPROGRAMS, SUBROUTINES or a MAIN 
!!	PROGRAM require ALL variables/parameters to be declared, e.g. if an
!!	INTEGER variable is passed to a procedure it MUST also be declared
!!	as an INTEGER in this procedure as well as in the calling program.

!! 3.	Actual and dummy arguments.
!!
!!	The only communication between a 'calling' program and a subprogram 
!!	is through its arguments (another method uses modules - see later).
!!	The arguments of the function and subroutine subprograms are DUMMY 
!!	arguments until that subprogram is called, i.e. the do not yet have  
!!	any specific value. They are merely markers until such time as they 
!!	are invoked. It is only when they are called (for subroutines) or 
!!	referenced (for functions) that actual values are set for the dummy 
!!	arguments. They become ACTUAL arguments. 
!!
!!	Communication is a two way process. In the case of functions, the 
!!	arguments pass values TO the function. A single value is RETURNED 
!!	through a variable which is the function name. For subroutines, an 
!!	argument can be used to pass values to the subroutine, to return a 
!!	value from the subroutine or it can be used to pass a value and 
!!	receive an answer. This passing of information is a common source 
!!	of error and it is advisable to be clear what is intended. For this 
!!	reason, Fortran90 has an INTENT attribute:
!!
!!	INTENT(IN) 	dummy argument used only for passing information to 
!!			the procedure. Procedure not permitted to alter value 
!!			of argument.
!!	INTENT(OUT)	dummy argument used only for returning information to 
!!			the calling procedure. Value, undefined on entry to 
!!			procedure, is set within procedure.
!!	INTENT(INOUT)	can be used for transmission of information in both 
!!			directions.

!! 4. 	Local variables.
!!
!!	Variables declared within a procedure (not arguments) are LOCAL to 
!!	that procedure and are not known outside it. It is important to 
!!	realise this; the same name can be used for different variables 
!!	provided they are local variables in different procedures. 
!!	Sometimes, however, it is useful to make variables/constants 
!!	available to more than one procedure. Below, we shall show how 
!!	modules may be used to do this.

!! 5.	Strategy for building programs:
!!
!!	DIVIDE AND CONQUER - break the overall task into subprograms, each of
!!	which performs only one well-defined task. Each subprogram should be 
!!	independently testable. Write out this modularization in pseudocode.
!!
!!	START AT THE TOP - decide on the main program first. It should be an 
!!	outline of the whole program and might often consist only of calls to 
!!	subprograms, namely very little by way of calculation is done in the
!!	main program unit. The sequencing of the tasks in the main program
!!	unit is the "top level" in the process of top-down design.
!!
!!	LITTLE BY LITTLE - compile and check the main program first, perhaps
!!	by having only bare versions of the subprograms. This allows the main
!!	program logic to be designed sensibly and ensures that it communicates
!!	correctly with the subprograms. Only then should you start working on 
!!	the subprograms.

!! 6.	Design steps in more detail:
!!
!!	WRITE A CLEAR STATEMENT OF THE TASK. Describe the purpose of the 
!!	program. Describe the inputs required, the processing needed, and the
!!	outputs that are desired. Specify illegal inputs (bullet-proofing).
!!	Describe limitations of the algorithm to be used. Write out in 
!!	pseudocode. 
!!
!!	INPUTS AND OUTPUTS. Sketch how the inputs and outputs of the program 
!!	should look. 
!!
!!	DESIGN AND CODE THE MAIN PROGRAM, WITH ITS INPUTS AND OUTPUTS, AND
!!	ALL THE SUBPROGRAM INVOCATIONS. At this stage, the subprograms have
!!	not been written; it is enough to use a skeleton, often called a 
!!	"stub", which is sufficient to check the arguments passing between the
!!	subprogram and the main program. Make sure the main program compiles
!!	and is tested before moving on to the next level of design
!!
!!	DESIGN, WRITE AND TEST EACH SUBPROGRAM INDIVIDUALLY.
!!
!!	INSERT EXTRA PRINT STATEMENTS TO DISPLAY INTERMEDIATE RESULTS. Once
!!	you are satisfied that the program is correct, these may be removed 
!!	(or, changed to comments by inserting a `!' in the first column).
!!
!!	DON'T WORRY ABOUT ERRORS. Even the most experienced programmers make
!!	frequent errors.
!!
!!	TORTURE THE PROGRAM when you think it is correct. Try it out with
!!	exceptional or crazy data. The more rugged a program the better.

!!	End of file: procedure4.f90 
