Skip to content
Snippets Groups Projects
Commit 633cd904 authored by JBrucksch's avatar JBrucksch
Browse files

Adds bidirectional constraint in BaseStorage; adds example files, new...

Adds bidirectional constraint in BaseStorage; adds example files, new community_runme (parts of it now in main_district)
parent f9cfdf37
No related branches found
No related tags found
No related merge requests found
......@@ -229,6 +229,7 @@ class BaseStorage(BaseComponent):
self._constraint_maxcap(model, var_dict, T)
self._constraint_conser(model, flows, var_dict, T)
self._constraint_vdi2067(model, var_dict, T)
self._constraint_bidirectional_flows(model, var_dict, T, self.max_size)
#self._constraint_reopt(model, flows, var_dict, T)
def add_variables(self, input_profiles, plant_parameters, var_dict, flows,
......
injection_price,injection_price_variable,injection/pvpeak,gas_price,gas_price_variable,elec_price,elec_price_variable,heat_price,heat_price_variable,cooling_price,cooling_price_variable,injection_price_gas,injection_price_gas_variable,injection_price_heat,injection_price_heat_variable,injection_price_cooling,injection_price_cooling_variable,elec_emission,gas_emission,yearly_interest,planning_horizon
0.0793,0,0.7,0.0606,0,0.3046,0,0,0,0,0,0,0,0,0,0,0,0.401,0.21,0.03,20
type,path,unit
demand_electric,generate,h
demand_heat,generate,h
irradiance,input_files/data/irradiance/Lindenberg2006BSRN_Irradiance_60sec.csv,min
temperature,input_files/data/temperature/temperature.csv,h
comp_name,comp_type,model,min_size,max_size,current_size,inv_pv_bat,battery,grd,elec_cns
inv_pv_bat,Inverter,STP-7000TL-20,0,20,0,0,1,1,1
battery,LiionBattery,BAT1,0,6,6,1,0,0,0
grd,StandardACGrid,GRD1,1000,1000,1000,1,0,0,1
elec_cns,StandardElectricalConsumption,CNS1,1000,1000,0,0,0,0,0
injection_price,injection_price_variable,injection/pvpeak,gas_price,gas_price_variable,elec_price,elec_price_variable,network_usage_capacity_fee_low,network_usage_energy_fee_low,network_usage_capacity_fee_high,network_usage_energy_fee_high,heat_price,levies_int,levies_ext,concession,electricity_tax_int,electricity_tax_ext,VAT,heat_price_variable,cooling_price,cooling_price_variable,injection_price_gas,injection_price_gas_variable,injection_price_heat,injection_price_heat_variable,injection_price_cooling,injection_price_cooling_variable,elec_emission,gas_emission,yearly_interest,planning_horizon
0.0793,0,0.7,0.0606,0,0.3046,0,14.79,0.0506,50.54,0.0363,0,0.0276,0.0496,0.0199,0,0.0205,0.190,0,0,0,0,0,0,0,0,0,0.401,0.21,0.03,20
type,path,unit
elec_price,input_files/data/prices/day-ahead/hourly_price.csv,h
comp_name,comp_type,model,min_size,max_size,current_size,pv_roof,inv_pv_bat,battery,grd,elec_cns
pv_roof,StandardPVGenerator,PV2,6,6,6,0,1,0,0,0
inv_pv_bat,Inverter,STP-7000TL-20,0,20,0,0,0,1,1,1
battery,LiionBattery,BAT1,6,6,6,0,1,0,0,0
grd,StandardACGrid,GRD1,1000,1000,1000,0,1,0,0,1
elec_cns,StandardElectricalConsumption,CNS1,1000,1000,0,0,0,0,0,0
# runme.py is the central script to execute the optimization of the community.
# Importing the necessary files
import numpy as np
import Model_Library.District.scripts as scripts
from datetime import timedelta
import math
import time
import pandas as pd
import Model_Library.Prosumer.scripts as scripts
import Model_Library.Prosumer.main as main
import Model_Library.Prosumer.scripts.extract_inputs as extract_inputs
from functools import partial
from multiprocessing import Pool
from tqdm import tqdm
import os
import argparse
from Model_Library.Prosumer.scripts.results_evaluation.results_evaluation import Plot_savings
import Model_Library.Prosumer.main_ca as main_ca
import Model_Library.District.main_district as main_district
def process_each_prosumer(prosumer_name, prosumer_dict, data_source, commentary, no_process_bar_rh):
try:
# PLEASE CHANGE HERE
# Set the simulation time frame and optional rolling horizon configurations:
# 't_start': start date of simulations, Unit: JJJJ-MM-DD hh:mm:ss
# 't_end': end date of simulations, Unit: JJJJ-MM-DD hh:mm:ss
# 't_step': granularity of optimization model, Unit: hours
# Rolling horizon (RH) can be set by:
# 't_rh_horizon': width of rolling horizon intervals, Unit: hours, MINIMUM VALUE: 2 !!!
# 't_rh_shift': rolling horizon shift between intervals, Unit: hours
# 't_current_value_length': number of values at beginning of rolling horizon interval that are replaced by real values, Unit: hours
# 't_history': number of days before actual simulation interval for the demand generator to be able to make required predictions
if prosumer_dict[prosumer_name]['rolling_horizon']:
t_start = pd.Timestamp("2019-09-01 00:00:00")
t_end = pd.Timestamp("2019-09-01 5:00:00")
t_step = 1
t_rh_horizon = 3
t_rh_shift = 1
t_current_value_length = 2
t_history = 14 # days
# PLEASE CHANGE HERE
# Prediction settings
predictions = {'demand_electric': 'SameHourYesterday',
'demand_heat': 'SameHourYesterday',
'day_ahead_price': 'SameHourYesterday',
'intraday_price': 'SameHourYesterday',
'solar_radiation': 'Perfect',
# currently the method generate_g_t_series takes the same t_start as the prediction -> no historical
# data for the prediction available: easy fix would be to set a minus time delta in the t_start
# argument of generate_g_t_series
'temperature': 'SameHourYesterday'}
else:
t_start = pd.Timestamp("2019-07-01 00:00:00")
t_end = pd.Timestamp("2019-7-10 23:00:00") + pd.Timedelta(hours=1)
t_step = 1
t_rh_horizon = (t_end - t_start) / pd.Timedelta(hours=1)
t_rh_shift = t_rh_horizon - 1
t_current_value_length = t_rh_horizon
t_history = 0 # days
# PLEASE CHANGE HERE
# Prediction settings
predictions = {'demand_electric': 'Perfect',
'demand_heat': 'Perfect',
'day_ahead_price': 'Perfect',
'intraday_price': 'Perfect',
'solar_radiation': 'Perfect',
# currently the method generate_g_t_series takes the same t_start as the prediction -> no historical
# data for the prediction available: easy fix would be to set a minus time delta in the t_start
# argument of generate_g_t_series
'temperature': 'Perfect'}
# Fixed variables - DO NOT CHANGE
storage_states = {}
interim_results = {}
final_iteration = False
# Set aggregation options
parser = argparse.ArgumentParser(description='Start optimization from DB or local data')
parser.add_argument('-a', '--aggregate', action="store_true", dest="aggregate",
help="activating aggregation of input time series", default=False)
options = parser.parse_args()
# Calculate number of rolling horizon intervals and loop through them
for t in tqdm(pd.date_range(t_start, t_end - pd.Timedelta(hours=t_rh_shift + 1), freq=str(t_rh_shift) + 'H'), disable=no_process_bar_rh):
# ToDo: replace first value with perfect value (can be done in runme)
# set end date for current loop
t_end_loop = t + pd.Timedelta(hours=t_rh_horizon)
# exceptions that occur at global end of simulation horizon
if t_end_loop > t_end:
t_end_loop = t_end
if t_current_value_length > (t_end_loop - t) / pd.Timedelta(hours=1):
t_current_value_length = (t_end_loop - t) / pd.Timedelta(hours=1)
# Set flag for final iteration
if t == t_end - pd.Timedelta(hours=t_rh_shift + 1):
final_iteration = True
# Start main programme
prosumer = main.Main(data_source, {prosumer_name: prosumer_dict[prosumer_name]}, t, t_end_loop, t_step,
predictions, t_current_value_length, t_end,
t_history, commentary, storage_states, t_rh_shift, aggregation=options.aggregate)
# Run optimization
prosumer.run_optimization(prosumer.prosumer_name_list)
# Show results - Results are only plotted after last iteration of rolling horizon
prosumer.show_results(prosumer.prosumer_name_list, interim_results, final_iteration)
# Get storage states from this iteration
storage_states = prosumer.charge_status
# Get interim results of current rolling horizon interval
interim_results = prosumer.interim_results
return prosumer.prosumer[prosumer_name]
except ValueError:
print(prosumer_name+" could not be optimized!")
# # MAIN PROGRAM -------------------------------------------------------------------------------------------------------
if __name__ == "__main__":
# Initialization scenario path and global variables for the prosumer optimization
# Start timer
start = time.time()
# PLEASE CHANGE HERE
# Path to local data - this is only used when selecting local mode
# 'topology_path': path to matrices that define the prosumer topology
# 'config_path': path to global configurations like prices, injection prices, emission costs, etc.
#topology_path = 'input_files/models/Study_Base'
#config_path = topology_path + '/config.csv'
#data_path = topology_path + '/data_path.csv'
#prosumer_name = 'office'
#prosumer_dict = {prosumer_name: {'topology_path': topology_path, 'config_path': config_path, 'data_path': data_path}}
topology_path = ['input_files/models/prosumer_models/SCN0_CAT1']
prosumer_name = ['SCN0_CAT1', 'SCN0_CAT1']
rolling_horizon = [False]
elec_demand = [1500, 10000]
therm_demand = [5000, 20000]
hot_water_demand = 1500#[1500, 1500]
step_elec_demand = 500
step_therm_demand = 500
#step_hot_water_demand = 0
prosumer_dict = {}
""" for i in range(len(prosumer_name)):
for j in range(elec_demand[0], elec_demand[1], step_elec_demand):
for k in range(therm_demand[0], therm_demand[1], step_therm_demand):
#for l in range(hot_water_demand[0], hot_water_demand[1], step_hot_water_demand):
prosumer_dict[prosumer_name[i]+'_'+str(j)+'_'+str(k)] = {'elec_demand': j,
'therm_demand': k,
'hot_water_demand': hot_water_demand,
'topology_path': topology_path[i],
'config_path': topology_path[i] + '/config.csv',
'data_path': topology_path[i] + '/data_path.csv',
'rolling_horizon': rolling_horizon[i]}"""
prosumer_dict={'SCN2_CAT1_PV11_3000_6000': {'elec_demand': 3000, 'therm_demand': 6000, 'hot_water_demand': 1500,
'topology_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV11',
'config_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV11/config.csv',
'data_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV11/data_path.csv',
'rolling_horizon': False},
'SCN2_CAT1_PV12_BA_6000_6000': {'elec_demand': 6000, 'therm_demand': 6000, 'hot_water_demand': 1500,
'topology_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV12_BA',
'config_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV12_BA/config.csv',
'data_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV12_BA/data_path.csv',
'rolling_horizon': False},
'SCN0_CAT1_6000_6000': {'elec_demand': 6000, 'therm_demand': 6000, 'hot_water_demand': 1500,
'topology_path': 'input_files/models/prosumer_models/SCN0_CAT1',
'config_path': 'input_files/models/prosumer_models/SCN0_CAT1/config.csv',
'data_path': 'input_files/models/prosumer_models/SCN0_CAT1/data_path.csv',
'rolling_horizon': False},
'SCN0_CAT1_3000_6000': {'elec_demand': 3000, 'therm_demand': 6000, 'hot_water_demand': 1500,
'topology_path': 'input_files/models/prosumer_models/SCN0_CAT1',
'config_path': 'input_files/models/prosumer_models/SCN0_CAT1/config.csv',
'data_path': 'input_files/models/prosumer_models/SCN0_CAT1/data_path.csv',
'rolling_horizon': False}}
# PLEASE CHANGE HERE
# Select data source
# Options: '1': import from database, '2': import from local folder
data_source = 2
reference_results = {}
commentary = False
no_process_bar_rh = True
parallel_processing = False
# Timer output
tic = time.time()
# Start program
# Run multiple independent prosumers in parallel on multiple cores
final_prosumer_dict = dict.fromkeys(prosumer_dict.keys())
if parallel_processing:
count_processes = len(prosumer_dict.keys())
pool = Pool(os.cpu_count())
parallel_func = partial(process_each_prosumer, prosumer_dict=prosumer_dict, data_source=data_source, commentary=commentary, no_process_bar_rh=no_process_bar_rh)
mapped_values = list(tqdm(pool.map(parallel_func, list(prosumer_dict.keys())), total=count_processes))
# Normal processing, one core only
else:
for prosumer_name in list(prosumer_dict.keys()):
final_prosumer_dict[prosumer_name] = process_each_prosumer(prosumer_name= prosumer_name, prosumer_dict=prosumer_dict, data_source=data_source, commentary=commentary, no_process_bar_rh=no_process_bar_rh)
# Timer output
toc = time.time()
if reference_results:
for topology in prosumer_name:
Plot_savings(reference_results, topology)
# Timer output
end = time.time()
# Additional console output
if commentary:
print("============ Execution Times =============")
print("Pre-processing [s]: \t" + str(tic - start))
#print("(Interaction with database [s]:\t" + str(prosumer.connect_with_db) + ")")
print("Optimization [s]: \t" + str(toc - tic))
print("Post-processing [s]: \t" + str(end - toc))
print("----------------------------------------")
print("Total [s]: \t" + str((end - toc) + (toc - tic) + (tic - start)))
print("==========================================")
'-----------------COMMUNITY-PART----------------------------------'
start_total = time.time()
data_source = 2 # [1]: datasource from data bank; [2]: datasource from local
commentary = False
t_start = pd.Timestamp("2019-07-01 00:00:00")
t_end = pd.Timestamp("2019-07-10 23:00:00") + pd.Timedelta(hours=1)
t_step = 1
t_rh_horizon = (t_end - t_start) / pd.Timedelta(hours=1)
t_horizon = (pd.Timestamp(t_end) - pd.Timestamp(t_start)) / np.timedelta64(t_step, 'h')
"------------------------Communnity Asset---------------------------"
"-------------------------------------------------------------------"
topology_path = 'input_files/models/district_models/example_CA'
config_path = topology_path + '/config.csv'
data_path = topology_path + '/data_path.csv'
ca_dict = {'ca_bat': {'elec_demand': 0,
'therm_demand': 0,
'hot_water_demand': 0,
'topology_path': topology_path,
'config_path': config_path,
'data_path': data_path}}
#ca_dict = {}
# PLEASE CHANGE HERE
# Prediction settings
predictions = {'demand_electric': 'SameHourYesterday',
'demand_heat': 'SameHourYesterday',
'day_ahead_price': 'SameHourYesterday',
'intraday_price': 'SameHourYesterday',
'solar_radiation': 'Perfect',
# currently the method generate_g_t_series takes the same t_start as the prediction -> no historical
# data for the prediction available: easy fix would be to set a minus time delta in the t_start
# argument of generate_g_t_series
'temperature': 'SameHourYesterday'}
# Fixed variables - DO NOT CHANGE
storage_states = {}
interim_results = {}
final_iteration = False
ca_strategy = 'sizing_max_operational_profit'
# create time steps list
time_steps = []
for t in pd.date_range(pd.Timestamp(t_start),
pd.Timestamp(t_start) + timedelta(hours=t_horizon) - timedelta(hours=t_step),
freq=str(t_step)+'H'):
time_steps.append(t)
t_start = pd.Timestamp(t_start)
t_end = pd.Timestamp(t_start) + timedelta(hours=t_horizon) - timedelta(hours=t_step)
t_rh_shift = 0
t_current_value_length = (t_end-t_start)/np.timedelta64(t_step, 'h')
t_history = t_horizon/24
# initialize community component in the same way prosumers are.
# The difference is that they are not directly optimized
comm_assets = main.Main_CA(data_source, ca_dict, t_start, t_end, t_step, predictions, t_current_value_length, t_end,
t_history, commentary, storage_states, t_rh_shift, aggregation=False)
"""---------------------------COMMUNITY-LEVEL----------------------"""
"""----------------------------------------------------------------"""
topology_path = 'input_files/models/district_models/example_community'
config_path = topology_path + '/config.csv'
data_path_comm = topology_path + '/data_path.csv'
comm_dict = {'community': {'topology_path': topology_path, 'config_path': config_path, 'data_path': data_path_comm}}
comm_strategy = ['max_operational_profit']
community_main = main_district.MainDistrict(final_prosumer_dict,
comm_assets,
time_steps,
t_step,
comm_dict,
ca_strategy,
comm_strategy,
t_horizon)
# ------------POST-PROCESS-----------------
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment