! 8. Modules.						   File: module8.f90
!------------------------------------------------------------------------------!

MODULE	physical_constants
	IMPLICIT NONE
	SAVE

	! constant declarations
	REAL, PARAMETER :: pi=3.1415926, c=2.9979e8, q=1.6022e-19
	REAL, PARAMETER :: h=6.6262e-34,hbar=h/(2.0*pi)
	REAL, PARAMETER :: me=9.1095e-31,mp=1.6726e-27	! electron/proton mass
	REAL, PARAMETER :: mcsquared=510989.6422 ! electron rest mass energy, eV
	REAL, PARAMETER :: mc = 2.7e-22 ! unit of momentum
	REAL, PARAMETER :: factor1 = q/(1.9e15*h)	! E = h*nu
	REAL, PARAMETER :: factor2 = mc/hbar		! p = hbar*k

	! variable declarations
	REAL :: energy  ! input energy (rest mass + kinetic) in eV
	REAL :: omega 	! angular frequency of particle
	REAL :: k	! De Broglie wavenumber of particle
	CHARACTER(LEN=1) :: yn

END MODULE physical_constants


MODULE inout
	USE physical_constants
	IMPLICIT NONE
CONTAINS
	SUBROUTINE input(m)
		IMPLICIT NONE

		! declarations
		REAL, INTENT(OUT) :: m      ! mass of your particle

		! inputs
		PRINT *, 'This program calculates the properties of a photon,'
 		PRINT *, 'electron, proton and a particle of your own choosing'
		PRINT *, 'having a given energy specified in eV '
		PRINT *
		PRINT *, 'It is based on the formulae:'
		PRINT *
		PRINT *, 'E**2 = (m*c**2)**2 + (pc)**2 '
		PRINT *
		PRINT *, 'E = gamma*m*c**2 where '
		PRINT *
		PRINT *, 'gamma = sqrt(1 + (p/mc)**2) = 1/sqrt(1-v**2/c**2) '
		PRINT *
		PRINT *, 'E = hbar*omega '
		PRINT *
		PRINT *, 'p = hbar*k '
		PRINT *
		PRINT *
		PRINT *, 'Do you wish to specify a particle of your own '
		PRINT *, ' choosing? '
		PRINT *
		PRINT *, 'If yes: type y '
		PRINT *, 'If no: type n '
		READ *, yn
		PRINT *

		IF (yn == 'y') THEN
			PRINT *, 'Specify the particle mass (kg)'
			READ *, m
		ELSE IF (yn == 'n') THEN 
			m = mp
		ELSE
			PRINT *, 'Invalid choice. Try again'
			STOP
		END IF

		PRINT *,'Specify the energy in eV'
		PRINT *
		PRINT *,'This energy must be greater than the rest mass '
		PRINT *,'energy of the particle'
		PRINT *,'[0 for photon, 511KeV for electron, 939MeV for proton]'
		PRINT *
		READ *, energy
	END SUBROUTINE input


	SUBROUTINE output(part,mu,p,v)
		IMPLICIT NONE

		! declarations
		REAL, INTENT(IN) :: mu
		REAL, INTENT(IN) :: p
		REAL, INTENT(IN) :: v
		CHARACTER(LEN=8), INTENT(IN) :: part

		omega = energy*factor1
		k = p*factor2
	
		! output
		PRINT *
		PRINT *, 'Properties of ',part,' of energy ',energy,'eV are '
		PRINT *
		PRINT *,'   Rest mass energy = ',mu*mcsquared,' KeV'
		PRINT *,'   Momentum         = ',p*mc,' kg m s-1'
		PRINT *,'   Speed/c          = ',v
		PRINT *,'   Frequency        = ',omega, ' PetaHz'
		PRINT *,'   Wavenumber       = ',k,' m-1'

	END SUBROUTINE output

END MODULE inout


MODULE parton
	IMPLICIT NONE
CONTAINS
	SUBROUTINE particle(e,mu,p,v)
		IMPLICIT NONE

		! declarations
		REAL, INTENT(IN) :: e	  ! photon energy in units of mcsquared
		REAL, INTENT(IN) :: mu	  ! particle mass as multiple of me
		REAL, INTENT(OUT):: p	  ! photon momentum in units of mc
		REAL, INTENT(OUT):: v	  ! particle speed as fraction of c

		p = SQRT(e*e - mu*mu)

		IF (NINT(mu) == 0) THEN
			v = 1.0
		ELSE
			v = p/SQRT(1.0+p*p)
		END IF

	END SUBROUTINE particle

END MODULE parton


PROGRAM	particles
	USE inout
	USE parton
	IMPLICIT NONE

	! declarations	
	REAL :: e      ! energy in units of electron rest mass energy 
	REAL :: p      ! momentum in units of mc
	REAL :: v      ! speed of particle
	REAL :: m      ! mass of particle
	REAL :: mu     ! mass of particle as multiple of electron mass
	CHARACTER(LEN=8) :: partcle

	! inputs
	CALL input(m)

	! convert E to units of mc**2
	e = energy/mcsquared

	! photon properties
	mu = 0.0
	CALL particle(e,0.0,p,v)
	CALL output("photon",mu,p,v)

	! electron properties
	mu = 1.0
	IF (e >= 1.0) THEN
		CALL particle(e,1.0,p,v)
		CALL output("electron",mu,p,v)
	ELSE 
		PRINT *, 'Energy selected less than electron rest mass energy'
	END IF

	! proton properties
	! convert particle mass to multiple of electron mass
	mu = mp/me
	IF (e >= mu) THEN
		CALL particle(e,mu,p,v)
		CALL output("proton",mu,p,v)
	ELSE 
		PRINT *, 'Energy selected less than proton rest mass energy'
	END IF

	IF (yn == 'yes') THEN
		mu = m/me
		IF (e > mu) THEN
			CALL particle(e,mu,p,v)
			CALL output("particle",mu,p,v)
		ELSE
			PRINT *, 'Energy less than particle rest mass energy'
		END IF	
	END IF

END PROGRAM particles


!! 1.	So far, variables within procedures are entirely LOCAL to that 
!!	procedure; otherwise data is supplied to the procedure through the 
!!	dummy arguments. It is often the case that there might be variables, 
!!	such as the common physical constants, which are needed in several 
!!	different procedures. Rather than passing these variables via the 
!!	procedure arguments, which may then become rather long lists, an 
!!	alternative is to make these variables available to the procedures 
!!	which need them by the USE of a MODULE.
!!
!!	The MODULE 'physical_constants' is used to make constants and variables 
!!	available to other program units. In this case, it is made available to 
!!	the module 'inout' by including the statement 'USE physical_constants' 
!!	at the beginning of the module 'inout'. This is called USE association.
!!	This use of modules avoids us having to declare variables, or give 
!!	values to constants, in each of the procedures where they are needed; 
!!	or having to pass them as arguments (of which there might then be a 
!!	long list).
!!
!!	The module 'inout' is used to CONTAIN or encapsulate the two 
!!	subroutines 'input' and 'output'. The purpose of the module here is to 
!!	group related procedures together and to make their INTERFACES EXPLICIT 
!!	to each other and to any program which USEs this module. In other words,
!!	it is to provide the calling program with some information about the 
!!	procedure it is calling. See $3 below. 
!!
!!	The module 'parton' contains only the subroutine 'particle'. It is 
!!	USED in the main program unit 'particles'. 
!!	Note also that the module 'physical_constants' is also made available 
!!	to 'particles' through its inclusion in the module 'inout'. 
!!
!!	Note that the subroutine 'particle' did not need to USE any module.
!!

!! 2. 	The structure of a module is
!!
!!		MODULE module_name
!!			....
!!		END MODULE module_name
!!
!!	The contents of a module are made available to a program unit by means 
!!	of the USE statement:
!!
!!		USE module_name
!!
!!	Study the example above. Note how a variety of useful constants are 
!!	specified and variables declared. 
!!
!!	Include the SAVE statement in all modules which declare variables.

!! 3.	The INTERFACE of a procedure.
!!
!!	This may be defined, loosely, as consisting of the procedure name, the 
!!	number of its arguments and the type of its arguments. There must be 
!!	agreement about these in the procedure definition and in the calling 
!!	statement.
!!
!!	In general, the calling program will know nothing about the called 
!!	procedure and hence be unable to check that there is consistency in 
!!	the interface. Such an interface is called IMPLICIT. This situation 
!!	is prone to error. Hence, it is desirable to make interfaces EXPLICIT 
!!	so that there is matching of procedure name, and the number and type
!!	of arguments. 
!!
!!	One means of making the interface of a procedure explicit is to contain
!!	it within a module. The rules are 
!!
!!		- the interfaces of all procedures defined within a single 
!!		  module are explicit to each other
!!
!!		- the interfaces of any procedures made available by USE 
!!		  association are explicit in the program unit that is using 
!!		  the module.

!! 4.	Modules provide a powerful functionality to Fortran90. The two 
!!	purposes of modules met here are:
!!
!!		- to make constants and/or variables available to other 
!!		  program units
!!		- to make procedure interfaces explicit. Note the use of the 
!!		  word CONTAINS when used in this way.
!!
!!	It is recommended these two ways of using modules be kept separate.
!!	Together, they provide an added device to help with a program's 
!!	data structure.

!! 5.	Now read Chapter 4 (except $4.8)

!!	 End of file: module8.f90

