smif.convert.interval module

Handles conversion between the set of time intervals used in the SosModel

There are three main classes, which are currently rather intertwined. Interval represents an individual definition of a period within a year. This is specified using the ISO8601 period syntax and exposes methods which use the isodate library to parse this into an internal hourly representation of the period.

TimeIntervalRegister holds the definitions of time-interval sets specified for the sector models at the SosModel level. This class exposes one public method, add_interval_set() which allows the SosModel to add an interval definition from a model configuration to the register.

Quantities

Quantities are associated with a duration, period or interval. For example 120 GWh of electricity generated during each week of February.:

Week 1: 120 GW
Week 2: 120 GW
Week 3: 120 GW
Week 4: 120 GW

Other examples of quantities:

  • greenhouse gas emissions
  • demands for infrastructure services
  • materials use
  • counts of cars past a junction
  • costs of investments, operation and maintenance

Upscale: Divide

To convert to a higher temporal resolution, the values need to be apportioned across the new time scale. In the above example, the 120 GWh of electricity would be divided over the days of February to produce a daily time series of generation. For example:

1st Feb: 17 GWh
2nd Feb: 17 GWh
3rd Feb: 17 GWh
...

Downscale: Sum

To resample weekly values to a lower temporal resolution, the values would need to be accumulated. A monthly total would be:

Feb: 480 GWh

Remapping

Remapping quantities, as is required in the conversion from energy demand (hourly values over a year) to energy supply (hourly values for one week for each of four seasons) requires additional averaging operations. The quantities are averaged over the many-to-one relationship of hours to time-slices, so that the seasonal-hourly timeslices in the model approximate the hourly profiles found across the particular seasons in the year. For example:

hour 1: 20 GWh
hour 2: 15 GWh
hour 3: 10 GWh
...
hour 8592: 16 GWh
hour 8593: 12 GWh
hour 8594: 21 GWh
...
hour 8760: 43 GWh

To:

season 1 hour 1: 20+16+.../4 GWh # Denominator number hours in sample
season 1 hour 2: 15+12+.../4 GWh
season 1 hour 3: 10+21+.../4 GWh
...

Prices

Unlike quantities, prices are associated with a point in time. For example a spot price of £870/GWh. An average price can be associated with a duration, but even then, we are just assigning a price to any point in time within a range of times.

Upscale: Fill

Given a timeseries of monthly spot prices, converting these to a daily price can be done by a fill operation. E.g. copying the monthly price to each day.

From:

Feb: £870/GWh

To:

1st Feb: £870/GWh
2nd Feb: £870/GWh
...

Downscale: Average

On the other hand, going down scale, such as from daily prices to a monthly price requires use of an averaging function. From:

1st Feb: £870/GWh
2nd Feb: £870/GWh
...

To:

Feb: £870/GWh

Development Notes

  • We could use numpy.convolve() to compare time intervals as hourly arrays before adding them to the set of intervals

Summary

Data:

BASE_YEAR int([x]) -> integer int(x, base=10) -> integer
Interval A time interval
IntervalAdaptor Convert intervals, assuming uniform distributions where necessary
IntervalSet A collection of intervals

Reference

class smif.convert.interval.IntervalAdaptor(name)[source]

Bases: smif.convert.adaptor.Adaptor

Convert intervals, assuming uniform distributions where necessary

generate_coefficients(from_spec, to_spec) → <MagicMock id='139764765378688'>[source]

Generate conversion coefficients for interval dimensions

Assumes that the Coordinates elements contain an ‘interval’ key whose value corresponds to Interval data, that is a {‘name’: interval_id, ‘interval’: list of interval extents}.

For example, intervals covering each hour of a period

{ 'name': 'first_hour', 'interval': [('PT0H', 'PT1H')] }
{ 'name': ''second_hour', 'interval': [('PT1H', 'PT2H')] }
...

Or intervals corresponding to repeating hours for each day of a period

{
    'name': midnight',
    'interval': [
        ('PT0H', 'PT1H'), ('PT24H', 'PT25H'), ('PT48H', 'PT49H'), ...
    ]
},
{
    'name': ''one_am',
    'interval': [
        ('PT1H', 'PT2H'), ('PT25H', 'PT26H'), ('PT49H', 'PT50H'), ...
    ]
}
...
class smif.convert.interval.Interval(name, list_of_intervals, base_year=2010)[source]

Bases: object

A time interval

Parameters:
  • id (str) – The unique name of the Interval
  • list_of_intervals (str) – A list of tuples of valid ISO8601 duration definition string denoting the time elapsed from the beginning of the year to the (beginning, end) of the interval
  • base_year (int, default=2010) – The reference year used for conversion to a datetime tuple

Example

>>> a = Interval('id', ('PT0H', 'PT1H'))
>>> a.interval = ('PT1H', 'PT2H')
>>> repr(a)
"Interval('id', [('PT0H', 'PT1H'), ('PT1H', 'PT2H')], base_year=2010)"
>>> str(a)
"Interval 'id' starts at hour 0 and ends at hour 1"
name

The name (or id) of the interval(s)

Returns:Name or ID
Return type:str
start

The start hour of the interval(s)

Returns:A list of integers, representing the hour from the beginning of the year associated with the start of each of the intervals
Return type:list
end

The end hour of the interval(s)

Returns:An integer or list of integers, representing the hour from the beginning of the year associated with the end of each of the intervals
Return type:int or list
interval

The list of intervals

Setter appends a tuple or list of intervals to the list of intervals

baseyear

The reference year

bounds

Return a list of tuples of the intervals in terms of hours

Returns:A list of tuples of the start and end hours of the year of the interval
Return type:list
to_hourly_array()[source]

Converts a list of intervals to a boolean array of hours

Returns:A boolean array
Return type:numpy.ndarray
class smif.convert.interval.IntervalSet(name, data, base_year=2010)[source]

Bases: smif.convert.register.ResolutionSet

A collection of intervals

Parameters:
  • name (str) – A unique identifier for the set of time intervals
  • data (list) – Time intervals required as a list of dicts, with required keys start, end and name
static get_bounds(entry)[source]

Implement this helper method to return bounds from an entry in the register

Parameters:entry – An entry from a ResolutionSet
Returns:The bounds of the entry
Return type:bounds
get_proportion(from_index, to_interval)[source]

Find proportion of interval address by from_index in to_interval

Parameters:
  • from_index (int) – Index of source interval
  • to_interval (Interval) – The destination interval
Returns:

Return type:

float

coverage

The total coverage in hours of the year by the interval set

Returns:
Return type:float
intersection(to_entry)[source]

Return the destination intervals that intersect with to_entry

to_entry : Interval

Returns:A list of Intervals that intersect with bounds
Return type:list

Notes

Look at the columns of the intersection array and identify overlapping intervals

static check_interval_bounds_equal(bounds)[source]

Checks that each interval in the list of bounds is equal

Parameters:bounds (list) – A list of tuples containing the start and end hours of an interval
Returns:True if all intervals in list of bounds are equal in length
Return type:bool
data

Returns the intervals as a list

Returns:
Return type:list
get_entry_names()[source]

Returns the names of the intervals