NEMO User's Guide: an IPython Notebook

A simple example

NEMO can be driven by your own Python code. Some simple examples of how to do this appear below. First, we will create a simulation with a single combined cycle gas turbine (CCGT).

In [1]:
import nem
import scenarios
c = nem.Context()
scenarios._one_ccgt(c)
print c.generators
[CCGT (NSW1), 0.00 GW]

Then run the simulation:

In [2]:
nem.run(c)
print c
Timesteps: 8760 h
Demand energy: 204.4 TWh
Spilled energy: 0.0 TWh
Unserved energy: 100.000%
WARNING: NEM reliability standard exceeded
Unserved total hours: 8760
min, max shortfalls: (15469.0, 33645.0)

The CCGT is configured with a capacity of 0 MW. Hence, no electricity is served in the simulation (100% unserved energy) and the largest shortfall was 33,645 MW (33.6 GW). This figure corresponds to the peak demand in the simulated year. So let's change the capacity of the only generator (generator #0) to 40 GW:

In [3]:
c.generators[0].set_capacity(40)
nem.run(c)
print c
Timesteps: 8760 h
Demand energy: 204.4 TWh
Spilled energy: 0.0 TWh
No unserved energy

This time, all energy was served.

Scripting simulations

Writing NEMO in Python allows the simulation framework to be easily scripted using Python language constructs, such as for loops. Using the previous example, the following small script demonstrates how simulation runs can be automated:

In [6]:
c = nem.Context()
scenarios._one_ccgt(c)
for i in range(0, 40):
    c.generators[0].set_capacity(i)
    nem.run(c)
    if c.unserved_energy == 0:
        break
print c.generators
[CCGT (NSW1), 34.00 GW]

Once the generator capacity reaches 34 GW, there is no unserved energy.

Scenarios

NEMO contains two types of scenarios: supply-side and demand-side sceanrios. The supply-side scenario modifies the list of generators. For example:

In [7]:
c = nem.Context()
scenarios.ccgt(c)
print c.generators
[CCGT (NSW1), 0.00 GW, QLD1 pumped-hydro (QLD1), 0.50 GW, NSW1 pumped-hydro (NSW1), 1.74 GW, TAS1 hydro (TAS1), 2.25 GW, NSW1 hydro (NSW1), 0.91 GW, VIC1 hydro (VIC1), 2.24 GW, OCGT (NSW1), 0.00 GW]

The current supply-side scenarios include:

  • ccgt
  • ccgt-ccs
  • coal-ccs
  • replacement
  • re100
  • re100+batteries
  • re100+dsp
  • re100+egs
  • re100+hsa
  • re100+geo
  • re100-nocst
  • re100+geo-nocst
  • re+fossil
  • re+ccs
  • theworks

A full list of scenarios (with descriptions) can be obtained by running:

python evolve.py --list-scenarios

Demand-side scenarios modify the electricity demand time series before the simulation runs. Demand-side scenarios behave like operators that can be combined in any combination to modify the demand as desired. These are:

  • roll:X rolls the load by x timesteps
  • scale:X scales the load by x percent
  • scaletwh:X scales the load to x TWh
  • shift:N:H1:H2 shifts n megawatts every day from hour h1 to hour h2
  • peaks:N:X adjust demand peaks over n megawatts by x percent
  • npeaks:N:X adjust top n demand peaks by x percent

For example, applying scale:-10 followed by shift:1000:16:12 will reduce the overall demand by 10% and then shift 1 MW of demand from 4pm to noon every day of the year.

Configuration file

NEMO uses a configuration file to give users control over where data such as demand time series are to be found. The location of the configuration file can be specified by setting the NEMORC environment variable. The configuration file format is similar to Windows INI files; it has sections (in brackets) and, within sections, key=value pairs.

The default configuration file is called default.cfg. The keys currently recognised are:

  • [generation]
    • cst-trace -- URL of CST generation traces
    • egs-geothermal-trace -- URL of EGS geothermal generation traces
    • hsa-geothermal-trace -- URL of HSA geothermal generation traces
    • wind-trace -- URL of wind generation traces
    • pv1axis-trace -- URL of 1-axis PV generation traces
  • [demand]
    • demand-trace -- URL of demand trace data

Running an optimisation

Instead of running a single simulation, it is more interesting to use evolve.py which drives an evolutionary algorithm to find the least cost portfolio that meets demand. There are many options which you can discover by running python evolve.py --help. Here is a simple example to find the least cost portfolio using the default "re100" scenario (100% renewables):

$ python evolve.py -s re100

At the end of a run, details of the least cost system are printed on the console: the capacity of each generator, the energy supplied, CO2 emissions, costs, and the average cost of generation in dollars per MWh. If you want to see a plot of the system dispatch, you need to use the replay.py script described in the next section.

Many of the optimisation parameters can be controlled from the command line, requiring no changes to the source code. Typically, source code changes are only required to add new supply scenario functions or cost classes. The command line options for evolve.py are documented as follows:

Short option Long option Description Default
-h --help Show help and then exit
-c --carbon-price Carbon price in \$/tonne 25
-d --demand-modifer Demand modifier unchanged
-g --generations Number of generations to run 100
-r --discount-rate Discount rate 0.05
-s --supply-scenario Generation mix scenario re100
-t --transmission Include transmission costs False
-v --verbose Be verbose False
--bioenergy-limit Limit on annual energy from bioenergy in TWh/year 20
--ccs-storage-costs CCS storage costs in \$/tonne 27
--coal-price Coal price in \$/GJ 1.86
--costs Use different cost scenario AETA2013-in2030-mid
--emissions-limit Limit total emissions to N Mt/year None
--fossil-limit Limit fraction of energy from fossil sources None
--gas-price Gas price in \$/GJ 11
--hydro-limit Limit on annual energy from hydro in TWh/year 12
--lambda CMA-ES lambda value None (autodetect)
--list-scenarios Print list of scenarios and exit
--min-regional-generation Minimum share of energy generated intra-region None
--nsp-limit Non-synchronous penetration limit 0.75
--reliability-std Reliability standard (% unserved) None
--seed Seed for random number generator None
--sigma CMA-ES sigma value 2.0
--trace-file Filename for evaluation trace None
--version Print version number and exit

Replaying a simulation

To avoid having to re-run a long optimisation just to examine the resulting system, it is possible to reproduce a single run using the results from an earlier optimisation. The parameters from an evolve.py run must be copied and pasted into a text file (in this example the file is called previous.out, but the file can have any name). The parameters appear on the line beginning with List: followed by a list of numbers in square brackets (Python list notation).

The input file for replay.py consists of any number of configurations to replay, one per line. Each line must begin with the scenario name (eg, re100) and then the Python list of parameter values. For example:

re100: [0, 0, 23.25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.74, 1.16, 0.96, 0.36, 1.73, 0, 4.74]

A run is reproduced using the replay.py script like so:

$ python replay.py -f previous.out -x

The -f switch (which is mandatory) specifies the name of the input data file and the -x option enables a graphical plot of the system dispatch that you can navigate using zoom in, zoom out and pan controls. By including the `--spills' option, surplus energy in each hour will be plotted above the demand line in a lighter shade than the colour of the spilling generator. All command line options can be displayed using:

$ python replay.py --help

Summarising the results

At the end of a simulation run, the results (including score, generator sizes, generated energy, CO2 emissions, etc.) can be fed through an AWK script called summary.awk. You will need a version of AWK installed. This is almost guaranteed to be installed on a Linux or Mac OS X system, but for Windows you can download a version from Sourceforge.

You can feed the output of evolve.py or replay.py into summary.awk. For example:

$ python replay.py -f example.data -v | awk -f summary.awk

or:

$ python evolve.py -s re100 | awk -f summary.awk

(although the latter means that you will have no opportunity to see the detailed results as they will be consumed by AWK).