Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Input/single_year_example.xlsx
Binary file not shown.
32 changes: 16 additions & 16 deletions run_single_year.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,30 @@
objective = 'cost' # set either 'cost' or 'CO2' as objective

# Choose Solver (cplex, glpk, gurobi, ...)
solver = 'glpk'
solver = 'gurobi'

# simulation timesteps
(offset, length) = (0, 8760) # time step selection
(offset, length) = (0, 120) # time step selection
timesteps = range(offset, offset+length+1)
dt = 1 # length of each time step (unit: hours)

# detailed reporting commodity/sites
report_tuples = [
(2019, 'North', 'Elec'),
(2019, 'Mid', 'Elec'),
(2019, 'South', 'Elec'),
(2019, ['North', 'Mid', 'South'], 'Elec')
(2020, 'North', 'Elec'),
(2020, 'Mid', 'Elec'),
(2020, 'South', 'Elec'),
(2020, ['North', 'Mid', 'South'], 'Elec')
]

# optional: define names for sites in report_tuples
report_sites_name = {('North', 'Mid', 'South'): 'All'}

# plotting commodities/sites
plot_tuples = [
(2019, 'North', 'Elec'),
(2019, 'Mid', 'Elec'),
(2019, 'South', 'Elec'),
(2019, ['North', 'Mid', 'South'], 'Elec')
(2020, 'North', 'Elec'),
(2020, 'Mid', 'Elec'),
(2020, 'South', 'Elec'),
(2020, ['North', 'Mid', 'South'], 'Elec')
]

# optional: define names for sites in plot_tuples
Expand All @@ -67,12 +67,12 @@
# select scenarios to be run
scenarios = [
urbs.scenario_base,
urbs.scenario_stock_prices,
urbs.scenario_co2_limit,
urbs.scenario_co2_tax_mid,
urbs.scenario_no_dsm,
urbs.scenario_north_process_caps,
urbs.scenario_all_together
# urbs.scenario_stock_prices,
# urbs.scenario_co2_limit,
# urbs.scenario_co2_tax_mid,
# urbs.scenario_no_dsm,
# urbs.scenario_north_process_caps,
# urbs.scenario_all_together
]

for scenario in scenarios:
Expand Down
12 changes: 6 additions & 6 deletions urbs/features/BuySellPrice.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def res_sell_total_rule(m, stf, sit, com, com_type):
total_consumption = 0
for tm in m.tm:
total_consumption += (
m.e_co_sell[tm, stf, sit, com, com_type])
m.e_co_sell[tm, stf, sit, com, com_type] * m.typeday['weight_typeday'][(stf,tm)])
total_consumption *= m.weight
return (total_consumption <=
m.commodity_dict['max'][(stf, sit, com, com_type)])
Expand All @@ -99,7 +99,7 @@ def res_buy_total_rule(m, stf, sit, com, com_type):
total_consumption = 0
for tm in m.tm:
total_consumption += (
m.e_co_buy[tm, stf, sit, com, com_type])
m.e_co_buy[tm, stf, sit, com, com_type] * m.typeday['weight_typeday'][(stf,tm)])
total_consumption *= m.weight
return (total_consumption <=
m.commodity_dict['max'][(stf, sit, com, com_type)])
Expand Down Expand Up @@ -174,15 +174,15 @@ def revenue_costs(m):
try:
return -sum(
m.e_co_sell[(tm,) + c] *
m.buy_sell_price_dict[c[2]][(c[0], tm)] * m.weight *
m.buy_sell_price_dict[c[2]][(c[0], tm)] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.commodity_dict['price'][c] *
m.commodity_dict['cost_factor'][c]
for tm in m.tm
for c in sell_tuples)
except KeyError:
return -sum(
m.e_co_sell[(tm,) + c] *
m.buy_sell_price_dict[c[2], ][(c[0], tm)] * m.weight *
m.buy_sell_price_dict[c[2], ][(c[0], tm)] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.commodity_dict['price'][c] *
m.commodity_dict['cost_factor'][c]
for tm in m.tm
Expand All @@ -194,15 +194,15 @@ def purchase_costs(m):
try:
return sum(
m.e_co_buy[(tm,) + c] *
m.buy_sell_price_dict[c[2]][(c[0], tm)] * m.weight *
m.buy_sell_price_dict[c[2]][(c[0], tm)] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.commodity_dict['price'][c] *
m.commodity_dict['cost_factor'][c]
for tm in m.tm
for c in buy_tuples)
except KeyError:
return sum(
m.e_co_buy[(tm,) + c] *
m.buy_sell_price_dict[c[2], ][(c[0], tm)] * m.weight *
m.buy_sell_price_dict[c[2], ][(c[0], tm)] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.commodity_dict['price'][c] *
m.commodity_dict['cost_factor'][c]
for tm in m.tm
Expand Down
31 changes: 31 additions & 0 deletions urbs/features/TypeDay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import math
import pyomo.core as pyomo

def add_typeday(m):

# Validation:
if not (len(m.timesteps) % 24 == 0 or len(m.timesteps) % 24 == 1):
print('Warning: length of timesteps does not end at the end of a day!')

# change weight parameter to 1, since the whole year is representated by weight_typeday
m.del_component(m.weight)
m.weight = pyomo.Param(
initialize=1,
doc='Pre-factor for variable costs and emissions for annual result for type days = 1')

# m.t_endofday = pyomo.Set(
# within=m.t,
# initialize=[i * 24 * m.dt for i in list(range(1,1+int(len(m.timesteps) / m.dt / 24)))],
# ordered=True,
# doc='timestep at the end of each day')
#
# m.res_storage_state_cyclicity_typeday = pyomo.Constraint(
# m.t_endofday, m.sto_tuples,
# rule=res_storage_state_cyclicity_typeday_rule,
# doc='storage content initial == storage content at the end of each day')

return m

def res_storage_state_cyclicity_typeday_rule(m, t, stf, sit, sto, com):
return (m.e_sto_con[m.t[1], stf, sit, sto, com] ==
m.e_sto_con[t, stf, sit, sto, com])
3 changes: 2 additions & 1 deletion urbs/features/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
from .dsm import add_dsm, dsm_surplus
from .BuySellPrice import add_buy_sell_price, bsp_surplus, revenue_costs, \
purchase_costs
from .TimeVarEff import add_time_variable_efficiency
from .TimeVarEff import add_time_variable_efficiency
from .TypeDay import add_typeday
4 changes: 2 additions & 2 deletions urbs/features/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,11 @@ def storage_cost(m, cost_type):
m.storage_dict['cost_factor'][s]
for s in m.sto_tuples)
elif cost_type == 'Variable':
return sum(m.e_sto_con[(tm,) + s] * m.weight *
return sum(m.e_sto_con[(tm,) + s] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.storage_dict['var-cost-c'][s] *
m.storage_dict['cost_factor'][s] +
(m.e_sto_in[(tm,) + s] + m.e_sto_out[(tm,) + s]) *
m.weight * m.storage_dict['var-cost-p'][s] *
m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] * m.storage_dict['var-cost-p'][s] *
m.storage_dict['cost_factor'][s]
for tm in m.tm
for s in m.sto_tuples)
Expand Down
6 changes: 3 additions & 3 deletions urbs/features/transmission.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,18 +370,18 @@ def transmission_cost(m, cost_type):
for t in m.tra_tuples)
elif cost_type == 'Variable':
if m.mode['dpf']:
return sum(m.e_tra_in[(tm,) + t] * m.weight *
return sum(m.e_tra_in[(tm,) + t] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.transmission_dict['var-cost'][t] *
m.transmission_dict['cost_factor'][t]
for tm in m.tm
for t in m.tra_tuples_tp) + \
sum(m.e_tra_abs[(tm,) + t] * m.weight *
sum(m.e_tra_abs[(tm,) + t] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.transmission_dict['var-cost'][t] *
m.transmission_dict['cost_factor'][t]
for tm in m.tm
for t in m.tra_tuples_dc)
else:
return sum(m.e_tra_in[(tm,) + t] * m.weight *
return sum(m.e_tra_in[(tm,) + t] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.transmission_dict['var-cost'][t] *
m.transmission_dict['cost_factor'][t]
for tm in m.tm
Expand Down
3 changes: 3 additions & 0 deletions urbs/identify.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def identify_mode(data):
'bsp': False, # buy sell price
'tve': False, # time variable efficiency
'dpf': False, # dc power flow
'tdy': False, # type days
'exp': { # expansion
'pro': True,
'tra': False,
Expand All @@ -55,6 +56,8 @@ def identify_mode(data):
if 'reactance' in data['transmission'].keys():
if any(data['transmission']['reactance'] > 0):
mode['dpf'] = True
if any(data['type day']['weight_typeday'] > 0):
mode['tdy'] = True

return mode

Expand Down
10 changes: 10 additions & 0 deletions urbs/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ def read_input(input_files, year):
demand = xls.parse('Demand').set_index(['t'])
demand = pd.concat([demand], keys=[support_timeframe],
names=['support_timeframe'])
typeday = demand.loc[:, ['weight_typeday']]
demand = demand.drop(columns=['weight_typeday'])
# split columns by dots '.', so that 'DE.Elec' becomes
# the two-level column index ('DE', 'Elec')
demand.columns = split_columns(demand.columns, '.')
Expand Down Expand Up @@ -163,6 +165,7 @@ def read_input(input_files, year):
'commodity': commodity,
'process': process,
'process_commodity': process_commodity,
'type day': typeday,
'demand': demand,
'supim': supim,
'transmission': transmission,
Expand Down Expand Up @@ -245,6 +248,13 @@ def pyomo_model_prep(data, timesteps):
if m.mode['tve']:
m.eff_factor_dict = \
data["eff_factor"].dropna(axis=0, how='all').to_dict()
if m.mode['tdy']:
m.typeday = data['type day'].dropna(axis=0, how='all').to_dict()
else:
# if mode 'typeday' is not active, create a dict with ones
temp = pd.DataFrame(index=data['demand'].dropna(axis=0, how='all').index)
temp['weight_typeday']=1
m.typeday = temp.to_dict()

# Create columns of support timeframe values
commodity['support_timeframe'] = (commodity.index.
Expand Down
19 changes: 12 additions & 7 deletions urbs/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def create_model(data, dt=1, timesteps=None, objective='cost',
# costs are annual by default, variable costs are scaled by weight) and
# among different simulation durations meaningful.
m.weight = pyomo.Param(
initialize=float(8760) / (len(m.timesteps) * dt),
initialize=float(8760) / ((len(m.timesteps) - 1) * dt),
doc='Pre-factor for variable costs and emissions for an annual result')

# dt = spacing between timesteps. Required for storage equation that
Expand Down Expand Up @@ -79,6 +79,7 @@ def create_model(data, dt=1, timesteps=None, objective='cost',
indexlist.add(tuple(key)[0])
m.stf = pyomo.Set(
initialize=indexlist,
ordered=True,
doc='Set of modeled support timeframes (e.g. years)')

# site (e.g. north, middle, south...)
Expand Down Expand Up @@ -287,6 +288,8 @@ def create_model(data, dt=1, timesteps=None, objective='cost',
m.pro_timevar_output_tuples = pyomo.Set(
within=m.stf * m.sit * m.pro * m.com,
doc='empty set needed for (partial) process output')
if m.mode['tdy']:
m = add_typeday(m)

# Equation declarations
# equation bodies are defined in separate functions, referred to here by
Expand Down Expand Up @@ -505,7 +508,7 @@ def res_stock_total_rule(m, stf, sit, com, com_type):
total_consumption = 0
for tm in m.tm:
total_consumption += (
m.e_co_stock[tm, stf, sit, com, com_type])
m.e_co_stock[tm, stf, sit, com, com_type] * m.typeday['weight_typeday'][(stf,tm)])
total_consumption *= m.weight
return (total_consumption <=
m.commodity_dict['max'][(stf, sit, com, com_type)])
Expand Down Expand Up @@ -534,7 +537,7 @@ def res_env_total_rule(m, stf, sit, com, com_type):
# calculate total creation of environmental commodity com
env_output_sum = 0
for tm in m.tm:
env_output_sum += (- commodity_balance(m, tm, stf, sit, com))
env_output_sum += (- commodity_balance(m, tm, stf, sit, com) * m.typeday['weight_typeday'][(stf,tm)])
env_output_sum *= m.weight
return (env_output_sum <=
m.commodity_dict['max'][(stf, sit, com, com_type)])
Expand Down Expand Up @@ -681,7 +684,7 @@ def res_global_co2_limit_rule(m, stf):
# minus because negative commodity_balance represents creation
# of that commodity.
co2_output_sum += (- commodity_balance(m, tm,
stf, sit, 'CO2'))
stf, sit, 'CO2') * m.typeday['weight_typeday'][(stf,tm)])

# scaling to annual output (cf. definition of m.weight)
co2_output_sum *= m.weight
Expand All @@ -704,6 +707,7 @@ def res_global_co2_budget_rule(m):
# creation of that commodity.
co2_output_sum += (- commodity_balance
(m, tm, stf, sit, 'CO2') *
m.typeday['weight_typeday'][(stf, tm)] *
m.weight *
stf_dist(stf, m))

Expand Down Expand Up @@ -784,7 +788,7 @@ def def_costs_rule(m, cost_type):

elif cost_type == 'Variable':
cost = \
sum(m.tau_pro[(tm,) + p] * m.weight *
sum(m.tau_pro[(tm,) + p] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.process_dict['var-cost'][p] *
m.process_dict['cost_factor'][p]
for tm in m.tm
Expand All @@ -797,15 +801,15 @@ def def_costs_rule(m, cost_type):

elif cost_type == 'Fuel':
return m.costs[cost_type] == sum(
m.e_co_stock[(tm,) + c] * m.weight *
m.e_co_stock[(tm,) + c] * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.commodity_dict['price'][c] *
m.commodity_dict['cost_factor'][c]
for tm in m.tm for c in m.com_tuples
if c[2] in m.com_stock)

elif cost_type == 'Environmental':
return m.costs[cost_type] == sum(
- commodity_balance(m, tm, stf, sit, com) * m.weight *
- commodity_balance(m, tm, stf, sit, com) * m.weight * m.typeday['weight_typeday'][(m.stf[1],tm)] *
m.commodity_dict['price'][(stf, sit, com, com_type)] *
m.commodity_dict['cost_factor'][(stf, sit, com, com_type)]
for tm in m.tm
Expand Down Expand Up @@ -837,6 +841,7 @@ def co2_rule(m):
# creation of that commodity.
if m.mode['int']:
co2_output_sum += (- commodity_balance(m, tm, stf, sit, 'CO2') *
m.typeday['weight_typeday'][(stf, tm)] *
m.weight * stf_dist(stf, m))
else:
co2_output_sum += (- commodity_balance(m, tm, stf, sit, 'CO2') *
Expand Down
2 changes: 1 addition & 1 deletion urbs/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def sort_plot_elements(elements):
quotient = quotient.fillna(0)
# sort created/consumed ascencing with quotient i.e. base load first
elements = elements.append(quotient)
new_columns = elements.columns[elements.ix[elements.last_valid_index()]
new_columns = elements.columns[elements.loc[elements.last_valid_index()]
.argsort()]
elements_sorted = elements[new_columns][:-1]

Expand Down
15 changes: 15 additions & 0 deletions urbs/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,21 @@ def validate_input(data):
"worksheet 'DSM' must be from the list of site "
"names specified in the worksheet 'Site'.")

if any(data['type day']['weight_typeday'] > 0):
if not data['dsm'].empty:
print('Warning: Typeday and DSM active!')

if not (len(data['type day'].dropna(axis=0, how='all').index) % 24 == 0 or
len(data['type day'].dropna(axis=0, how='all').index) % 24 - 1 == 0):
print('Warning: Weighting of the typeday does not end at the end of a day, please check the length of '
'-Demand-weight_typeday')

if min(data['type day'].iloc[1:,0]) < 1:
print('Warning: weighting_typeday < 1')

if sum(data['type day'].loc[:,'weight_typeday'].dropna(axis=0, how='all')) != 8760:
print('Warning: The sum of weighting_typeday does not equal a year')

# report that variable costs may have error if used with CO2 minimization and DCPF
def validate_dc_objective(data, objective):
if not data['transmission'].empty:
Expand Down