Skip to content

Commit

Permalink
Add function and class (OOP) examples to Python lesson (#108)
Browse files Browse the repository at this point in the history
* Minor text edits

* Add module with an example funtion

* Add example class to model diffusion

* Remove lint

* Update example to pass doctest

* Rename advanced Python section

* Swap the order of the last two topics
  • Loading branch information
mdpiper committed Apr 26, 2023
1 parent 9079dac commit 1ba1e4c
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 44 deletions.
5 changes: 3 additions & 2 deletions README.ipynb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "b56d3d13",
"metadata": {},
Expand Down Expand Up @@ -56,13 +57,13 @@
"1. [Python Fundamentals][python]\n",
"1. [Anaconda and conda][conda]\n",
"1. [Version Control with git and GitHub][git]\n",
"1. [Scientific Python][python]\n",
"1. [Python for Modeling][python]\n",
"1. [Landlab][landlab]\n",
"1. [The Basic Model Interface (BMI)][bmi]\n",
"1. [The Python Modeling Toolkit (pymt)][pymt]\n",
"1. [Permamodel Toolkit][permamodel]\n",
"1. [Best Practices in Scientific Software Development][best-practices]\n",
"1. [Introduction to Cluster Computing][hpc]\n",
"1. [Best Practices in Scientific Software Development][best-practices]\n",
"\n",
"The lessons can be run locally\n",
"if a user installs Anaconda and a `git` client on their computer.\n",
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ although the ordering below represents a typical progression.
1. [Python Fundamentals][python]
1. [Anaconda and conda][conda]
1. [Version Control with git and GitHub][git]
1. [Scientific Python][python]
1. [Python for Modeling][python]
1. [Landlab][landlab]
1. [The Basic Model Interface (BMI)][bmi]
1. [The Python Modeling Toolkit (pymt)][pymt]
1. [Permamodel Toolkit][permamodel]
1. [Best Practices in Scientific Software Development][best-practices]
1. [Introduction to Cluster Computing][hpc]
1. [Best Practices in Scientific Software Development][best-practices]

The lessons can be run locally
if a user installs Anaconda and a `git` client on their computer.
Expand Down
99 changes: 59 additions & 40 deletions lessons/python/8_diffusion.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,50 @@
},
{
"cell_type": "markdown",
"id": "9a275439",
"id": "2f1aba6f-1e74-45ce-9cfe-edbc68cedb48",
"metadata": {},
"source": [
"## Diffusion\n",
"### Introduction\n",
"# Diffusion\n",
"\n",
"The diffusion equation can be used to represent a great deal of natural\n",
"The diffusion equation can be used to represent a variety of natural\n",
"and environmental processes. It was introduced by Fourier in 1822 to\n",
"calculate the distribution of the temperature in materials and has later\n",
"been applied by Fick to material science. The mathematical expression\n",
"that we will derive can be used to model e.g. heat transfer in the\n",
"earth's crust, soil evolution, transport of contaminant in an aquifer or\n",
"in the atmosphere, erosion of mountain ranges, the evolution of glaciers\n",
"that we will derive can be used to model, e.g., heat transfer in the\n",
"earth's crust, soil evolution, transport of contaminants in an aquifer or\n",
"in the atmosphere, erosion of mountain ranges, the evolution of glaciers,\n",
"and many other phenomena. But before describing the equation directly,\n",
"we will investigate what diffusion actually means.\n",
"\n",
"Note: Lecture notes on diffusion are partly based on Prof. Dr. Frédéric Herman's course on geophysical processes. \n",
"@author: Benjamin Campforts\n",
"Note: The lecture notes on diffusion are partly based on Prof. Dr. Frédéric Herman's course on geophysical processes.\n",
"\n",
"#### Diffusion, what does it mean? \n",
"The following movie illustrates Brownian motion, we can\n",
"see that the equation to derive for diffusion must enable us to\n",
"represent the movement of molecules from a high concentration zone to a\n",
"zone of low concentration (Movie 1): \n",
"Author: Prof. Benjamin Campforts"
]
},
{
"cell_type": "markdown",
"id": "43856871-49e6-4232-8467-bedd91282d5c",
"metadata": {},
"source": [
"## Diffusion, what does it mean? \n",
"\n",
"The following movie illustrates Brownian motion.\n",
"We can see that the equation we intend to derive for diffusion must\n",
"represent the movement of molecules from a zone of high concentration to a\n",
"zone of low concentration.\n",
"\n",
"[![Brownian motion](./media/diffusion.png)](https://www.youtube.com/watch?v=UhL9OsRSKO8 \"Brownian motion\")\n",
"\n",
"**Movie 1:** Brownian motion causes food dye molecules to move throughout the water\n",
"**Movie 1:** Brownian motion causes food dye molecules to move throughout a solute.\n",
"\n",
"If we simplify this as a graph, we would get the following:\n",
"\n",
"If we simplify this is a graph, we would get the following: \n",
"<img src=\"./media/Diff_Fig1.png\" style=\"width:3in;height:2in\" />\n",
"\n",
"**Figure 1**: Diffusion is the movement of molecules from a high\n",
"concentration zone to a zone of low concentration due to random\n",
"processes. C represents the concentration; X is the horizontal distance\n",
"and q is the net particle flow.\n",
"**Figure 1**: Diffusion is the movement of molecules from high\n",
"to low concentrations due to random processes.\n",
"Here, `C` represents the concentration, `X` is the horizontal distance\n",
"and `q` is the net particle flow.\n",
"\n",
"Due to diffusion, the particles move from the black zone to the grey\n",
"zone. This can be explained by the fact that each particle can move at\n",
Expand All @@ -54,22 +62,30 @@
"and this as well in the gray region as the black region. However, at the\n",
"transition from the black zone to the grey zone, the probability of\n",
"seeing particles move from left to right is much larger than the\n",
"opposite (because there are much more black particles). This causes a\n",
"opposite, because there are many more black particles. This causes a\n",
"particle transfer that depends on the difference of concentration $\\Delta C$ and\n",
"the distance that the particle must travel $\\Delta x$, where $\\Delta C$ is the\n",
"difference of concentration in a transition zone of length $\\Delta x$.\n",
"difference of concentration in a transition zone of length $\\Delta X$.\n",
"Therefore, we can see that the flow of particles (i.e. the number of\n",
"particles passing through per unit surface and time (in 2D, mol m<sup>-1</sup>\n",
"s<sup>-1</sup>) will depend on the concentration gradient. Over time,\n",
"the concentration changes as illustrated in Figure 2.\n",
"\n",
"<img src=\"./media/Diff_Fig2.png\" style=\"width:3in;height:2in\" />\n",
"\n",
"**Figure 2:** Concentration changes over time due to diffusion\n",
"**Figure 2:** Concentration changes over time due to diffusion."
]
},
{
"cell_type": "markdown",
"id": "362cf137-6cbd-43dd-a932-46eb3378e52a",
"metadata": {},
"source": [
"## Exercise 1: modeling the random movement of particles\n",
"\n",
"### Exercise 1: modeling the random movement of particles\n",
"The goal of this first exercise is to model the process of diffusion through the random movement of particles.\n",
"\n",
"Start by importing some libraries we will use"
"Start by importing some libraries we will use."
]
},
{
Expand All @@ -91,9 +107,7 @@
"id": "7d94b533",
"metadata": {},
"source": [
"The goal of the first exercise is to replicate the process of diffusion by modeling the random movement of particles.\n",
"\n",
"First, create a vector (called `xp`) that contains 100000 particles, having a random value between -20 and 20. "
"Create a vector, `xp`, with 100000 particles with random values between -20 and 20. "
]
},
{
Expand All @@ -112,7 +126,7 @@
"id": "fb8aa5d6",
"metadata": {},
"source": [
"Represent this graphically using a histogram (use the `plt.hist()` function) and using the number of bins `xbins` (see below) in which you calculate the frequency (that is, the number of particles that is in each bin). Complete the code block below:"
"Represent this graphically using a histogram (use the `plt.hist()` function) and using the number of bins `xbins` (see below) in which you calculate the frequency (that is, the number of particles that is in each bin)."
]
},
{
Expand Down Expand Up @@ -212,17 +226,22 @@
},
{
"cell_type": "markdown",
"id": "fbcbfe6e",
"id": "c1393bef-2ab4-4c88-8d79-47016d463f51",
"metadata": {},
"source": [
"Now that you have an efficient solution, answer the following questions:\n",
"\n",
"1. Describe the evolution of the particles. How does the shape of the histogram evolve?\n",
"2. Why does the evolution of the histogram over time slows down?\n",
"3. What happens if the number of particles is reduced to 1000?\n",
"4. What happens if the distance of the displacement now varies randomly between -10 and 10? Why is this the case?\n",
"\n",
"\n",
"4. What happens if the distance of the displacement now varies randomly between -10 and 10? Why is this the case?"
]
},
{
"cell_type": "markdown",
"id": "87f9cb0a-7db4-4467-ae16-d29fdb0bc88c",
"metadata": {},
"source": [
"## Derivation of the diffusion equation\n",
"\n",
"In the previous exercise, we modeled a particle transfer assuming a random particle shift. The solution showed that the change in particle distribution depends on the concentration difference $\\Delta C$ and the distance the particle must travel $\\Delta x$, where $\\Delta C$ is the difference in concentration in the transition zone of length $\\Delta x$ (Figure 2).\n",
Expand All @@ -234,11 +253,11 @@
"$$q = -D\\frac{\\Delta C}{\\Delta x} \\label{eq:1} \\tag{1}$$\n",
"\n",
"\n",
"where $D$ corresponds to the diffusion coefficient $\\mathrm{(m^{2} s^{-1})}$, or the diffusivity. *C* represents the concentration or the number of elements in a 2-dimensional infinitesimal block $\\mathrm{(mol \\: m^{-2})}$. The diffusion coefficient will vary from one problem to another and defines the speed of particle transfer. Now, we would also like to know how the *concentration* changes during the calculations. Let's take an infinitesimal block with an incoming flow, and an outgoing flow (Figure 4).\n",
"where $D$ corresponds to the diffusion coefficient $\\mathrm{(m^{2} s^{-1})}$, or the diffusivity. *C* represents the concentration or the number of elements in a 2-dimensional infinitesimal block $\\mathrm{(mol \\: m^{-2})}$. The diffusion coefficient will vary from one problem to another and defines the speed of particle transfer. Now, we would also like to know how the *concentration* changes during the calculations. Let's take an infinitesimal block with an incoming flow, and an outgoing flow (Figure 3).\n",
"\n",
"<img src=\"./media/Diff_Fig4.png\" style=\"width:3in;height:2in\" />\n",
"\n",
"**Figure 4:** Infinitesimal block with an incoming flow, and an\n",
"**Figure 3:** Infinitesimal block with an incoming flow, and an\n",
"outgoing flow.\n",
"\n",
"As the concentration varies in the *X* direction, the flow will be\n",
Expand Down Expand Up @@ -289,7 +308,7 @@
"id": "7922e870",
"metadata": {},
"source": [
"### Exercise 2: Change in concentration due to diffusion\n",
"## Exercise 2: Change in concentration due to diffusion\n",
"\n",
"You will now solve the diffusion equation and write a code that allows us to solve this equation. The change in concentration will be calculated over a distance $Lx$. There are two ways to do this, we can either calculate the second derivative directly (i.e. the curvature), or do it in two steps by calculating the flux (i.e. the first derivative of the concentration) and then the derivative of the flux. We will use the second method because it is easier to calculate a first derivative than a second derivative.\n",
"\n",
Expand Down Expand Up @@ -468,14 +487,14 @@
"\n",
"<img src=\"./media/Eyjafjallajokull.jpg\" />\n",
"\n",
"**Figure** \"On March 2010 Eyjafjallajokull volcano in Iceland exploded into life, spewing lava, magma, rock and clouds of ash into the sky above it. The disaster grounded airlines, stranding holidaymakers and business passengers across Europe and North America. While many could only watch the crisis unfolding in hotels and airports, photographer Ragnar Th. Sigurdsson chose to fly into the epicentre on a mission to record one of nature's most deadly phenomena\" The Telegraph (c); Picture: RAGNAR TH. SIGURDSSON / BARCROFT \n",
"**Figure 5:** \"On March 2010 Eyjafjallajokull volcano in Iceland exploded into life, spewing lava, magma, rock and clouds of ash into the sky above it. The disaster grounded airlines, stranding holidaymakers and business passengers across Europe and North America. While many could only watch the crisis unfolding in hotels and airports, photographer Ragnar Th. Sigurdsson chose to fly into the epicentre on a mission to record one of nature's most deadly phenomena\" The Telegraph (c); Picture: RAGNAR TH. SIGURDSSON / BARCROFT \n",
"\n",
"Exercise: 1-D diffusion\n",
"**Exercise: 1D diffusion.**\n",
"The Eyjafjallajökull volcano is located at the Southern Iceland coast and 2000 km from Brussels. Consider a one-dimensional case with a domain length of 5000 km. The volcano itself is situated at 2220 km from the left boundary of the simulation domain. Brussels is situated at 4220 km from the left boundary of the simulation domain. Choose a spatial resolution of 20 km. In the next couple of steps, you will calculate the time required to obtain a specific ash concentration above Brussels. \n",
"\n",
"<img src=\"./media/Situation1D.png\" />\n",
"\n",
"**Figure:** 1D situation sketch\n",
"**Figure 6:** 1D situation sketch.\n",
"\n",
"Solve the spread of ash using the diffusion equation (Eq. 3)\n",
"\n",
Expand Down Expand Up @@ -593,7 +612,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.4"
"version": "3.9.7"
}
},
"nbformat": 4,
Expand Down
57 changes: 57 additions & 0 deletions lessons/python/ivy-diffusion/diffusion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Modeling the one-dimensional diffusion equation."""
import numpy as np


class Diffusion:

"""Model one-dimensional diffusion with fixed boundary conditions.
Examples
--------
>>> import numpy as np
>>> from diffusion import Diffusion
>>> m = Diffusion(diffusivity=0.25)
>>> m.concentration = np.zeros(m.shape)
>>> m.concentration[int(m.shape/2)] = 5
>>> m.concentration
array([ 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0,
0.0])
>>> m.time
0.0
>>> m.update()
>>> m.time
1.0
>>> m.concentration
array([ 0.0, 0.0, 0.0, 0.0, 1.2, 2.5, 1.2, 0.0, 0.0,
0.0])
"""

def __init__(self, shape=10, spacing=1.0, diffusivity=1.0):
"""Create a new diffusion model.
Parameters
---------
shape : int, optional
The number of nodes in the solution grid.
spacing : float, optional
Grid spacing.
diffusivity : float, optional
Diffusivity.
"""
self.shape = shape
self.spacing = spacing
self.diffusivity = diffusivity
self.time = 0.0
self.time_step = self.spacing**2 / (4.0 * self.diffusivity)

self.concentration = np.random.random(self.shape)

def solve(self):
"""Solve the 1D diffusion equation."""
flux = -self.diffusivity * np.diff(self.concentration) / self.spacing
self.concentration[1:-1] -= self.time_step * np.diff(flux) / self.spacing

def update(self):
"""Calculate concentration at the next time step."""
self.solve()
self.time += self.time_step
61 changes: 61 additions & 0 deletions lessons/python/ivy-diffusion/solver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""A solver for the one-dimensional diffusion equation."""
import numpy as np

np.set_printoptions(formatter={"float": "{: 5.1f}".format})


def solve1d(concentration, spacing=1.0, time_step=1.0, diffusivity=1.0):
"""Solve the one-dimensional diffusion equation with fixed boundary conditions.
Parameters
----------
concentration : ndarray
The quantity being diffused.
spacing : float (optional)
Grid spacing.
time_step : float (optional)
Time step.
alpha : float (optional)
Diffusivity.
Returns
-------
result : ndarray
The temperatures after time *time_step*.
Examples
--------
>>> import numpy as np
>>> from solver import solve1d
>>> z = np.zeros(5)
>>> z[2] = 5
>>> solve1d(z, diffusivity=0.25)
array([ 0.0, 1.2, 2.5, 1.2, 0.0])
"""
flux = -diffusivity * np.diff(concentration) / spacing
concentration[1:-1] -= time_step * np.diff(flux) / spacing

return concentration


def _run_example():
"""An example of running solve1d."""
print(_run_example.__doc__)
D = 100
Lx = 10
dx = 0.5
C1 = 500
C2 = 0
C = np.empty(Lx)
C[: int(Lx / 2)] = C1
C[int(Lx / 2) :] = C2
dt = dx * dx / D / 2.1
print("Time = 0\n", C)

for t in range(1, 3):
solve1d(C, dx, dt, D)
print(f"Time = {t}\n", C)


if __name__ == "__main__":
_run_example()

0 comments on commit 1ba1e4c

Please sign in to comment.