[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ next ]
Fortran 90
Lessons for Computational Chemistry
The main aims of this lesson are the following:
present how to make use of the standard bash
redirection for
reading and writing data in Fortran
.
present the FORMAT statement, as well as its differents descriptors and its use with the commands PRINT and WRITE.
get a basic knowledge about file handling in Fortran
with the
commands OPEN, CLOSE, and WRITE.
bash
shell redirection
The standard input and output (STDIN/STDOUT) redirection in
bash with < and > allows a
Fortran
program in a simple and direct way to read from and write
to a file.
As an example, the following commands run from a terminal execute a program called a.out. Its output is sent to a file called output.dat in the first case. In the second case, the program reads its input from a file called input.dat, instead of the standard option, the keyboard. In the third case bot options are combined.
a.out > output.dat a.out < input.dat a.out <input.dat > output.dat
The assignment number 4 can be quite done quite easily making use of standard redirection.
The error output (STDERR) can be redirected too as follows
a.out 2> output.dat a.out 2>&1 ouput.dat
In the second case STDERR and STDOUT are merged together in file output.dat.
In order to gain a finer control of the format of input and output statementes the so called format descriptors are introduced. We have make use of the default options or free format up to now, indicated with the symbol * as in READ(*,*), READ*, and PRINT*.
To specify a particular format for the input and output in the above mentioned commands the syntax used is PRINT nlin, output_list, or READ nlin, output_list; where nlin is a label driving to a FORMAT statement with the necessary descriptors and output_list are the constant and variables that will be read or written. It is possible to include directly the descriptors in the statement.
The format descriptors in FORTRAN
, due to historical reasons (line
printers), treated the first character as a control character. If the first
character is
0 : double spacing.
1 : new page.
+ : no spacing. Print over the previous line.
blank : simple spacing.
But this is not anymore true unless you are using a line printer (quite bizarre situation in the XXI century).
The format descriptors can fix the vertical position in a line of text, alter the horizontal position of characters in a line, control the display of integers (I), floats (F and E), strings A and logical variables (L).
The following symbols are used
c : column number
d : number of digits after decimal point (real values)
m : minimum number of digits displayed
n : number of spaces
r : times a descriptor is repeated
w : number of characters affected by a descriptor
Descriptors in I/O operations
Integers: I: General form rIw
This descriptor indicates that r integer values will be read or written, and they occupy w characters or columns. The number is right justified and if the number of digits is less than the number of spacings the rest of the space is filled with space characters. The example
PRINT 100, I, I*I 100 FORMAT(' ',I3, ' squared is ', I6)
outputs a space, a three-digit integer, the string 'squared is' and finish with the square of the variable I, with a maximum number of six digits. More examples can be found in excode_6_1.f90, Section 6.3.1, where the reader can see the effect of having a number with more digits than the allocated space in the format. In this example we also include the X descriptor, such that nX includes n space characters in the output, or skip n characters from the input.
Format descriptors can be also included directly in the PRINT statement, though the resulting code is generally less readable.
PRINT "(' ',I3, ' squared is ', I6)", I, I*I
As can be seen in code example excode_6_1.f90, Section 6.3.1 we can have an arithmetic overflow in a variable and the solution is shown in example excode_6_2.f90, Section 6.3.2.
Real values descriptor F: General form rFw.d
Where w is the total number of columns used to fit the number, d the number of figures after the decimal point, and r the number of times this descriptor is applied.
For example if the descriptor is F7.3 the number will be displayed with three figures after the decimal point and occupies seven spaces. This implies that this format descriptor is valid for numbers between -99.999 and 999.999. The truncated decimal part of the number is properly rounded. It may happens that as a result of the truncation the number has more digits than expected. The output will be changed for w asterisk characters (*). In source code excode_6_3.f90, Section 6.3.3 we face such kind of problems.
Real descriptor E: General form rEw.d
Introduces scientific notation. The number that multiplies the power of ten takes values between 0.1 to 1.0. This case differs from the previous one that some space should be devoted to the exponent. In fact, apart from the multiplier, it is needed one character for the sign of the number if it is negative, another character for the decimal point, another one for the E symbol (stands for Exponent), and the magnitude and sign of the exponent. Therefore the minimum size in this case is w = d+7. Example code excode_6_4.f90, Section 6.3.4 is identical to example excode_6_3.f90, Section 6.3.3 changing the F descriptors to E. This change facilitates to work with numbers whose value vary into a big range.
Real data descriptor ES: general format rESw.d
It allows the use of the standard scientific notation, with the factor that multiplies the power of ten taking velues in the range 1.0 to 10.0. Apart from this it is similar to the previous float descriptor.
Logical data descriptor L: general format rLw
Logical or boolean data only take the values TRUE or FALSE and the output of this descriptor will be a right justified T or F.
Character descriptor A: general format rA or rAw
This format implies that there are r string fields w character wide. If w is missing the string is taken with the same length of the character variable. The example excode_6_5.f90, Section 6.3.5 shows how this descriptor is used.
X descriptor: general format nX
The X descriptor controls horizontal displacement, and it implies that n spaces should be included in the output. You can find an example of this descriptor in source code excode_6_5.f90, Section 6.3.5.
Descriptor T:
El descriptor Tc controla el desplazamiento horizontal e indica que se salte directamente a la columna c.
/ descriptor:
The /descriptor flush the output buffered and feeds a new line. It does not need to be included between commas.
The repetition of a set of descriptors can be easily indicated combining them between parentheses. For example
100 FORMAT(1X, I6, I6, F9.3, F9.3, F9.3)
can be simplified to
100 FORMAT(1X, 3(I6, F9.3))
Fortran
allows file manipulation with the commands
OPEN, WRITE and CLOSE. Other, more
advanced, commands are REWIND and BACKSPACE.
The OPEN command allows to initiate a file. The simplest instance of this command is
OPEN(UNIT=unit_number,FILE='filename')
where the file name and the integer number of the associated unit are indicated. The file is therefore associated to this number for any Read/Write operation. We can write something in this file as follows
OPEN(UNIT=33, FILE='program_OUT.dat') WRITE(UNIT=33,FMT=100) variable_lists
which indicates that the data included in variable_list will be written in the file associated with unit number 33, following the format specified in line labeled 100. It is possible to abbreviate the command to WRITE(33,100) or WRITE(33,*) if free format is required. In order to send the data to STDOUT, WRITE(UNIT=6,format), WRITE(6,*), WRITE(*,*), or PRINT* are all valid and equivalent commands. Standard input STDIN is associated with unit number 5 or the * symbol[6].
Once the write process takes place the unit should be closed using the statement CLOSE(UNIT=unit_number). In our case
CLOSE(UNIT=33)
Example excode_6_6.f90, Section 6.3.6 shows how data are sent to a file and introduces the intrinsic function CPU_TIME that allows to estimate the cpu time spent in a program and its different sections.
The OPEN command can be more specific, adding the following arguments:
OPEN(UNIT=unit_number,FILE=file_name,STATUS=file_status, ACTION=action_var, IOSTAT=integer_var)
These options control the following aspects:
STATUS=file_status
The constant or variable file_status is of character type and can take the following values:
'OLD'
'NEW'
'REPLACE'
'SCRATCH'
'UNKNOWN'
ACTION=action_var
The constant or variable action_var is of character type and can have the following forms:
'READ'
'WRITE'
'READWRITE'
By default. archives are opened with both read and write permissions active.
IOSTAT=integer_var
The variable integer_stat is of integer type and gives feedback about the success of the opening of the file. If the final value is 0 the file has been correctly opened. Any other value indicates a problem.
A complete example will be
INTEGER ierr OPEN(UNIT=33, FILE='input_program.dat', STATUS='OLD', ACTION='READ', IOSTAT=ierr)
If we want to create a file to store some data:
INTEGER ierr OPEN(UNIT=33, FILE='output_program.dat', STATUS='NEW', ACTION='WRITE', IOSTAT=ierr)
It is possible some degree of control on the access to the elements stored sequentially using the commands
BACKSPACE(UNIT = unit_number) REWIND(UNIT = unit_number)
The BACKSPACE statement set the register one line back in the associated file while REWIND move back to the first register of the file.
The default is to open formatted files. Thus, the following two statements are equivalent
OPEN(UNIT=33,FILE='file_name') OPEN(UNIT=33,FILE='file_name',FORM='FORMATTED')
Formatted files can be edited and read by the user, but they have a couple of cons. Data storage and reading in formatted files takes longer than in unformatted files and there may be some precision loss in float numbers. In order to write data without format files should be opened including the FORM='UNFORMATTED' option:
OPEN(UNIT=33,FILE='file_name',FORM='UNFORMATTED')
To write in a file declared unformatted the WRITE command takes the form
WRITE(UNIT=33) variable_list
The combination of fortran descriptors and different kinds of loop in a code can be found in the example excode_6_7.f90, Section 6.3.7. This program reads a data file (a template of this fila can be found under the program, and can be saved removing the trailing ! symbols). When the program opens the datafile with OPEN it uses the STATUS = 'OLD' and ACTION='READ' options. It reads the file, skipping some files making use of a REPEAT UNTIL loop, until it arrives to a line that provides the number of data pairs in the file[7]. Knowing the number of data pairs the appropriate matrices are allocated and the points are read and saved into vectors data_X and data_Y, and computes the maximum (minimum) value of data_X (data_Y) making use of the intrinsic functions MAXVAL and MINVAL (see Objectives, Section 8.1).
PROGRAM ex_6_1 ! IMPLICIT NONE ! ! Variables INTEGER :: i, big=10 ! DO i=1,20 PRINT 100, i, big big=big*10 END DO ! ! Format Statements 100 FORMAT(1X, '10 to the ',I3,2X,'=',2X,I12) ! END PROGRAM ex_6_1
PROGRAM ex_6_2 ! IMPLICIT NONE ! INTEGER, PARAMETER :: Long=SELECTED_INT_KIND(16) ! 64 bits integer INTEGER :: i INTEGER (KIND=Long) :: big=10 ! DO i=1,18 ! PRINT 100, i, big 100 FORMAT(1X, '10 to the ', I3, 2X, '=', 2X, I16) ! big=big*10 ! END DO ! END PROGRAM ex_6_2
PROGRAM ex_6_3 ! Program to produce numeric overflow and underflow IMPLICIT NONE INTEGER :: I REAL :: small = 1.0 REAL :: big = 1.0 ! DO i=1,45 PRINT 100, I, small, big 100 FORMAT(' ',I3,' ',F9.4,' ',F9.4) ! small = small/10.0 big = big*10.0 ! END DO END PROGRAM ex_6_3
PROGRAM ex_6_4 ! Program to produce numeric overflow and underflow IMPLICIT NONE INTEGER :: I REAL :: small = 1.0 REAL :: big = 1.0 ! DO i=1,45 PRINT 100, I, small, big 100 FORMAT(' ',I3,' ',E10.4,' ',E10.4) ! small = small/10.0 big = big*10.0 ! END DO END PROGRAM ex_6_4
PROGRAM ex_6_5 ! Program to compute the Body Mass Index (Quetelet Index) according to the formula: ! BMI = (weight (kg))/(height^2 (m^2)) ! IMPLICIT NONE CHARACTER (LEN=25) :: Name INTEGER :: height_cm = 0, weight_kg = 0 ! height in cm and weight in kg REAL :: height_m = 0.0 ! height in m units REAL :: BMI ! Body Mass Index ! PRINT*, 'Full Name:'; READ*, Name ! PRINT*, 'Weight (kg)?:'; READ*, weight_kg ! PRINT*, 'Height (cm)?:'; READ*, height_cm ! height_m = height_cm/100.0 BMI = weight_kg/(height_m**2) ! PRINT 100, Name, BMI, BMI 100 FORMAT(1X,A ' BMI is ', F10.4,' or ', E10.4) ! END PROGRAM ex_6_5
PROGRAM ex_6_6 ! IMPLICIT NONE INTEGER , PARAMETER :: N=1000000 INTEGER , DIMENSION(1:N) :: X REAL , DIMENSION(1:N) :: Y INTEGER :: I REAL :: T REAL , DIMENSION(1:5) :: TP CHARACTER*10 :: COMMENT ! OPEN(UNIT=10,FILE='/tmp/ex_6_6.txt') ! CALL CPU_TIME(T) ! TP(1)=T COMMENT=' Initial Time : ' PRINT 100, COMMENT, TP(1) ! DO I=1,N X(I)=I END DO ! CALL CPU_TIME(T) ! TP(2)=T-TP(1) COMMENT = ' Integer vector. Time : ' PRINT 100,COMMENT,TP(2) ! Y=REAL(X) ! CALL CPU_TIME(T) ! TP(3)=T-TP(1)-TP(2) COMMENT = ' Real vector. Time : ' ! PRINT 100,COMMENT,TP(3) ! DO I=1,N WRITE(10,200) X(I) 200 FORMAT(1X,I10) END DO ! CALL CPU_TIME(T) TP(4)=T-TP(1)-TP(2)-TP(3) ! COMMENT = ' Write Integer vector. Time : ' PRINT 100,COMMENT,TP(4) ! DO I=1,N WRITE(10,300) Y(I) 300 FORMAT(1X,f10.0) END DO ! CALL CPU_TIME(T) TP(5)=T-TP(1)-TP(2)-TP(3)-TP(4) ! COMMENT = ' Write Real vector. Time : ' PRINT 100,COMMENT,TP(5) ! 100 FORMAT(1X,A,2X,F7.3) END PROGRAM ex_6_6
PROGRAM ex_6_7 ! IMPLICIT NONE ! REAL , DIMENSION(:), ALLOCATABLE :: X_vec, Y_vec ! Data Vectors INTEGER :: Index, Ierr, Numpoints = 0 REAL :: Max_x, Min_y CHARACTER(LEN=64) :: Filename ! ! READ FILENAME READ(5,*) Filename ! OPEN FILE (READONLY) OPEN( UNIT=10, FILE=Filename, STATUS='OLD', ACTION='READ' ) ! DO READ(UNIT=10, FMT=100, ERR=10) Numpoints IF (Numpoints /= 0) EXIT 10 READ (UNIT=10, FMT=*) ! JUMP ONE LINE CYCLE ENDDO ! PRINT*, 'NUMPOINTS = ', Numpoints ! ! ALLOCATE X, Y VECTORS ALLOCATE(X_vec(1:NUMPOINTS), STAT = IERR) IF (Ierr /= 0) STOP 'X_vec MEM ALLOCATION FAILED' ALLOCATE(Y_vec(1:NUMPOINTS), STAT = IERR) IF (Ierr /= 0) STOP 'Y_vec MEM ALLOCATION FAILED' ! DO I = 1, Numpoints ! READ(UNIT=10, FMT=110) X_vec(I), Y_vec(I) ! ENDDO ! Max_x = MAXVAL(X_vec) Min_y = MINVAL(Y_vec) ! PRINT*, "MAXIMUM X VALUE = ", Max_x PRINT*, "MINIMUM Y VALUE = ", Min_y ! DEALLOCATE AND CLOSE FILE DEALLOCATE(X_vec, STAT = IERR) IF (Ierr /= 0) STOP 'X_vec MEM DEALLOCATION FAILED' DEALLOCATE(Y_vec, STAT = IERR) IF (Ierr /= 0) STOP 'Y_vec MEM DEALLOCATION FAILED' ! CLOSE(10) ! FORMAT STATEMENTS 100 FORMAT(19X,I3) 110 FORMAT(F6.3,1X,F6.3) ! END PROGRAM ex_6_7 !# Remark 1 !# Remark 2 !Useless line 1 !Useless line 2 !Number of points = 4 !+1.300;-2.443 !+1.265;-1.453 !+1.345;-8.437 !+1.566;+4.455 !+1.566;+4.455 !+3.566;+7.755 !+1.566;+4.457 !+2.366;+2.454 !+1.566;+4.405 !+0.566;+9.450 !+1.545;+4.465 !+9.566;+6.455 !+1.466;+8.405 !+0.566;+7.055
[ previous ] [ Contents ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ next ]
Fortran 90
Lessons for Computational Chemistry
mailto:francisco.perez@dfaie.uhu.es