{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python Fortran Rosetta Stone\n", "\n", "This shows Python/NumPy code side by side with Fortran. The Python code is simply executed directly. The Fortran code must be prefixed by the `%%fortran` magic, which is defined in the `fortranmagic.py` module, loaded by:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%load_ext fortranmagic" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we take the Fortran code, if it starts with `module` or `program`, we leave it untouched, compile, execute and show the output (or compiler errors if it fails to compile).\n", "\n", "If the code doesn't start with either `module` or `program`, then we intelligently prepend `implicit none` (i.e. after any possible `use` lines) and append `end`, that way you can write Fortran code directly." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## NumPy vs. Fortran" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 1" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from numpy import array, size, shape, min, max, sum\n", "a = array([1, 2, 3])\n", "print shape(a)\n", "print size(a)\n", "print max(a)\n", "print min(a)\n", "print sum(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(3,)\n", "3\n", "3\n", "1\n", "6\n" ] } ], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "integer :: a(3)\n", "a = [1, 2, 3]\n", "print *, shape(a)\n", "print *, size(a)\n", "print *, maxval(a)\n", "print *, minval(a)\n", "print *, sum(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 3\n", " 3\n", " 3\n", " 1\n", " 6\n", "\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 2" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from numpy import reshape\n", "a = reshape([1, 2, 3, 4, 5, 6], (2, 3))\n", "b = reshape([1, 2, 3, 4, 5, 6], (2, 3), order=\"F\")\n", "print a[0, :]\n", "print a[1, :]\n", "print\n", "print b[0, :]\n", "print b[1, :]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1 2 3]\n", "[4 5 6]\n", "\n", "[1 3 5]\n", "[2 4 6]\n" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "integer :: a(2, 3), b(2, 3)\n", "a = reshape([1, 2, 3, 4, 5, 6], [2, 3], order=[2, 1])\n", "b = reshape([1, 2, 3, 4, 5, 6], [2, 3])\n", "print *, a(1, :)\n", "print *, a(2, :)\n", "print *\n", "print *, b(1, :)\n", "print *, b(2, :)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 1 2 3\n", " 4 5 6\n", "\n", " 1 3 5\n", " 2 4 6\n", "\n" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 3" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from numpy import array, size, shape, max, min\n", "a = array([[1, 2, 3], [4, 5, 6]])\n", "print shape(a)\n", "print size(a, 0)\n", "print size(a, 1)\n", "print max(a)\n", "print min(a)\n", "print a[0, 0], a[0, 1], a[0, 2]\n", "print a[1, 0], a[1, 1], a[1, 2]\n", "print a" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(2, 3)\n", "2\n", "3\n", "6\n", "1\n", "1 2 3\n", "4 5 6\n", "[[1 2 3]\n", " [4 5 6]]\n" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "integer :: a(2, 3)\n", "a = reshape([1, 2, 3, 4, 5, 6], [2, 3], order=[2, 1])\n", "print *, shape(a)\n", "print *, size(a, 1)\n", "print *, size(a, 2)\n", "print *, maxval(a)\n", "print *, minval(a)\n", "print *, a(1, 1), a(1, 2), a(1, 3)\n", "print *, a(2, 1), a(2, 2), a(2, 3)\n", "print \"(3i5)\", transpose(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 2 3\n", " 2\n", " 3\n", " 6\n", " 1\n", " 1 2 3\n", " 4 5 6\n", " 1 2 3\n", " 4 5 6\n", "\n" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 4" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from numpy import array, dot\n", "a = array([[1, 2], [3, 4]])\n", "b = array([[2, 3], [4, 5]])\n", "print a * b\n", "print dot(a, b)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[ 2 6]\n", " [12 20]]\n", "[[10 13]\n", " [22 29]]\n" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "integer :: a(2, 2), b(2, 2)\n", "a = reshape([1, 2, 3, 4], [2, 2], order=[2, 1])\n", "b = reshape([2, 3, 4, 5], [2, 2], order=[2, 1])\n", "print *, a * b\n", "print *, matmul(a, b)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 2 12 6 20\n", " 10 22 13 29\n", "\n" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "module a\n", "implicit none\n", "\n", "integer :: i = 5\n", "\n", "contains\n", "\n", "integer function f(x) result(r)\n", "integer, intent(in) :: x\n", "r = x + 5\n", "end function\n", "\n", "integer function g(x) result(r)\n", "integer, intent(in) :: x\n", "r = x - 5\n", "end function\n", "\n", "end module\n", "\n", "program main\n", "use a, only: f, i\n", "implicit none\n", "print *, f(3)\n", "print *, i\n", "end program" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 8\n", " 5\n", "\n" ] } ], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Use of implicitly defined modules\n", "\n", "The `fortranmagic` implicitly defines two modules: `types` and `constants` (they contain code that most Fortran programmers tend define in all their projects one way or another):\n", "```fortran\n", "module types\n", "implicit none\n", "private\n", "public dp\n", "integer, parameter :: dp=kind(0.d0) ! double precision\n", "end module\n", "\n", "module constants\n", "use types, only: dp\n", "implicit none\n", "private\n", "public pi, e_, i_\n", "\n", "! Constants contain more digits than double precision, so that\n", "! they are rounded correctly. Single letter constants contain underscore so\n", "! that they do not clash with user variables (\"e\" and \"i\" are frequently used as\n", "! loop variables)\n", "real(dp), parameter :: pi = 3.1415926535897932384626433832795_dp\n", "real(dp), parameter :: e_ = 2.7182818284590452353602874713527_dp\n", "complex(dp), parameter :: i_ = (0, 1)\n", "end module\n", "```\n", "\n", "NOTE: The formatting above is wrong due to a bug in IPython.\n", "\n", "Here is how to use them:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "program test\n", "use types, only: dp\n", "implicit none\n", "real(dp) x\n", "x = 5.3_dp\n", "print *, x\n", "end" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 5.2999999999999998 \n", "\n" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "use types, only: dp\n", "real(dp) x\n", "x = 5.3_dp\n", "print *, x" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 5.2999999999999998 \n", "\n" ] } ], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Show the famous $e^{i \\pi}=-1$ relation using Fortran:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "use types, only: dp\n", "use constants, only: pi, i_\n", "complex(dp) x\n", "x = exp(pi*i_)\n", "print *, x" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " ( -1.0000000000000000 , 1.22464679914735321E-016)\n", "\n" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "and Python:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from cmath import exp, pi\n", "x = exp(pi*1j)\n", "print x" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(-1+1.22460635382e-16j)\n" ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Show compilation failures" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Undefined variables:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "print *, i ! undefined variable" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "err:\n", "a.f90:23.10:\n", "\n", "print *, i ! undefined variable\n", " 1\n", "Error: Symbol 'i' at (1) has no IMPLICIT type\n", "\n", "*** FAILED TO COMPILE ***\n" ] } ], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "use types, only: dp\n", "real(dp) :: x\n", "x = 5\n", "print *, x\n", "print *, i ! undefined variable" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "err:\n", "a.f90:27.10:\n", "\n", "print *, i ! undefined variable\n", " 1\n", "Error: Symbol 'i' at (1) has no IMPLICIT type\n", "\n", "*** FAILED TO COMPILE ***\n" ] } ], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Invalid code:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "integer :: i\n", "i = \"str\"" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "err:\n", "a.f90:24.4:\n", "\n", "i = \"str\"\n", " 1\n", "Error: Can't convert CHARACTER(1) to INTEGER(4) at (1)\n", "\n", "*** FAILED TO COMPILE ***\n" ] } ], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Show runtime failures\n", "\n", "Fortran checks bounds of arrays, both at compile time if it has enough information:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "use types, only: dp\n", "real(dp) x(5)\n", "x = [1, 2, 3, 4, 5]\n", "print *, \"OK:\", x\n", "x = [1, 2, 3, 4, 5, 6]\n", "print *, \"FAIL:\", x" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "err:\n", "a.f90:27:\n", "\n", "x = [1, 2, 3, 4, 5, 6]\n", "1\n", "Error: Different shape for array assignment at (1) on dimension 1 (5 and 6)\n", "\n", "*** FAILED TO COMPILE ***\n" ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "and at runtime, in debug mode (in this case Fortran actually also warns during compile time):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "use types, only: dp\n", "real(dp) x(5)\n", "x = [1, 2, 3, 4, 5]\n", "x(5) = 0\n", "print *, \"OK:\", x\n", "x(6) = 0 ! Fails" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "err:\n", "a.f90:28.2:\n", "\n", "x(6) = 0 ! Fails\n", " 1\n", "Warning: Array reference at (1) is out of bounds (6 > 5) in dimension 1\n", "\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " OK: 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 0.0000000000000000 \n", "\n", "err:\n", "At line 28 of file a.f90\n", "Fortran runtime error: Index '6' of dimension 1 of array 'x' above upper bound of 5\n", "\n", "Backtrace for this error:\n", " + /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7faf148e676d]\n", "\n", "Non-zero exit code: 2\n" ] } ], "prompt_number": 19 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here it only fails at runtime:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%fortran\n", "program test\n", "use types, only: dp\n", "implicit none\n", "real(dp) x(5)\n", "x = [1, 2, 3, 4, 5]\n", "call modify(x, 5)\n", "print *, \"OK:\", x\n", "call modify(x, 6) ! Fails\n", "\n", "contains\n", "\n", "subroutine modify(a, i)\n", "real(dp), intent(inout) :: a(:)\n", "integer, intent(in) :: i\n", "a(i) = 0\n", "end subroutine\n", "\n", "end program" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " OK: 1.0000000000000000 2.0000000000000000 3.0000000000000000 4.0000000000000000 0.0000000000000000 \n", "\n", "err:\n", "At line 36 of file a.f90\n", "Fortran runtime error: Index '6' of dimension 1 of array 'a' above upper bound of 5\n", "\n", "Backtrace for this error:\n", " + function modify (0x4008A1)\n", " at line 36 of file a.f90\n", " + function test (0x400A6F)\n", " at line 29 of file a.f90\n", " + /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f597521b76d]\n", "\n", "Non-zero exit code: 2\n" ] } ], "prompt_number": 20 } ], "metadata": {} } ] }