-
Notifications
You must be signed in to change notification settings - Fork 133
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #118 from ojdo/split-urbs-into-subfiles
Split urbs.py into 10 files. Kind of closes #2.
- Loading branch information
Showing
12 changed files
with
2,618 additions
and
2,605 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
"""urbs: A linear optimisation model for distributed energy systems | ||
urbs minimises total cost for providing energy in form of desired commodities | ||
(usually electricity) to satisfy a given demand in form of timeseries. The | ||
model contains commodities (electricity, fossil fuels, renewable energy | ||
sources, greenhouse gases), processes that convert one commodity to another | ||
(while emitting greenhouse gases as a secondary output), transmission for | ||
transporting commodities between sites and storage for saving/retrieving | ||
commodities. | ||
""" | ||
|
||
from .data import COLORS | ||
from .model import create_model | ||
from .input import read_excel, get_input | ||
from .output import get_constants, get_timeseries | ||
from .plot import plot, result_figures, to_color | ||
from .pyomoio import get_entity, get_entities, list_entities | ||
from .report import report | ||
from .saveload import load, save |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
COLORS = { | ||
# process types | ||
'Biomass plant': (0, 122, 55), | ||
'Coal plant': (100, 100, 100), | ||
'Gas plant': (237, 227, 0), | ||
'Gud plant': (153, 153, 0), | ||
'Hydro plant': (198, 188, 240), | ||
'Lignite plant': (116, 66, 65), | ||
'Photovoltaics': (243, 174, 0), | ||
'Slack powerplant': (163, 74, 130), | ||
'Wind park': (122, 179, 225), | ||
# hard-coded strings | ||
'Decoration': (128, 128, 128), # plot labels | ||
'Unshifted': (130, 130, 130), # unshifted demand line | ||
'Shifted': (25, 25, 25), # shifted demand line | ||
'Delta': (130, 130, 130), # demand delta | ||
'Grid': (128, 128, 128), # background grid | ||
'Overproduction': (190, 0, 99), # excess power (diagnostic) | ||
'Storage': (60, 36, 154), # storage area | ||
'Stock': (222, 222, 222), # stock commodity creation | ||
# cost types | ||
'Environmental': (180, 50, 15), | ||
'Feed-in': (255, 204, 153), | ||
'Fixed': (128, 128, 128), | ||
'Fuel': (218, 215, 203), | ||
'Invest': (0, 101, 189), | ||
'Revenue': (62, 173, 0), | ||
'Purchase': (0, 51, 89), | ||
'Startup': (105, 8, 90), | ||
'Variable': (128, 153, 172)} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import pandas as pd | ||
from xlrd import XLRDError | ||
|
||
|
||
def read_excel(filename): | ||
"""Read Excel input file and prepare URBS input dict. | ||
Reads an Excel spreadsheet that adheres to the structure shown in | ||
mimo-example.xlsx. Two preprocessing steps happen here: | ||
1. Column titles in 'Demand' and 'SupIm' are split, so that | ||
'Site.Commodity' becomes the MultiIndex column ('Site', 'Commodity'). | ||
2. The attribute 'annuity-factor' is derived here from the columns 'wacc' | ||
and 'depreciation' for 'Process', 'Transmission' and 'Storage'. | ||
Args: | ||
filename: filename to an Excel spreadsheet with the required sheets | ||
'Commodity', 'Process', 'Transmission', 'Storage', 'Demand' and | ||
'SupIm'. | ||
Returns: | ||
a dict of 6 DataFrames | ||
Example: | ||
>>> data = read_excel('mimo-example.xlsx') | ||
>>> data['hacks'].loc['Global CO2 limit', 'Value'] | ||
150000000 | ||
""" | ||
with pd.ExcelFile(filename) as xls: | ||
site = xls.parse('Site').set_index(['Name']) | ||
commodity = ( | ||
xls.parse('Commodity').set_index(['Site', 'Commodity', 'Type'])) | ||
process = xls.parse('Process').set_index(['Site', 'Process']) | ||
process_commodity = ( | ||
xls.parse('Process-Commodity') | ||
.set_index(['Process', 'Commodity', 'Direction'])) | ||
transmission = ( | ||
xls.parse('Transmission') | ||
.set_index(['Site In', 'Site Out', | ||
'Transmission', 'Commodity'])) | ||
storage = ( | ||
xls.parse('Storage').set_index(['Site', 'Storage', 'Commodity'])) | ||
demand = xls.parse('Demand').set_index(['t']) | ||
supim = xls.parse('SupIm').set_index(['t']) | ||
buy_sell_price = xls.parse('Buy-Sell-Price').set_index(['t']) | ||
dsm = xls.parse('DSM').set_index(['Site', 'Commodity']) | ||
try: | ||
hacks = xls.parse('Hacks').set_index(['Name']) | ||
except XLRDError: | ||
hacks = None | ||
|
||
# prepare input data | ||
# split columns by dots '.', so that 'DE.Elec' becomes the two-level | ||
# column index ('DE', 'Elec') | ||
demand.columns = split_columns(demand.columns, '.') | ||
supim.columns = split_columns(supim.columns, '.') | ||
buy_sell_price.columns = split_columns(buy_sell_price.columns, '.') | ||
|
||
data = { | ||
'site': site, | ||
'commodity': commodity, | ||
'process': process, | ||
'process_commodity': process_commodity, | ||
'transmission': transmission, | ||
'storage': storage, | ||
'demand': demand, | ||
'supim': supim, | ||
'buy_sell_price': buy_sell_price, | ||
'dsm': dsm} | ||
if hacks is not None: | ||
data['hacks'] = hacks | ||
|
||
# sort nested indexes to make direct assignments work | ||
for key in data: | ||
if isinstance(data[key].index, pd.core.index.MultiIndex): | ||
data[key].sortlevel(inplace=True) | ||
return data | ||
|
||
|
||
def split_columns(columns, sep='.'): | ||
"""Split columns by separator into MultiIndex. | ||
Given a list of column labels containing a separator string (default: '.'), | ||
derive a MulitIndex that is split at the separator string. | ||
Args: | ||
columns: list of column labels, containing the separator string | ||
sep: the separator string (default: '.') | ||
Returns: | ||
a MultiIndex corresponding to input, with levels split at separator | ||
Example: | ||
>>> split_columns(['DE.Elec', 'MA.Elec', 'NO.Wind']) | ||
MultiIndex(levels=[['DE', 'MA', 'NO'], ['Elec', 'Wind']], | ||
labels=[[0, 1, 2], [0, 0, 1]]) | ||
""" | ||
if len(columns) == 0: | ||
return columns | ||
column_tuples = [tuple(col.split('.')) for col in columns] | ||
return pd.MultiIndex.from_tuples(column_tuples) | ||
|
||
|
||
def get_input(prob, name): | ||
"""Return input DataFrame of given name from urbs instance. | ||
These are identical to the key names returned by function `read_excel`. | ||
That means they are lower-case names and use underscores for word | ||
separation, e.g. 'process_commodity'. | ||
Args: | ||
prob: a urbs model instance | ||
name: an input DataFrame name ('commodity', 'process', ...) | ||
Returns: | ||
the corresponding input DataFrame | ||
""" | ||
if hasattr(prob, name): | ||
# classic case: input data DataFrames are accessible via named | ||
# attributes, e.g. `prob.process`. | ||
return getattr(prob, name) | ||
elif hasattr(prob, '_data') and name in prob._data: | ||
# load case: input data is accessible via the input data cache dict | ||
return prob._data[name] | ||
else: | ||
# unknown | ||
raise ValueError("Unknown input DataFrame name!") |
Oops, something went wrong.