! 20. Input and Output.					File: inout20.f90
!------------------------------------------------------------------------------!

MODULE io
	IMPLICIT NONE
CONTAINS

	SUBROUTINE introduction()
		IMPLICIT NONE

		! 0. Introduction.

		PRINT *
		PRINT *,'		INPUT and OUTPUT	'
		PRINT *
		PRINT *,'The following session is in the form of a longish &
			 &very artificial program illustrating the many &
			 &powerful input/output features which Fortran & 
			 &supports. It consists of 9 cases. Each case & 
			 &introduces a new idea and is heavily commented &
			 &(the !! lines) at the point of introduction. & 
			 &View this program, execute each item and observe &
			 &the action performed by each part. Compare what you &
			 &expect from the program with the output to screen &
			 &carefully - this means character by character, & 
			 &space by space'


	END SUBROUTINE introduction

!------------------------------------------------------------------------------!

	SUBROUTINE proceed(item)
		IMPLICIT NONE

		INTEGER, INTENT(OUT) :: item

		! decide which item you wish to examine. 
		PRINT *
		PRINT *,'Which item do you wish to proceed with?'
		PRINT *
		PRINT *,'1. A summary of input/output so far: type 1'
		PRINT *,'2. The WRITE statement : type 2'
		PRINT *,'3. The FORMAT statement : type 3'
		PRINT *,'4. The embedded format : type 4'
		PRINT *,'5. Edit descriptors : type 5'
		PRINT *,'6. Slash editing : type 6'
		PRINT *,'7. Repeat formats : type 7'
		PRINT *,'8. Character output : type 8'
		PRINT *,'9. An example : type 9' 
		PRINT *,'To QUIT type any other number'
		PRINT *
		READ *, item
		PRINT *

		IF (item > 9 .OR. item <= 0) STOP


	END SUBROUTINE proceed

!------------------------------------------------------------------------------!

	SUBROUTINE io_sofar(item)
		IMPLICIT NONE

		! 1:  A summary of what we have used so far

		INTEGER, INTENT(IN) :: item
		INTEGER :: i,j
		REAL :: x, y, z, w

		i = 12345
		x = 1.2345
		y = 0.12345E+5
		z = 0.123456E-8

		! input an integer j and a real number w
		PRINT *, 'Specify an integer j and a real number w'
		READ *, j, w
		PRINT *
		PRINT *, 'i =',i,'  j =',j
		PRINT *
		PRINT *, '       x           y           z            w   '
		PRINT *,'-----------------------------------------------'
		PRINT *, x,y,z,w
		PRINT *
		WRITE(19,*) x,y,z,w
		PRINT *

	END SUBROUTINE io_sofar

!! 1a:	The PRINT statement always sends output to the standard output device
!!	stdout (usually the monitor). 
!!	Note how anything enclosed within apostrophes or quotes is reprinted 
!!	"as is".
!!	Note how we created vertical "white space" using PRINT * .
!!	Note how we sent the output to a file, called by default "fort.19" by
!!	use of the WRITE statement.
!!	Note how successive variables are separated by a comma. This is an 
!!	example of a VALUE SEPARATOR. Other separators are a slash(/), a 
!!	blank, and an 'end of record (i.e. line). See later.
!!
!! 1b: The input and output are "list-directed" input or output, namely where
!!     the FORMAT is specified by default and driven only by the list of
!!     values to be read or printed. This is the significance of the * in
!!     all of the above.
!!
!! 1c: We now look at ways of controlling the appearance of input/output (i/o)
!!     rather than having the above free forms imposed upon us. We concentrate
!!     on the output first.

!------------------------------------------------------------------------------!

	SUBROUTINE print_write(item)
		IMPLICIT NONE

		! 2. The WRITE and PRINT statements.

		INTEGER, INTENT(IN) :: item
		REAL :: x

		x = 1.2345

		PRINT *, x
		WRITE(*,*) x
		WRITE(UNIT=*,FMT=*) x

	END SUBROUTINE print_write

!! 2a:	The above statements produce identical output. The first * in the WRITE
!!	means that output goes to the stdout (monitor) while the second stands 
!!	for the default list-directed output format. Recall that PRINT always
!!	sends output to stdout.
!!
!! 2b:	The general form of the write statement is
!!
!!		WRITE (cilist)  output-list
!!
!!	where the cilist represents a control information list consisting of one
!!	or more specifiers, separated by commas. Only two specifiers need 
!!	concern us for the moment.
!!
!!	The first specifier is the "unit specifier" of the form
!!
!!			UNIT = u
!!
!!	where u is a positive integer which identifies a unit (file, peripheral 
!!	device like a plotter, magnetic disk or tape drive) to which the output 
!!	is to be sent. Fortran imagines that a channel is opened to the unit
!!	specified. Some units are already preconnected, such as output to the
!!	stdout/monitor - on most systems identified as unit 6 - or connection
!!	to the file "fort.u". Other units need to be connected by OPENing a
!!	channel to them. We will discuss this in the following session.
!!	If it appears first in the list then the UNIT= may be omitted as shown
!!	above.
!!
!!	The second specifier is the FORMAT statement
!!
!!			FMT = character variable
!!			FMT = label
!!			FMT = * 
!!
!!	where the right hand side is the format specifier providing a link to 
!!	the information required for editing the output (or input as 
!!	appropriate). This information consists of a list of edit descriptors 
!!	which are described below and can be provided either in an embedded 
!!	form as a character variable, or by providing a label redirecting the 
!!	program to a format statement. The final form of the three above is 
!!	the list-directed format already met. Again, if this appears as the
!!	second item in the cilist and the "UNIT=" has been omitted in the 
!!	first specifier then the "FORMAT="  may be also be omitted. Thus, for
!!	example,
!!			WRITE(23,100) x,y,z
!!
!!	indicates that the output is to be sent to UNIT=23 (by default, fort.23
!!	unless this channel has been opened with an OPEN statement (see later))
!!	in a FORMAT statement whose label is 100.

!------------------------------------------------------------------------------!

	SUBROUTINE format_statement(item)
		IMPLICIT NONE

		! 3: The FORMAT statement

		INTEGER :: i
		REAL :: x
		INTEGER, INTENT(IN) :: item

		i = 12345
		x = 1.2345

		WRITE(UNIT=6,FMT=300) i,x
		WRITE(6,FMT=300) i,x
		WRITE(6,300) i,x

		WRITE(31,300) i,x
		WRITE(31,FMT=300) i,x
		WRITE(UNIT=31,FMT=300) i,x
		PRINT *

		300  FORMAT ( 1X, I5, 5X, F8.3 )

	END SUBROUTINE format_statement


!! 3a.	Observe the first three WRITE statements - each performs identically
!!	with output going to UNIT=6, the stdout(monitor).
!!	The second three send the output to the preconnected UNIT=31 which is
!!	the file fort.31
!!	In each case the layout of the data is identical and determined by the
!!	FORMAT statement. Look at its form
!!
!!		label  FORMAT (ed1,ed2,....,edn)
!!
!!	where ed1,...edn are "edit descriptors". These interpret how the output
!!	is to be displayed.
!!
!! 3b.	In the above example, all of the WRITE statements invoked the same 
!!	FORMAT statement. Equally there could have been separate and distinct
!!	FORMAT statements for each.
!!	What appears within the parentheses means the following. Imagine a line
!!	of output on a page/monitor with a number of character positions. Then
!!
!!	   1X	ignore the first character position (i.e. blank)
!!	   I5	output an integer in the next 5 positions (right justified)
!!	   5X	ignore the next 5 character positions (5 blanks)
!!	   F8.3	output a real number in the next 8 character positions 
!!		with 3 decimal places (right justified)
!!
!! 3c.	FORMAT statements may appear anywhere in the program before the END but
!!	after the declarations. We could place them immediately after the WRITE 
!!	statement to which they refer. However it is preferable to gather them 
!!	all together and place them all just before the END statement. This is
!!	a matter of style. Sometimes, too many FORMATs clutter the look of a 
!!	program if they are distributed throughout it.

!------------------------------------------------------------------------------!

	SUBROUTINE embedded(item)
		IMPLICIT NONE

		! 4. The embedded format

		INTEGER :: i,j
		REAL :: x,y
		INTEGER, INTENT(IN) :: item

		i = 2467
		x = 1.000e-3

		! read in an integer and a real number
		PRINT *
		PRINT *,'Type in a positive integer less than 10000'
		PRINT *
		READ '(I4)', j
		PRINT *
		PRINT *,'Type in a positive real number less than 10000 and '
		PRINT *,'accurate to 3 decimal places'
		PRINT *
		READ '(F8.3)', y
		PRINT *

		! output to screen
		PRINT *
		PRINT '(3X,I4,2X,I4,2X,F8.3,2X,F8.3)', i,j,x,y
		PRINT *


		! output to file fort.43
		WRITE (UNIT=43,FMT='(3X,I4,2X,I4,2X,F8.3,2X,F8.3)') i,j,x,y

	END SUBROUTINE embedded

!! 4a.	Note how the EMBEDDED FORMAT statements are constructed and where 
!!	they are placed. They are in the form of a character variable. 
!!	Note however that this list of edit descriptors may become quite long. 
!!	Then it is preferable to use a separate format statement with a label.

!------------------------------------------------------------------------------!

	SUBROUTINE edit_descriptor(item)
		IMPLICIT NONE

		! 5. Edit descriptors

		INTEGER :: i
		REAL :: x,y,z
		INTEGER, INTENT(IN) :: item

		i = 12345
		x = 1.2345
		y = 0.12345e+5
		z = 0.123456e-8

		WRITE(6,500)  i,x,y,z
		PRINT 500, i,x,y,z

		500 FORMAT(1X,I5,4X,F6.4,4X,E11.5,4X,E12.6)

		WRITE(6,520)  i,x,y,z

		520 FORMAT(1X,I6,4X,F8.4,4X,E13.4,4X,E9.6)

		WRITE(6,540)  i,x,y,z

		540 FORMAT(1X,'I=',I6,4X,'X=',F6.4,4X,'Y=',E9.3,4X,'Z=',E12.5)

		PRINT *


	END SUBROUTINE edit_descriptor

!! 5a.	Look carefully at the output produced by each of the above formats.
!!
!!	Descriptor			Meaning
!!     ______________________________________________________________________
!!
!!	Iw		output an integer in the next w character positions
!!
!!	Fw.d		output a real number in the next w character positions
!!			with d decimal places 
!!
!!
!!	Ew.d		output a real number in the next w character positions
!!			using scientific format with d decimal places in the
!!			mantissa and four characters in the exponent
!!			(e.g. for 0.12345E-12 we would need E11.4)
!!
!!	nX		ignore the next n character positions (blanks)
!!
!!	Tc		output the next item in the list starting at character 
!!			position c (an absolute position, similar to tabbing)
!!
!!	TLn		output next item starting n positions before (TL) or 
!!	TRn		after (TR) the current position. TRn has same effect
!!			as nX.
!!
!!	'abc...def'	output the string of characters abc...def starting at
!!			the next character position.
!!    ________________________________________________________________________
!!
!!     In the first three cases above, if the number has less than w digits it
!!     is right justified. If it has more than w digits then a format overflow
!!     occurs and **** are output.
!!
!!     Now run the program and study in detail what is output. Note that when
!!     there are not sufficient decimal places the number is rounded and NOT
!!     truncated. Check that the exact number of spaces that you see in the 
!!     output is what you expect from the FORMAT statements.

!------------------------------------------------------------------------------!

	SUBROUTINE  slash_edit(item)
		IMPLICIT NONE

		! 6. Slash editing

		INTEGER, INTENT(IN) :: item

		PRINT *
		PRINT *
		PRINT *, '   FREQUENCY    CURRENT'
		PRINT *, '    (hertz)      (amps)'
		PRINT *, '--------------------------'
		PRINT *

		! the following achieves exactly the same effect using 
		! only a single PRINT statement in conjunction with a FORMAT

		PRINT 600

		600 FORMAT ( //'   FREQUENCY    CURRENT'/& 
		&'    (hertz)      (amps)'/&
		&'--------------------------'/ )

	END SUBROUTINE slash_edit


!! 6a:	The "slash" means terminate the current line. It also then acts as a 
!!	value separator between edit descriptors.

!------------------------------------------------------------------------------!

	SUBROUTINE repeats(item)
		IMPLICIT NONE

		! 7. Repetition of edit descriptors

		INTEGER :: i,j
		REAL :: x,y,z,w
		INTEGER, INTENT(IN) :: item

		i = 2345
		j = 67890
		x = 23.456789
		y = 1.0e-12
		z = 0.1234
		w = 2.12e4

		PRINT 700

		700 FORMAT(//5X,'i     j       x         y         z        w'/)

		! the following two formats achieve the same output

		PRINT 720, i,j,x,y,z,w
		PRINT 740, i,j,x,y,z,w

		720 FORMAT (1X, I6, I6, F8.4, E12.5, E12.5, E12.5//)
		740 FORMAT (1X, 2I6, F8.4, 3E12.5//)

		! the following two formats achieve the same output

		PRINT 760, i,j,x,y,z,w
		PRINT 780, i,j,x,y,z,w

		760 FORMAT (2X, I6, 2X, I6, 3X, F8.4, 3X, E12.5,&
		&3X, E12.5, 3X, E12.5//)

		780 FORMAT ( 2(2X, I6), 3X, F8.4, 3(3X, E12.5)//)

	END SUBROUTINE repeats


!! 7a:	The integer in front of the edit descriptor means repeat this number
!!	of times. The first two FORMATs achieve identical outputs.
!!
!! 7b:	Note also how groups of formats may be repeated.

!------------------------------------------------------------------------------!

	SUBROUTINE character_output(item)
		IMPLICIT NONE

		! 8. Character output.

		REAL :: E,R,L,C
		INTEGER, INTENT(IN) :: item

		E = 4.35791e-3
		R = 1.2e+04
		L = 0.1592e0
		C = 134.9

		PRINT 800, E
		PRINT 820, R
		PRINT 840, L
		PRINT 860, C

		800 FORMAT ( 1X, 'E = ', E13.5, ' volt' )
		820 FORMAT ( 1X, 'R = ', E13.5, ' ohm' )
		840 FORMAT ( 1X, 'L = ', E13.5, ' henry' )
		860 FORMAT ( 1X, 'C = ', E13.5, ' farad'// )

		PRINT 880, 'E = ', E, ' volt '
		PRINT 880, 'R = ', R, ' ohm  '
		PRINT 880, 'L = ', L, ' henry'
		PRINT 880, 'C = ', C, ' farad'

		880 FORMAT ( 1X, A4, E13.5, A6 )

	END SUBROUTINE character_output


!! 8a.	In the first set of PRINTs the strings appear in the FORMATs. This is
!!	not ideal since some of the output is specified in the PRINT while the
!!	rest, namely the strings are specified in the FORMAT. The second option
!!	is more symmetrical in that everything that is to be output is specified
!!	in the PRINT and the FORMAT concentrates on the how the output is to be
!!	formatted. 

!! 8b.	The FORMAT here is using a character format specifier, called the "A 
!!	format", which has the form "An" where n is the number of characters
!!	in the output string. Note that the first string has 4 characters 
!!	between the apostrophes and the second 6; hence the A4 and A6. Note 
!!	also that one FORMAT serves all PRINT statements.

!! 8c.	The READ statement.

!!	More often than not we will be inputting data from the keyboard (stdin)
!!	or reading a list-directed set of data (default format) from a data
!!	file. However, it is possible to read data from a file in which the 
!!	data is formatted in much the same way that occurs for output. Look
!!	at the following program for an example of such a formatted READ.

!! 8d.	Printer control characters.
!!
!!	You will have noticed how many of the FORMAT statements have included
!!	1X at the beginning and hence leaving the first space blank. This is
!!	a safety measure in that when output is sent to a printer Fortran treats
!!	the first character space as a "printer control character". Thus, this
!!	character is removed and used to indicate how much vertical space to
!!	move before printing the next part of the output. These characters are
!!
!!		CHARACTER:	VERTICAL SPACING BEFORE PRINTING:
!!		space/blank	one line
!!		0 (zero)	2 lines
!!		1 (one)		first line of next page
!!		+ (plus)	overprint current line
!! 
!!	Remember that this is effective only when output is being sent to a 
!!	device that acts like a printer. On some systems, a monitor acts like
!!	a terminal and on others it does not. That is why it is often a safe
!!	choice to insert a 1X to ensure the first character is a blank.

!------------------------------------------------------------------------------!

	SUBROUTINE example(item)
		IMPLICIT NONE

		! 9. An example.
		! This program processes experimental data relating to 
		! radioactive decay


		INTEGER :: alpha, beta, gamma, i, maxint=0
		REAL :: time, period, maxg=0.0, tlast=0.0, ava, avb, avg
		! maxdata is number of readings to be processed (kept small) 
		INTEGER, PARAMETER :: maxdata=3
		INTEGER, INTENT(IN) :: item

		PRINT *
		PRINT *, 'WARNING: This item still has a bug yet to be '
		PRINT *, 'found and corrected!!!'

		PRINT *
		PRINT *, 'This program processes experimental data relating'
		PRINT *, 'to radioactive decay'

		! print headings to file fort.92
		WRITE(91,601)

		! process 'maxdata' sets of data read in from file fort.91
		! this file will need to contain the data as specified 
		! in FORMAT 600
		! you will need to create fort.91
		PRINT *, 'Input read from file fort.91'
		PRINT *, 'Output sent to fort.92'

		DO i = 1,maxdata
			READ (91,600) time, alpha, beta, gamma

			! calculate interval since last readings
			period = time - tlast
			tlast = time

			! calculate the average rates of emission
			ava = alpha/period
			avb = beta/period
			avg = gamma/period

			! print statistics for this interval to file fort.92
			WRITE (92,602) i,period,alpha,beta,gamma,ava,avb,avg

			! check for maximum gamma radiation
			IF (avg > maxg ) THEN
				maxg = avg
				maxint = i
			END IF
		END DO

		! print details of interval with maximum gamma radiation 
		! to file fort.92
		WRITE (92,603) maxg,maxint

		600 FORMAT (F8.2,3(5X,I6))
		601 FORMAT (T5,'Interval',T16,'Time',T23,'Alpha',T32,&
		'Beta',T39,'Gamma',T47,'Av. A',T55,'Av. B',T63,'Av. G')
		602 FORMAT (I11,F8.2,3I8,3F8.2)
		603 FORMAT (T5,'Maximum average gamma radiation was',F7.2,&
		 ' in interval',I5)

	END SUBROUTINE example

!------------------------------------------------------------------------------!

END MODULE io



PROGRAM inputoutput
	USE io
	IMPLICIT NONE

	! The following session is in the form of a longish very artificial 
	! program illustrating the many powerful input/output features which 
	! Fortran supports. Each small section introducing a new idea is 
	! heavily commented (the !! lines) at the point of introduction. 
	! View this program and at the same time execute it to see the action 
	! performed by each part. 

	INTEGER :: item, index

	CALL introduction()

	! decide on next section to study
	CALL proceed(item)

	DO index=1,20

		SELECT CASE(item)
		CASE (1)
			CALL io_sofar(item)
			CALL proceed(item)
		CASE (2)
			CALL print_write(item)
			CALL proceed(item)
		CASE (3)
			CALL format_statement(item)
			CALL proceed(item)
		CASE (4)
			CALL embedded(item)
			CALL proceed(item)
		CASE (5)
			CALL edit_descriptor(item)
			CALL proceed(item)
		CASE (6)
			CALL slash_edit(item)
			CALL proceed(item)
		CASE (7)
			CALL repeats(item)
			CALL proceed(item)
		CASE (8)
			CALL character_output(item)
			CALL proceed(item)
		CASE (9)
			CALL example(item)
			CALL proceed(item)
		CASE DEFAULT
			CALL proceed(item)
		END SELECT
	END DO
END PROGRAM inputoutput

!!	END OF FILE: inout20.f90
