{ "metadata": { "name": "Revision-1-Introduction-to-programming-for-geoscientists-Solutions" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Introduction to programming for Geoscientists (through Python)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#Revision Workshop 1 - Solutions\n", "\n", "[Gerard J. Gorman](http://www.imperial.ac.uk/people/g.gorman) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Find errors in the coding of formulas**
\n", "Some versions of the program for calculating the formula\n", "$$F = \\frac{9}{5}C + 32$$\n", "are listed below. Determine which versions will not work correctly and explain why in each case." ] }, { "cell_type": "code", "collapsed": false, "input": [ "C = 21; F = 9/5*C + 32; print F # This will not work as expected because \"9/5\" will give a value of 1, not 1.8, due to integer division.\n", "C = 21.0; F = (9/5)*C + 32; print F # Same as above\n", "C = 21.0; F = 9*C/5 + 32; print F # This works fine\n", "C = 21.0; F = 9.*(C/5.0) + 32; print F # This works fine\n", "C = 21.0; F = 9.0*C/5.0 + 32; print F # This works fine\n", "C = 21; F = 9*C/5 + 32; print F # This will not work because of integer division problems in the expression \"C/5\".\n", "C = 21.0; F = (1/5)*9*C + 32; print F # This will not work because of integer division problems in the expression \"1/5\".\n", "C = 21; F = (1./5)*9*C + 32; print F # This works fine" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "53\n", "53.0\n", "69.8\n", "69.8\n", "69.8\n", "69\n", "32.0\n", "69.8\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Index a nested lists**
\n", "We define the following nested list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "q = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h']]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Index this list to extract 1) the letter *a*; 2) the list *['d', 'e', 'f']*; 3) the last element *h*; 4) the *d* element. Explain why *q[-1][-2]* has the value *g*." ] }, { "cell_type": "code", "collapsed": false, "input": [ "q = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h']]\n", "print q[0][0] # Select the first list in q, then the first element in that list.\n", "print q[1] # Select the entire second list in q. Remember that the second element has an index of 1 because Python indexing starts at 0.\n", "print q[len(q)-1][1] # Remember: index 0 corresponds to the first element, and index len(q)-1 corresponds to the last element (of q).\n", "print q[1][0] # First element of the second list in q.\n", "\n", "# Both \"q[len(q)-1]\" and \"q[-1]\" can be used to extract the last element in q. \n", "# Then, within the sub-list q[-1], the element with index \"-2\" is the second last element.\n", "# So q[-1][-2] selects the last list in q, and the second last element within that list." ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "a\n", "['d', 'e', 'f']\n", "h\n", "d\n" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Implement the sum function**
\n", "The standard Python function called *sum* takes a list as argument and computes the sum of the elements in the list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "sum([1,3,5,-5])" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 1, "text": [ "4" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Implement your own version of *sum*." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def sum_new(l):\n", " s = 0 # A variable to hold the sum as we loop over the elements in the list l\n", " for element in l:\n", " s += element # Add each element onto the running total 's'.\n", " return s # Return the result\n", "\n", "print sum_new([1, 3, 5, -5])" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "4\n" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Construct a double for loop over a nested list**
\n", "Consider the list *q* defined earlier. Construct a double *for* loop (i.e. a loop within a loop) to print out all of the elements in the nested list." ] }, { "cell_type": "code", "collapsed": false, "input": [ "q = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h']]\n", "\n", "for i in range(0, len(q)):\n", " sublist = q[i]\n", " for j in range(0, len(sublist)):\n", " print \"q[%d][%d] = %s\" % (i, j, q[i][j])" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "q[0][0] = a\n", "q[0][1] = b\n", "q[0][2] = c\n", "q[1][0] = d\n", "q[1][1] = e\n", "q[1][2] = f\n", "q[2][0] = g\n", "q[2][1] = h\n" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **How to cook the perfect egg**
\n", "As an egg cooks, the proteins first denature and then coagulate. When the temperature exceeds a critical point, reactions begin and proceed faster as the temperature increases. In the egg white the proteins start to coagulate for temperatures above 63 C, while in the yolk the proteins start to coagulate for temperatures above 70 C. For a soft boiled egg, the white needs to have been heated long enough to coagulate at a temperature above 63 C, but the yolk should not be heated above 70 C. For a hard boiled egg, the center of the yolk should be allowed to reach 70 C. The following formula expresses the time $t$ it takes (in seconds) for the center of the yolk to reach the temperature $T_y$ (in Celsius degrees):\n", "\n", "$$t = \\frac{M^{2/3}c\\rho^{1/3}}{K\\pi^2(4\\pi/3)^{2/3}}\\ln\\left[0.76\\frac{T_o - T_w}{T_y - T_w}\\right]$$\n", "\n", "Here, $M, \\rho, c$ and $K$ are properties of the egg: $M$ is the mass, $\\rho$ is the density, $c$ is the specific heat capacity, and $K$ is thermal conductivity. Relevant values are $M$ = 47 g for a small egg and $M$ = 67 g for a large egg, $\\rho$ = 1.038 g cm$^{-3}$, $c$ = 3.7 J g$^{-1}$K$^{-1}$, and $K$ = 5.4 $\\times$ 10$^{-3}$ W cm$^{-1}$ K$^{-1}$. Furthermore, $T_w$ is the temperature (in C degrees) of the boiling water, and $T_o$ is the original temperature (in C degrees) of the egg before being put in the water. Implement the formula in a program, set $T_w$ = 100 C and $T_y$ = 70 C, and compute $t$ for a large egg taken from the fridge ($T_o$ = 4 C) and from room temperature ($T_o$ = 20 C). \n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from math import pi, log\n", "\n", "def t(Tw, Ty, To):\n", " # Tw: Temperature of the water\n", " # Ty: Desired temperature of the yolk\n", " # To: Initial temperature of the egg\n", " rho = 1.038 # g cm^{-3}\n", " M = 67 # g\n", " K = 5.4e-3 # W cm^{-1} K^{-1}\n", " c = 3.7 # J g^{-1} K^{-1}\n", "\n", " t = (M**(2.0/3.0)*c*rho**(1.0/3.0))/(K*(pi**2)*(4.0*pi/3.0)**(2.0/3.0))*log(0.76*(To - Tw)/(Ty - Tw))\n", " return t\n", "\n", "print \"Time required when To = %d degrees: %.2f seconds.\" % (4, t(100.0, 70.0, 4)) # To = 4\n", "print \"Time required when To = %d degrees: %.2f seconds.\" % (20, t(100.0, 70.0, 20)) # To = 20" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Time required when To = 4 degrees: 396.58 seconds.\n", "Time required when To = 20 degrees: 315.22 seconds.\n" ] } ], "prompt_number": 11 }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Implement the factorial function**
\n", "The factorial of $n$, written as $n!$, is defined as\n", "\n", "$$n! = n(n \u2212 1)(n \u2212 2) \\cdots 2 \\cdot 1,$$\n", "\n", "with the special cases\n", "\n", "$$1! = 1,$$ $$0! = 1.$$\n", "\n", "For example, $4! = 4 \\cdot 3 \\cdot 2 \\cdot 1 = 24$, and $2! = 2 \\cdot 1 = 2$. Write a function *fact(n)* that returns $n!$. Return 1 immediately if $n$ is 1 or 0, otherwise use a loop to compute $n!$." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def fact(n):\n", " if(n == 1 or n == 0):\n", " return 1\n", " else:\n", " product = 1 # This variable keeps track of the product n * (n-1) * (n-2) * ... * 1\n", " while n > 1:\n", " product *= n\n", " n -= 1 # Keep decreasing n until we reach 1, then return the result held in the variable 'product'.\n", " return product\n", "print \"%d! = %d\" % (4, fact(4))\n", "print \"%d! = %d\" % (2, fact(2))\n", "print \"%d! = %d\" % (1, fact(1))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "4! = 24\n", "2! = 2\n", "1! = 1\n" ] } ], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Add error checking**
\n", "Add in a try-except block to the function *fact(n)*. An exception should be thrown/raised if the number *n* is negative. If an exception occurs, your program should print a helpful error message and quit." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def fact(n):\n", " try:\n", " if(n < 0):\n", " raise ValueError\n", " elif(n == 1 or n == 0):\n", " return 1\n", " else:\n", " product = 1 # This variable keeps track of the product n * (n-1) * (n-2) * ... * 1\n", " while n > 1:\n", " product *= n\n", " n -= 1 # Keep decreasing n until we reach 1, then return the result held in the variable 'product'.\n", " return product\n", " except ValueError:\n", " raise ValueError(\"n must be greater than or equal to 0.\")\n", " sys.exit(1)\n", "\n", "print \"%d! = %d\" % (-1, fact(-1)) # This should cause a ValueError exception." ], "language": "python", "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "n must be greater than or equal to 0.", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 17\u001b[1;33m \u001b[1;32mprint\u001b[0m \u001b[1;34m\"%d! = %d\"\u001b[0m \u001b[1;33m%\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfact\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# This should cause a ValueError exception.\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;32m\u001b[0m in \u001b[0;36mfact\u001b[1;34m(n)\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mproduct\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 14\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"n must be greater than or equal to 0.\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 15\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mValueError\u001b[0m: n must be greater than or equal to 0." ] } ], "prompt_number": 21 }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **Compute the length of a path**
\n", "Some object is moving along a path in the plane. At $n$ points of time we have recorded the corresponding $(x, y)$ positions of the object:\n", "$(x_0, y_0), (x_1, y_1), \\ldots, (x_{n-1}, y_{n-1})$. The total length $L$ of the path from $(x_0, y_0)$ to $(x_{n-1}, y_{n-1})$ is the sum of all the individual line segments $(x_{i-1}, y_{i-1})$ to $(x_i, y_i)$, $i = 1, \\ldots, n-1$:\n", "\n", "$$L = \\sum_{i=1}^{n-1}{\\sqrt{(x_i - x_{i-1})^2 + (y_i - y_{i-1})^2}}.$$\n", "\n", "Make a function *pathlength(x, y)* for computing $L$ according to the formula. The arguments $x$ and $y$ hold all the $x_0, \\ldots, x_{n-1}$ and $y_0, \\ldots, y_{n-1}$ coordinates, respectively. Test the function on a triangular path with the four points (1, 1), (2, 1), (1, 2), and (1, 1)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from math import sqrt\n", "def pathlength(x,y):\n", " L = 0 \n", " for i in range(1, len(x)):\n", " L += sqrt( (x[i] - x[i-1])**2 + (y[i] - y[i-1])**2 )\n", " return L \n", "\n", "x = [1, 2, 1, 1]\n", "y = [1, 1, 2, 1]\n", "print pathlength(x, y)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "3.41421356237\n" ] } ], "prompt_number": 22 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }