April 13, 2015 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 2 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 3 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 4 Fortran Program Structure program program-name implicit none [declaration part] [execution part] end program program-name ! only one main program is defined subroutine subroutine-name ! contains commonly executed pieces of code implicit none [declaration part] [execution part] end subroutine subroutine-name Integer function function-name implicit none [declaration part] [execution part] end function function-name ! same as subroutine but used differently Fortran 90 / 95 Programming 5 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 6 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 7 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() end function Payment ! can be called from outside the module double precision function RoundToCents( amount ) end function RoundToCents end module module-name ! Not visible from outside Fortran 90 / 95 Programming 8 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 9 Fortran Conditional Statements if ( a > b ) then [execution part] elseif ( a .eq. b ) then [execution part] else ! a < b [execution part] end if conditional operators .lt. .le. .eq. .ne. .ge. .gt. < <= == /= >= > .and. .or. .not. Example if ( (a > b .and. b <= z) .or. .not. finishedSuccessfully ) then [execution part] end if Tip: Use indentation to improve readability of the code Fortran 90 / 95 Programming 10 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 [execution part] end do Example-2: do i = -5, 10, 2 ! Loop starts from i=-5; at the “end do” i=i+2; last loop i=9 [execution part] end do Example-3: do i = 10, 1, -1 ! Loop starts from i=10; at the “end do” i=i-1; last loop i=1 [execution part] end do Fortran 90 / 95 Programming 11 Fortran DO and WHILE loops Example-4: a = 5; b = 4; c = 1 do i = a, b, c [execution part] end do ! Attention: Loop will be skipped Rule: Fortran checks the loop exit condition (a <= b) before starting the iteration do while (a < b) [execution part] end do do i = a, b, c [execution part -1] if ( x == y ) cycle if ( m .ne. n ) exit [execution part-2] end do ! Loop will be continued as long as the condition is true ! If satisfied, skip part of the loop after this point ! If satisfied, exit the loop Fortran 90 / 95 Programming 12 Fortran Arrays program arrays implicit none integer, parameter integer double precision double precision, allocatable character (len=80) :: nRows = 5, nColumns = 3 :: allocStat :: a(nRows, nColumns) ! Static array :: b(:,:) ! Dynamic array :: 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 13 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 14 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 write(*,’(a8, i3, 3f6.2)’) label, index, x, y, z end program ReadFormattedText ! Read from standard input (console) ! Write to standard input Question: what will the result of write(*,’(a,i0)’) label, index Fortran 90 / 95 Programming 15 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 16 Fortran Intrinsic Functions Function Example Function 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 String length 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 17 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 do i = 1, 10 sumEven = sumEven + mod(i+1,2) * i sumOdd = sumOdd + mod(i,2) * i enndo Fortran 90 / 95 Programming 18 Fortran Compiler Efficiency Which code is faster? do i = 1, n a(i) = b(i+1) c(i) = b(i+1) end do do i = 1, n i1 = i+1 a(i) = b(i1) c(i) = b(i1) end do The code on the left side performs one less addition. Would it help? Fortran 90 / 95 Programming 19 Fortran Compiler Efficiency Which code is faster? do i = 1, n a(i) = b(i+1) c(i) = b(i+1) end do do i = 1, n i1 = i+1 a(i) = b(i1) c(i) = b(i1) 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. Fortran 90 / 95 Programming 20 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 end do do j = 1, jSize do i = 1, iSize index = (j-1)*iSize + i a(index) = i * j end do end do Which code is better? Fortran 90 / 95 Programming 21 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 end do do j = 1, jSize do i = 1, iSize index = (j-1)*iSize + i a(index) = i * j end do end do Which code is better? Better for serial computation Better for parallel computation Fortran 90 / 95 Programming 22 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 23 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(:) fmmcube ! Declare variable box using type ! 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 24 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 25 Let us know your opinion http://www.bitly.com/fiuworkshop Thank you !!! Presentation Title 26