XClose
Menu

Classroom exercise: energy calculation

Diffusion model in 1D

Description: A one-dimensional diffusion model. (Could be a gas of particles, or a bunch of crowded people in a corridor, or animals in a valley habitat...)

  • Agents are on a 1d axis
  • Agents do not want to be where there are other agents
  • This is represented as an 'energy': the higher the energy, the more unhappy the agents.

Implementation:

  • Given a vector $n$ of positive integers, and of arbitrary length
  • Compute the energy, $E(n) = \sum_i n_i(n_i - 1)$
  • Later, we will have the likelyhood of an agent moving depend on the change in energy.
In [1]:
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline

density =  np.array([0, 0, 3, 5, 8, 4, 2, 1])
fig, ax = plt.subplots()
ax.bar(np.arange(len(density))-0.5, density)
ax.xrange=[-0.5, len(density)-0.5]
ax.set_ylabel("Particle count $n_i$")
ax.set_xlabel("Position $i$")
Out[1]:
Text(0.5, 0, 'Position $i$')

Here, the total energy due to position 2 is $3 (3-1)=6$, and due to column 7 is $1 (1-1)=0$. We need to sum these to get the total energy.

Starting point

Create a Python module:

In [2]:
%%bash
mkdir -p diffusion
touch diffusion/__init__.py
  • Implementation file: diffusion_model.py
In [3]:
%%writefile diffusion/model.py
def energy(density, coeff=1.0):
  """ Energy associated with the diffusion model

      Parameters
      ----------

      density: array of positive integers
          Number of particles at each position i in the array
      coeff: float
          Diffusion coefficient.
  """
  # implementation goes here
Overwriting diffusion/model.py
  • Testing file: test_diffusion_model.py
In [4]:
%%writefile diffusion/test_model.py
from .model import energy
def test_energy():
  """ Optional description for nose reporting """
  # Test something
Overwriting diffusion/test_model.py

Invoke the tests:

In [5]:
%%bash
cd diffusion
py.test
============================= test session starts ==============================
platform linux -- Python 3.6.3, pytest-4.1.1, py-1.5.2, pluggy-0.8.1
rootdir: /home/travis/build/alan-turing-institute/rsd-engineeringcourse/ch03tests/diffusion, inifile:
plugins: cov-2.6.1
collected 1 item

test_model.py .                                                          [100%]

=========================== 1 passed in 0.02 seconds ===========================

Now, write your code (in model.py), and tests (in test_model.py), testing as you do.

Solution

Don't look until after you've tried!

In [6]:
%%writefile diffusion/model.py
"""  Simplistic 1-dimensional diffusion model """

def energy(density):
  """ Energy associated with the diffusion model
      :Parameters:
        density: array of positive integers
           Number of particles at each position i in the array/geometry
  """
  from numpy import array, any, sum

  # Make sure input is an numpy array
  density = array(density)

  # ...of the right kind (integer). Unless it is zero length, 
  #    in which case type does not matter.
    
  if density.dtype.kind != 'i' and len(density) > 0:
    raise TypeError("Density should be a array of *integers*.")
  # and the right values (positive or null)
  if any(density < 0):
    raise ValueError("Density should be an array of *positive* integers.")
  if density.ndim != 1:
    raise ValueError("Density should be an a *1-dimensional*"+
                     "array of positive integers.")
  
  return sum(density * (density - 1))
Overwriting diffusion/model.py
In [7]:
%%writefile diffusion/test_model.py
""" Unit tests for a diffusion model """

from pytest import raises
from .model import energy

def test_energy_fails_on_non_integer_density():
    with raises(TypeError) as exception: 
       energy([1.0, 2, 3])
    
def test_energy_fails_on_negative_density():
    with raises(ValueError) as exception: energy(
            [-1, 2, 3])
        
def test_energy_fails_ndimensional_density():
    with raises(ValueError) as exception: energy(
            [[1, 2, 3], [3, 4, 5]])

def test_zero_energy_cases():
  # Zero energy at zero density
  densities = [ [], [0], [0, 0, 0] ]
  for density in densities: 
    assert energy(density) == 0

def test_derivative():
  from numpy.random import randint

  # Loop over vectors of different sizes (but not empty)
  for vector_size in randint(1, 1000, size=30): 

    # Create random density of size N
    density = randint(50, size=vector_size)

    # will do derivative at this index
    element_index = randint(vector_size)

    # modified densities
    density_plus_one = density.copy()
    density_plus_one[element_index] += 1

    # Compute and check result
    # d(n^2-1)/dn = 2n
    expected = (2.0*density[element_index] 
                if density[element_index] > 0 
                else 0 )
    actual = energy(density_plus_one) - energy(density) 
    assert expected == actual

def test_derivative_no_self_energy():
  """ If particle is alone, then its participation to energy is zero """
  from numpy import array

  density = array([1, 0, 1, 10, 15, 0])
  density_plus_one = density.copy()
  density[1] += 1 

  expected = 0
  actual = energy(density_plus_one) - energy(density) 
  assert expected == actual
Overwriting diffusion/test_model.py
In [8]:
%%bash
cd diffusion
py.test
============================= test session starts ==============================
platform linux -- Python 3.6.3, pytest-4.1.1, py-1.5.2, pluggy-0.8.1
rootdir: /home/travis/build/alan-turing-institute/rsd-engineeringcourse/ch03tests/diffusion, inifile:
plugins: cov-2.6.1
collected 6 items

test_model.py ......                                                     [100%]

=========================== 6 passed in 0.12 seconds ===========================

Coverage

With py.test, you can use the "pytest-cov" plugin to measure test coverage

In [9]:
%%bash
cd diffusion
py.test --cov
============================= test session starts ==============================
platform linux -- Python 3.6.3, pytest-4.1.1, py-1.5.2, pluggy-0.8.1
rootdir: /home/travis/build/alan-turing-institute/rsd-engineeringcourse/ch03tests/diffusion, inifile:
plugins: cov-2.6.1
collected 6 items

test_model.py ......                                                     [100%]

----------- coverage: platform linux, python 3.6.3-final-0 -----------
Name                                                                                               Stmts   Miss  Cover
----------------------------------------------------------------------------------------------------------------------
__init__.py                                                                                            0      0   100%
model.py                                                                                              10      0   100%
test_model.py                                                                                         31      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/_argcomplete.py               36     35     3%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/_code/code.py                630    615     2%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/_code/source.py              216    209     3%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/assertion/__init__.py         68     61    10%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/assertion/rewrite.py         620    520    16%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/cacheprovider.py             212    177    17%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/capture.py                   442    375    15%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/compat.py                    198    164    17%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/config/__init__.py           601    503    16%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/config/argparsing.py         229    186    19%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/debugging.py                 148    137     7%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/doctest.py                   276    267     3%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/fixtures.py                  720    581    19%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/helpconfig.py                109    100     8%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/junitxml.py                  286    284     1%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/logging.py                   279    197    29%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/main.py                      442    270    39%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/mark/__init__.py              82     60    27%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/mark/evaluate.py              91     79    13%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/mark/structures.py           176    159    10%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/monkeypatch.py               147    135     8%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/nodes.py                     201    140    30%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/nose.py                       36     24    33%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/pastebin.py                   64     63     2%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/pathlib.py                   182    168     8%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/python.py                    772    546    29%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/python_api.py                239    217     9%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/reports.py                    84     65    23%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/resultlog.py                  90     88     2%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/runner.py                    274    157    43%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/setuponly.py                  50     49     2%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/setupplan.py                  15     14     7%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/skipping.py                  168    139    17%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/stepwise.py                   52     41    21%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/terminal.py                  595    441    26%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/tmpdir.py                     86     78     9%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/unittest.py                  175    168     4%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/_pytest/warnings.py                   81     62    23%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/attr/converters.py                    27     25     7%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/more_itertools/more.py               607    593     2%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/more_itertools/recipes.py            148    147     1%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/__config__.py                   22     12    45%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/__init__.py                     58      7    88%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/_distributor_init.py             0      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/_globals.py                     11      1    91%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/_import_tools.py               226    204    10%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/add_newdocs.py                 278      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/compat/__init__.py               8      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/compat/_inspect.py              70     19    73%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/compat/py3k.py                  78     53    32%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/__init__.py                73      9    88%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/_internal.py              396    314    21%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/_methods.py                87     63    28%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/arrayprint.py             410    337    18%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/defchararray.py           356    230    35%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/einsumfunc.py             311    298     4%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/fromnumeric.py            277    206    26%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/function_base.py           69     59    14%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/getlimits.py              182     91    50%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/info.py                     3      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/machar.py                 187    178     5%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/memmap.py                  98     82    16%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/numeric.py                562    408    27%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/numerictypes.py           388    113    71%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/records.py                356    315    12%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/core/shape_base.py             111     95    14%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/ctypeslib.py                   187    144    23%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/fft/__init__.py                  7      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/fft/fftpack.py                 131    106    19%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/fft/helper.py                   86     65    24%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/fft/info.py                      2      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/__init__.py                 42      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/_datasource.py             177    140    21%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/_iotools.py                392    337    14%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/_version.py                 77     61    21%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/arraypad.py                372    347     7%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/arraysetops.py             143    131     8%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/arrayterator.py             73     60    18%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/financial.py               109     92    16%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/format.py                  234    206    12%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/function_base.py          1312   1211     8%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/index_tricks.py            244    184    25%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/info.py                      3      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/mixins.py                   62     13    79%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/nanfunctions.py            226    200    12%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/npyio.py                   762    712     7%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/polynomial.py              399    336    16%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/scimath.py                  55     35    36%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/shape_base.py              183    157    14%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/stride_tricks.py            60     49    18%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/twodim_base.py             123    100    19%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/type_check.py              104     81    22%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/ufunclike.py                28     13    54%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/lib/utils.py                   515    433    16%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/linalg/__init__.py               6      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/linalg/info.py                   2      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/linalg/linalg.py               601    529    12%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/ma/__init__.py                  11      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/ma/core.py                    2420   1881    22%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/ma/extras.py                   563    472    16%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/matrixlib/__init__.py            6      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/matrixlib/defmatrix.py         267    213    20%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/__init__.py          10      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/_polybase.py        316    235    26%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/chebyshev.py        458    396    14%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/hermite.py          417    362    13%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/hermite_e.py        414    359    13%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/laguerre.py         403    349    13%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/legendre.py         411    357    13%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/polynomial.py       340    289    15%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/polynomial/polyutils.py         65     48    26%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/random/__init__.py              13      1    92%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/random/info.py                   3      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/testing/__init__.py              6      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/testing/decorators.py           64     56    12%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/testing/nosetester.py          167    134    20%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/testing/utils.py               791    701    11%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/numpy/version.py                       7      1    86%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pkg_resources/__init__.py           1517   1515     1%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pkg_resources/_vendor/six.py         444    442     1%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pkg_resources/extern/__init__.py      35     32     9%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pluggy/_tracing.py                    59     49    17%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pluggy/callers.py                    122     86    30%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pluggy/hooks.py                      175    106    39%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pluggy/manager.py                    175    134    23%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_code/code.py                     524    522     1%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_error.py                          52     49     6%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_io/__init__.py                     0      0   100%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_io/capture.py                    266    215    19%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_io/terminalwriter.py             249    161    35%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_path/common.py                   274    186    32%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_path/local.py                    673    520    23%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_vendored_packages/apipkg.py      148    129    13%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/py/_xmlgen.py                        170    168     1%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pytest_cov/compat.py                  19     15    21%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pytest_cov/engine.py                 179    166     7%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/pytest_cov/plugin.py                 170    154     9%
/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/six.py                               450    448     1%
----------------------------------------------------------------------------------------------------------------------
TOTAL                                                                                              34182  28126    18%


=========================== 6 passed in 3.44 seconds ===========================

Or an html report:

In [10]:
%%bash
cd diffusion
py.test --cov --cov-report html
============================= test session starts ==============================
platform linux -- Python 3.6.3, pytest-4.1.1, py-1.5.2, pluggy-0.8.1
rootdir: /home/travis/build/alan-turing-institute/rsd-engineeringcourse/ch03tests/diffusion, inifile:
plugins: cov-2.6.1
collected 6 items

test_model.py ......                                                     [100%]

----------- coverage: platform linux, python 3.6.3-final-0 -----------
Coverage HTML written to dir htmlcov


=========================== 6 passed in 6.30 seconds ===========================

Look at the coverage results

In [ ]: