Module nemo.nem

A National Electricity Market (NEM) simulation.

Expand source code
# Copyright (C) 2011, 2012, 2014 Ben Elliston
# Copyright (C) 2014, 2015, 2016 The University of New South Wales
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.

"""A National Electricity Market (NEM) simulation."""

import io

import numpy as np
import pandas as pd
import requests

from nemo import configfile, polygons, regions

# Demand is in 30 minute intervals. NOTE: the number of rows in the
# demand file now dictates the number of timesteps in the simulation.

url = configfile.get('demand', 'demand-trace')

if not url.startswith('http'):
    # Local file path
    traceinput = url
else:
    try:
        resp = requests.request('GET', url, timeout=5)
    except requests.exceptions.Timeout as exc:
        raise TimeoutError(f'timeout fetching {url}') from exc
    if not resp.ok:
        raise ConnectionError(f'HTTP {resp.status_code}: {url}')
    traceinput = io.StringIO(resp.text)

demand = pd.read_csv(traceinput, comment='#', sep=',',
                     parse_dates=[['Date', 'Time']], index_col='Date_Time')

# Check for date, time and n demand columns (for n regions).
assert len(demand.columns) == regions.NUMREGIONS
# The number of rows must be even.
assert len(demand) % 2 == 0, "odd number of rows in half-hourly demand data"

# Check demand data starts at midnight
startdate = demand.index[0]
assert (startdate.hour, startdate.minute, startdate.second) == (0, 30, 0), \
    'demand data must start at midnight'

# Calculate hourly demand, averaging half-hours n and n+1.
hourly_regional_demand = demand.resample('H', closed='right').mean()

# Now put the demand into polygon resolution according to the load
# apportioning figures given in each region's polygons field.
numsteps = len(hourly_regional_demand)
hourly_demand = pd.DataFrame(index=hourly_regional_demand.index,
                             data=np.zeros((numsteps, polygons.NUMPOLYGONS)))

for rgn, weights in [(r.id, r.polygons) for r in regions.All]:
    for polygon, share in weights.items():
        hourly_demand[polygon - 1] = hourly_regional_demand[rgn] * share