Fortran 90/95 Programming Victor Anisimov, NCSA June 25, 2018 Fortran 90/95 Programming Victor Anisimov, NCSA FIU / SSERCA / XSEDE Workshop, Apr 4-5, 2013, Miami, FL
Few facts about Fortran Fortran is a modern powerful programming language for scientific applications Fortran standard is actively evolving yet maintaining unbeatable backward compatibility and portability Fortran code is easy to read Fortran compiler produces the most optimized binary code Fortran offers specific language constructs for scientific computations which are not available in other languages Fortran 90 / 95 Programming
Fortran Compiler Efficiency ! compute vector product a(m,n) = b(m,n) * c(m,n) a = b * c ! FORTRAN-90 code has one line index = 0; /* C code requires four lines */ for ( i=1; i<=m*n; i++ ) { index++; a(index) = b(index) * c(index); } Fortran 90 / 95 Programming
Fortran basics Compilers: gfortran, pgf90, ifort, crayftn, etc. File extensions: .f .F .f90 .F90 lower case (.f .f90) no preprocessor will be invoked upper case (.F .F90) preprocessor will be invoked without number (.f .F) used with old F77 standard with number (.f90 .F90) to stress on F90 standard Fortran-90 compiler is fully backward compatible and allows mixing of different standards in the code Recommended extension .F90 gfortran -c prog.F90 ! Compiling produces object prog.o gfortran -o prog.x prog.o ! Linking produced binary prog.x Fortran 90 / 95 Programming
Fortran Program Structure program program-name ! only one main program is defined implicit none [declaration part] [execution part] end program program-name subroutine subroutine-name ! contains commonly executed pieces of code end subroutine subroutine-name Integer function function-name ! same as subroutine but used differently end function function-name Fortran 90 / 95 Programming
Fortran Data Type Operators fortran language is case-insensitive combine lower and upper case to improve readability please use meaningful variable names type declaration operators do not zero-initialize the variables integer :: counter double precision :: pi=3.14159265358d0 character (len=80) :: string integer, parameter :: nRows=5, nColumns=6 real :: array(nRows,nColumns) logical :: completedSuccessfully = .False. double complex :: phase = (4.0d0, 3.4d0) Tip: Unintialized variable contains machine garbage Fortran 90 / 95 Programming
Passing Arguments to / from Procedures a = function-name() ! By return value Subroutines and Functions have a special mechanism to declare argument intent subroutine subroutine-name ( arg1, arg2, arg3 ) implicit none integer, intent (in) :: arg1 ! Argument is read-only double precision, intent(out) :: arg2 ! Placeholder for return value character (len=80), intent(inout) :: arg3 ! Argument is for reading and writing [execution part] end subroutine subroutine-name Purpose: Clarity Protection against programming bugs Presentation Title
Fortran Modules Modules are Data and Function (subroutine) placeholders we will design module loan (loan.F90) module module-name ! Define data scope implicit none character (len=80), private :: string ! Local variable accessible within this module only double precision, public :: currentBalance public :: Interest, Payment contains double precision function Interest() ! can be called from outside the module end function Interest double precision function Payment() ! can be called from outside the module end function Payment double precision function RoundToCents( amount ) ! Not visible from outside end function RoundToCents end module module-name Fortran 90 / 95 Programming
Fortran Modules in Use program LoanSimulator ! Use module loan defined in loan.F90; note the use of variables and functions use loan, only : currentBalance, Interest, Payment implicit none ! .. local variables .. integer :: month ! .. executable statement .. ! read input parameters ! execute while-loop until the loan is paid of ! in each loop iteration ! apply interest ! update balance ! determine payment amount ! apply payment end program LoanSimulator Fortran 90 / 95 Programming
Fortran Conditional Statements if ( a > b ) then [execution part] elseif ( a .eq. b ) then else ! a < b end if Example if ( (a > b .and. b <= z) .or. .not. finishedSuccessfully ) then Tip: Use indentation to improve readability of the code conditional operators .lt. .le. .eq. .ne. .ge. .gt. < <= == /= >= > .and. .or. .not. Fortran 90 / 95 Programming
Fortran DO loops Formal definition of DO loop: do index = indexFrom, indexTo, indexIncrement [execution part] end do Example-1: do i = 1, 10 ! Loop starts from i=1; at the “end do” i=i+1; last loop i=10 Example-2: do i = -5, 10, 2 ! Loop starts from i=-5; at the “end do” i=i+2; last loop i=9 Example-3: do i = 10, 1, -1 ! Loop starts from i=10; at the “end do” i=i-1; last loop i=1 Fortran 90 / 95 Programming
Fortran DO and WHILE loops Example-4: a = 5; b = 4; c = 1 do i = a, b, c ! Attention: Loop will be skipped [execution part] end do Rule: Fortran checks the loop exit condition (a <= b) before starting the iteration do while (a < b) ! Loop will be continued as long as the condition is true do i = a, b, c [execution part -1] if ( x == y ) cycle ! If satisfied, skip part of the loop after this point if ( m .ne. n ) exit ! If satisfied, exit the loop [execution part-2] Fortran 90 / 95 Programming
Fortran Arrays program arrays implicit none integer, parameter :: nRows = 5, nColumns = 3 integer :: allocStat double precision :: a(nRows, nColumns) ! Static array double precision, allocatable :: b(:,:) ! Dynamic array character (len=80) :: string = “text” allocate( b(nRows, nColumns), stat=allocStat) ! Allocate memory if (allocStat .ne. 0) stop ‘Error in memory allocation’ ! Check for allocation error a = 1.0d0 ! Assign 1.0d0 to each element of the array b = a ! Copy array a to b b(1,2) = 3.1d0 ! Access specific array element deallocate ( b, stat=allocStat ) ! Free the memory for other uses string(3:3) = “s” ! String is a special type of array ! continue computation and perform new cycles of allocation and deallocation, if necessary end program arrays Fortran 90 / 95 Programming
Fortran Input / Output: Files integer, parameter :: inputUnit = 10 character (len=512) :: fname = “input.txt” open (unit=inpUnit, file=fname, status='old', form='formatted’, access=‘sequential’) ! .. do some work on the file here .. close (inpUnit) unit - can be any number except system reserved ones; number >= 10 should be fine status - ‘old’ requires existing file fname, otherwise error ‘new’ new file will be created ‘unknown’ open existing file or new file will be created if one does not exist form - ‘formatted’ text file; can be ‘unformatted’ (binary file) access - ‘sequential’ default; can be ‘direct’ (for random access) Fortran 90 / 95 Programming
Fortran Input / Output: Read and Write Synopsis: read(unit, format) list-of-variable write(unit, format) list-of-variables Sample input string (for visual clarity, we use underscore to represent white space): Hydrogen _ _1 _ _ 1.35 _ _ 2.60 _ -1.24 ! _ will be used instead of white-space character program ReadFormattedText implicit none character (len=20) :: label integer :: index double precision :: x, y, z read(*,’(a8, i3, 3f6.2)’) label, index, x, y, z ! Read from standard input (console) write(*,’(a8, i3, 3f6.2)’) label, index, x, y, z ! Write to standard input end program ReadFormattedText Question: what will the result of write(*,’(a,i0)’) label, index Fortran 90 / 95 Programming
Fortran: Reading Command-Line Arguments program ReadArguments implicit none character (len=512) :: prgName, string integer :: nArgs double precision :: startingBalance nArgs = command_argument_count() ! Get the number of command-line arguments call getarg(0, prgName) ! 0-th argument is the program name if (nArgs < 3) then write(*,'(a,a,a)') "Usage: ", trim(prgName), & " startingBalance annualInterestRate minPaymentRate [fixedMinimum]" stop endif call getarg(1, string) read (string,*) startingBalance write (*,'(/a,f10.2)') "Starting balance = $", startingBalance end program ReadArgument Fortran 90 / 95 Programming
Fortran Intrinsic Functions Example Conversion to integer int(2.3) = 2 Starting position index(“abcd”,”cd”)=3 Rounding nint(2.5) = 3 Remove trailing blanks trim(“aa “) = “aa” Absolute value abs(-2.4) = 2.4 String length len(“aa “) = 3 Remainder mod(4,2) = 0 len_trim(“aa “) = 2 Maximum max(2,3) = 3 Return size of array size(array) Minimum min(2,3) = 2 Minimum element minval(array) Conversion to double dble(1) = 1.0d0 Maximum element maxval(array) Mathematical functions: sin, cos, tan, log, log10, exp, sqrt Presentation Title
Exercise: Sum up Even and Odd Numbers integer :: i, sumEven=0, sumOdd=0 ! Naive implementation do i = 1, 10 if (mod(i,2) == 0) then sumEven = sumEven + i else sumOdd = sumOdd + I endif eddo ! High-performance implementation sumEven = sumEven + mod(i+1,2) * i sumOdd = sumOdd + mod(i,2) * i enndo Fortran 90 / 95 Programming
Fortran Compiler Efficiency Which code is faster? do i = 1, n a(i) = b(i+1) c(i) = b(i+1) end do The code on the left side performs one less addition. Would it help? do i = 1, n i1 = i+1 a(i) = b(i1) c(i) = b(i1) end do Fortran 90 / 95 Programming
Fortran Compiler Efficiency Which code is faster? do i = 1, n a(i) = b(i+1) c(i) = b(i+1) end do The code on the left side performs one less addition. Would it help? Answer: Both codes have the same speed, because fortran compiler automatically eliminates redundant operations. But, code on the left is easier to read. Thus, it represents the best coding practice. do i = 1, n i1 = i+1 a(i) = b(i1) c(i) = b(i1) end do Fortran 90 / 95 Programming
Index Computation We are doing a(i,j) = b(i,j) * 2.0d0, but “a” is a one-dimensional array index = 0 do j = 1, jSize do i = 1, iSize index = index + 1 a(index) = b(i,j) * 2.0d0 end do Which code is better? do j = 1, jSize do i = 1, iSize index = (j-1)*iSize + i a(index) = i * j end do Fortran 90 / 95 Programming
Index Computation We are doing a(i,j) = b(i,j) * 2.0d0, but “a” is a one-dimensional array index = 0 do j = 1, jSize do i = 1, iSize index = index + 1 a(index) = b(i,j) * 2.0d0 end do Which code is better? Better for serial computation Better for parallel computation do j = 1, jSize do i = 1, iSize index = (j-1)*iSize + i a(index) = i * j end do Fortran 90 / 95 Programming
Exercise: Compile Loan Simulator ls –l Makefile loan.F90 main.F90 read.F90 Type in the command-line: module add make make ./loan.x 1000 7.2 1.0 200.0 Fortran 90 / 95 Programming
User Defined Data Type type fmmcub ! Declare new data type “fmmcube” integer :: parent integer :: xyz(3) integer :: atomStart, nAtoms double complex, allocatable :: multipoleExpansion(:) end type fmmcube integer :: nBoxes = 8, allocStat, nSzExpansion=10 type (fmmcube), allocatable :: box(:) ! Declare variable box using type fmmcube ! Perform two-level memory allocation allocate(box(0:nBoxes), stat=allocStat) do iBox = 1, nBoxes allocate(box(iBox)%multipoleExpansion(0:nSzExpansion), stat=allocStat) box(iBox)%multipoleExpansion = (0.0d0, 0.0d0) enddo Fortran 90 / 95 Programming
Useful Internet Resources Fortran 90 intrinsic functions http://www.nsc.liu.se/~boein/f77to90/a5.html Fortran 90 tutorial https://www.cac.cornell.edu/VW/Fintro/default.aspx More just Goooooogle Fortran 90 / 95 Programming
Let us know your opinion http://www.bitly.com/fiuworkshop Thank you !!! Presentation Title