{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to Programming in Python: Functions\n", "\n", "This practical is the final one in our exploration of basic concepts in programming. It builds on the previous 3. It is based on an almagamation of course and examples, including the following (which you are welcome to explore on your own!):\n", "1. Introduction to programming for Geoscientists (with Python) by Gerard Gorman and Christian Jacobs: http://ggorman.github.io/Introduction-to-programming-for-geoscientists/lecture_series/\n", "2. Introduction to scientific programming in Python by the UCL graduate school: http://www.cs.ucl.ac.uk/scipython/index.html\n", "3. Programming with Python by Software Carpentry: http://swcarpentry.github.io/python-novice-inflammation/\n", "4. CS For All: Introduction to Computer Science and Python Programming by HarveyMuddX at edX: https://www.edx.org/course/cs-all-introduction-computer-science-harveymuddx-cs005x-0\n", "\n", "**Recommended Reading**: *Think Python*, Sections [3.1](http://greenteapress.com/thinkpython/html/thinkpython004.html#toc24), [3.5](http://greenteapress.com/thinkpython/html/thinkpython004.html#toc28)-[3.9](http://greenteapress.com/thinkpython/html/thinkpython004.html#toc32), [6.1](http://greenteapress.com/thinkpython/html/thinkpython007.html#toc66) and *SciPy Lecture Notes*, Sections [1.2.4.1](http://www.scipy-lectures.org/intro/language/functions.html#function-definition)-[1.2.4.3](http://www.scipy-lectures.org/intro/language/functions.html#parameters)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# MAKE SURE TO EXECUTE THIS CELL BEFORE YOU START YOUR WORK!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy\n", "import matplotlib.pyplot as pyplot\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 1a\n", "\n", "The function we defined in the main notebook (**`F_to_C`**) is copied below. First, execute the function cell so that the function has been defined in this notebook." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def F_to_C(Temp_in_F):\n", " Temp_in_C = (5.0/9.0)*(Temp_in_F-32)\n", " return Temp_in_C" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, convince yourself that you understand how to call a function by using the function we have already defined (**`F_to_C`**) to calculate the temperature in degrees Celsius when the temperature in Fahrenheit is:\n", "- 0\n", "- 32\n", "- 99\n", "

\n", "\n", "Try using different variable names each time.\n", "\n", "***You do not need to redefine the function. Just use it with different input values for F.***\n", "\n", "Check your answer using Google." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 1b\n", "\n", "Let's take a closer look at the syntax of function definitions by - as usual - finding out what kind of errors we get when we make a mistake.\n", "\n", "Try out each of the examples below without changing anything so you see the error message, then fix the error. Also add a comment explaining what the error was." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**i. Original**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Define the function\n", "def F_to_C(Temp_in_F)\n", " Temp_in_C = (5.0/9.0)*(Temp_in_F-32)\n", " return Temp_in_C\n", "\n", "# Test the function\n", "print( F_to_C(100) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**i. Fixed**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**ii. Original**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Define the function\n", "def F_to_C(Temp_in_F):\n", " Temp_in_C = (5.0/9.0)*(F_Temp-32)\n", " return Temp_in_C\n", "\n", "# Test the function\n", "print( F_to_C(100) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**ii. Fixed**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**iii. Original**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Define the function\n", "def F_to_C(Temp_in_F):\n", " Temp_in_C = (5.0/9.0)*(Temp_in_F-32)\n", " return Temp_in_C\n", "\n", "# Test the function\n", "print( F_to_C_conversion(100) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**iii. Fixed**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**iv. Original**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Define the function\n", "def F_to_C(Temp_in_F):\n", " Temp_in_C = (5.0/9.0)*(Temp_in_F-32)\n", " return\n", "\n", "# Test the function\n", "print( F_to_C(100) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**iv. Fixed**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**v. Original**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Define the function\n", "def F_to_C(Temp_in_F):\n", " Temp_in_C = (5.0/9.0)*(Temp_in_F-32)\n", "return Temp_in_C\n", "\n", "# Test the function\n", "print( F_to_C(100) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**v. Fixed**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 2a
\n", "\n", "Recall that once we know the solar flux $S$ at a given distance $r$, we can also calculate the effective temperature of a planet $T_e$ in Kelvin (in the absence of an atmosphere):\n", "$$T_e(r) = \\left (\\dfrac{S}{4\\times\\sigma}\\times(1-A) \\right )^{0.25}$$\n", "\n", "where:

\n", "\n", "- $\\sigma$ is the Stefan-Boltzmann constant, equal to $5.67\\times 10^{-8}$ W/m$^2$/K$^4$
\n", "- $A$ is the albedo (the amount of solar energy that is reflected by the planet's surface), and is unitless. For now, you can assume $A$ = 0.3.

\n", "\n", "1. Adapt the function `solar_flux` (copied below), so that ***after*** it calculates $S$, it then calculates $T_e$. (**Hint**: leave the existing lines intact but add an extra line after the line that starts `S=`...)

\n", "\n", "2. Give the function a new name (suggested name: effective_temperature), and make sure that it takes $r$ as input and returns $T_e$ as output.

\n", "\n", "3. Test your function by **calling** (i.e. using) it for $r$ values between 1 and 20. Remember, after you ***define*** the function you need to ***use*** the function to get output!

\n", "\n", "4. Plot the result with $T_e$ on the y-axis and $r$ on the x-axis.

\n", "\n", "**Hint**: We programmed this equation in the Week 2 practical. If you want to save yourselves a headache now, copy the function from that practical. *(Side note: when you're programming, you should always look for shortcuts like this that reduce the risk of errors.*)


\n", "\n", "**Extra**: You can actually call one function within another function - so you could leave the function `solar_flux` intact, and use it inside your new `effective_temperature` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Function to compute the solar flux at a given distance\n", "def solar_flux(r):\n", "\n", " # Define constant variables\n", " r0 = 1.00 # Distance from sun to Earth in AU\n", " S0 = 1366 # Solar flux at Earth\n", " \n", " # Add Albedo and sigma\n", " A = 0.3 # albedo, unitless\n", " sigma = 5.67e-8 # Stefan-Boltzmann constant, in W/m2/K4\n", "\n", " # Use the equation to calculate the solar flux\n", " S = S0*(r0/r)**2\n", " \n", " # return solar flux S\n", " return S" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Call the function\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Plot the result\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 2b
\n", "\n", "1. Copy your function from Exercise 2a and adapt it so that it returns **both $S$ and $T_e$** as outputs. (**Hint**: You only need to change ONE line!)

\n", "\n", "2. Call (use) your function with $r$ values between 1 and 20, storing the $S$ and $T_e$ output in **two** new variables .

\n", "\n", "3. Plot the output with $S$ on the x-axis and $T_e$ on the y-axis.
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Copy and adapt the function\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Call the function\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Plot the result\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 2c
\n", "\n", "1. Copy your function from Exercise 2b and adapt it so that the albedo (`A` in the equation) becomes an additional input argument (instead of being set as a constant in the function).

\n", "\n", "2. Call (use) your function with $A$ = 0.3 and $r$ values between 1 and 20, storing the $S$ and $T_e$ output and plotting $T_e$ as a function of $r$ (this should look just like the plot in 2a, with $T_e$ on the y-axis and $r$ on the x-axis).

\n", "\n", "3. Repeat step 2, but this time with A=0.9 (an icy planet!). Does the temperature look different? (**Hint**: it should -- check the y-axis values!)
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Copy and adapt the function\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Call the function with A = 0.3 and plot the result\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "scrolled": true }, "outputs": [], "source": [ "# Call the function with A = 0.9 and plot the result\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 2d
\n", "\n", "\n", "1. Copy your function from Exercise 2c and adapt it so that the albedo (`A`) has a default value of 0.3.

\n", "\n", "\n", "2. Call (use) the function for $r$ values between 1 and 20, and plot temperature ($T_e$) as a function of distance ($r$). Do this three different times:
\n", "A. Specify in your call that A = 0.3
\n", "B. Do not specify a value for A
\n", "C. Specify that A = 0.6

\n", "\n", "The temperatures that you find for A and B should be the same. The temperature that you find for C should be colder!
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Copy and adapt the function\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# A. Call the function specifying A = 0.3 and plot the result\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# B. Call the function without specifying A and plot the result\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "scrolled": true }, "outputs": [], "source": [ "# C.Call the function specifying A = 0.6 and plot the result\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 2e
\n", "\n", "\n", "Copy the code you used to make the final plot from Exercise 2d here and modify it so that it:
\n", "- Uses any color **except** red or blue (bonus points for creativity!).
\n", "- Shows points and the line through them
\n", "- Zooms in on the region between 5 and 15 AU.
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## EXERCISE 3: BRINGING IT ALL TOGETHER
\n", "\n", "This final exercise is designed to give you a chance to practice everything you have learned so far today (and in the last few weeks). Make sure to spend time thinking about what your answers **mean**.\n", "\n", "This week, we will continue developing an understanding of Daisyworld (look back to the previous practicals and/or the textbook if you don't remember!). Two weeks ago, we made a plot that showed how the temperature of the Daisyworld planet changed as the number of daisies increased. Last week, we made a plot that showed how daisy growth changes as temperature increases.

\n", "\n", "This time we will start putting these two ideas together.

\n", "\n", "### EXERCISE 3a
\n", "We will start by writing a **function** that calculates the temperature of the planet when the fraction covered by daisies is provided as an input.\n", "\n", "Luckily, we have already written most of the code! Back in Week 3 (Exercise 5), we determined that **if we know what fraction of the planet is covered by flowers (`frac_flower`) we can calculate the temperature (`Te`**):" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "# Define the albedos of flowers and the albedo of soil (unitless)\n", "albedo_flower = 0.75\n", "albedo_soil = 0.4\n", "\n", "# The fraction covered by soil is the rest of the planet, or 1.0 - the fraction covered by flowers\n", "frac_soil = 1.0 - frac_flower\n", "\n", "# The albedo is the sum of the two albedos after each has been multiplied by its fractional coverage.\n", "albedo = frac_soil * albedo_soil + frac_flower * albedo_flower\n", "\n", "# Define the solar flux on Daisyworld, in W/m2\n", "S = 3700.0\n", "\n", "# Define the Stefan-Boltzmann constant, in W/m2/K4\n", "sigma = 5.67e-8\n", "\n", "# Define the temperature as a function of the albedo\n", "Te = ((S*(1-albedo))/(4*sigma))**0.25" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**For this exercise:**\n", "1. Copy the code above and modify it so that it becomes a function that takes the fraction of the planet covered by daisies as an **input** and returns the temperature as an **output.** (**Hint**: what does a function need? Think about function names, indentations, colons, arguments and return values...)

\n", "2. To test that it is working, call (use) the function to find the temperature when:
\n", "a. 50% of the planet is covered by daisies (i.e., the fraction covered is 0.5).
\n", "b. 80% of the planet is covered by daisies (i.e., the fraction covered is 0.8).
\n", "\n", "**Hint:** If in step 2 above a and b give you the same value, or you get more than one temperature value as output, then you will know something has gone wrong.\n", "\n", "***Do not delete the %reset in the cell below*** (this makes sure your program isn't just \"remembering\" something you did before)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "%reset -s -f\n", "import numpy\n", "import matplotlib.pyplot as pyplot\n", "%matplotlib inline\n", "\n", "# Define your function here\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Call your function here\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### EXERCISE 3b
\n", "Now we will write a **function** that calculates the growth rate of daisies when the temperature of the planet is provided as an input.\n", "\n", "Recall from Week 4 that the growth rate of the ***population*** of flowers (in units of *fraction of the planet covered by flowers / year*) is defined as:\n", "$$1-0.005 \\times (295.5-T_e)^2$$\n", "and **can never be below zero** (this would represent daisy death, which we will deal with separately).

\n", "\n", "Good news! We already wrote most of this code in Week 4 (Exercise 5). **If we know the temperature of the planet in Kelvin (`Te`), we can calculate the growth rate (`growth_rate`)**:" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "# Test condition for temperature and calculate growth rate\n", "if Te <= 281:\n", " growth_rate=0\n", "elif Te < 310:\n", " growth_rate=1-0.005*(295.5-Te)**2\n", "else:\n", " growth_rate=0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(Some of you might notice this is simpler than the version we used before - that is because we were working with a whole array of temperature values, but now we will just need to use one at a time." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**For this exercise:**
\n", "1. Copy the code above and modify it so that it becomes a function that takes the temperature of the planet as an **input** and returns the growth rate as an **output.**

\n", "\n", "2. To test that it is working, call (use) the function to find the growth rate when:
\n", "a. the temperature is 289 K
\n", "b. the temperature is 269 K

\n", "\n", "3. At which temperature are the daisies growing faster, and why?

\n", "\n", "**Hint:** If the two different temperature inputs in 3 give you the same value, or you get more than one value as output, then you will know something has gone wrong." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Define your function here\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Call your function here\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Answer the question here\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### EXERCISE 3c
\n", "You might remember from last week that **flowers die at a constant rate of 0.3** (fraction/year).\n", "\n", "Using your two functions, you are now going to experiment with different values for the fraction of the planet covered by daisies. For each experiment you should:\n", "1. First calculate the temperature of the planet.\n", "2. Use that temperature to calculate the flower growth rate.\n", "\n", "Note that the way we have set up these functions, you can only use ONE input value -- they won't work with arrays. So here you are just going to pick some random values for the fraction of the planet covered by flowers and use the functions you've already written to test them, one at a time.\n", "\n", "Here's an example, using what we've already found in 3a and 3b. First, we wanted to understand what happens when we start with 0.5 of the planet covered by flowers. In 3a, we used the function defined in 3a with 0.5 as input to calculate the effective temperature. We found that the effective temperature in that scenario was about 289 K. Then in 3b we used the function defined in 3b with 289 K as input to calculate the growth rate. We found the growth rate was about 0.79. In other words, by using our two functions one after another, we found that with 0.5 fractional coverage, the temperature is 289 K and flowers are growing at a rate of 0.79.\n", "\n", "We did the same thing starting with a starting fraction of 0.8. We called the first function with 0.8 as input (3a), found an effective temperature of 269 K, and used that as input to the second function (3b) to find a growth rate of 0. At 0.8 fractional coverage, the temperature is 269 K and the growth rate is 0 (i.e. flowers are not growing).\n", "\n", "Your job is to repeat this process choosing different numbers as your starting point. We already know that at 0.5 coverage flowers are growing rapidly, and at 0.8 coverage they are not growing at all. Test out some different numbers (your choice!) to answer the following questions:\n", "1. For what range of initial daisy coverage values are the flowers **increasing** in area (i.e. growth > death)? Why?\n", "2. In that range (when flowers are increasing), is the temperature of the planet likely to get warmer or colder?\n", "3. For what range of daisy coverage values are the flowers **decreasing** in area? Why? What does that mean for the temperature?\n", "\n", "Use comments to show your thinking as you experiment. You can more cells if you like.\n", "\n", "**Hint**: DO NOT re-define your functions. All you need to do now is call them with different input values." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Call your functions here.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Extra cell to run more experiments if desired\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Extra cell to run more experiments if desired\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Extra cell to run more experiments if desired\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Extra cell to run more experiments if desired\n", "\n", "# To add even more, use the + symbol above (underneath \"File\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Answer the questions here\n", "\n", "# Q1\n", "#---\n", "# \n", "#\n", "#\n", "#\n", "\n", "# Q2\n", "#---\n", "# \n", "#\n", "#\n", "#\n", "\n", "# Q3\n", "#---\n", "# \n", "#\n", "#\n", "#" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.4" } }, "nbformat": 4, "nbformat_minor": 1 }