From de2686f8004811a2432abb311f3a576776af0b39 Mon Sep 17 00:00:00 2001 From: Jonas Paul Brucksch <jonas.brucksch@isea.rwth-aachen.de> Date: Mon, 26 Sep 2022 10:33:48 +0200 Subject: [PATCH] - adds .lp files to gitignore - changes according to my Todos - deletes old "runme_community" file and renames the "runme_community_new" file to "runme_community" --- .gitignore | 2 +- Model_Library | 2 +- runme_community.py | 328 +++++++---------------------------------- runme_community_new.py | 315 --------------------------------------- 4 files changed, 53 insertions(+), 594 deletions(-) delete mode 100644 runme_community_new.py diff --git a/.gitignore b/.gitignore index df67790660..b2525f5410 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ var/ *.egg-info/ .installed.cfg *.egg - +.lp # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. diff --git a/Model_Library b/Model_Library index 58a920d79c..e865185fd9 160000 --- a/Model_Library +++ b/Model_Library @@ -1 +1 @@ -Subproject commit 58a920d79c827c5a9da7203ba3ebe95cbac64608 +Subproject commit e865185fd95a787af218873e1f58b23fc9f3f849 diff --git a/runme_community.py b/runme_community.py index 519e700164..39f1b9ae7b 100644 --- a/runme_community.py +++ b/runme_community.py @@ -1,36 +1,16 @@ # runme.py is the central script to execute the optimization of the community. -""" -The FEN-Tool is an optimisation tool for prosumer, district, and interconnected city models. -Copyright (C) 2022. Mauricio Celi Cortés, Jingyu Gong, Jonas van Ouwerkerk, Felix Wege, Nie Yi, Jonas Brucksch - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public License -as published by the Free Software Foundation; either version 3 of -the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Project host: RWTH Aachen University, Aachen, Germany -Project Website: https://www.fenaachen.net/projekte/fen-ineed-dc -""" # 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 @@ -39,8 +19,7 @@ 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.model as comm_model +import Model_Library.District.main_district as main_district def process_each_prosumer(prosumer_name, prosumer_dict, data_source, commentary, no_process_bar_rh): @@ -109,7 +88,6 @@ def process_each_prosumer(prosumer_name, prosumer_dict, data_source, commentary, # 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) @@ -181,8 +159,26 @@ if __name__ == "__main__": 'data_path': topology_path[i] + '/data_path.csv', 'rolling_horizon': rolling_horizon[i]}""" - prosumer_dict={'SCN2_CAT1_PV14_HP_3000_6000_1': {'elec_demand': 3000, 'therm_demand': 6000, 'hot_water_demand': 1500, 'topology_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV14_HP', 'config_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV14_HP/config.csv', 'data_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV14_HP/data_path.csv', 'rolling_horizon': False}, - 'SCN2_CAT1_PV14_HP_3000_6000_2': {'elec_demand': 1500, 'therm_demand': 6000, 'hot_water_demand': 1500, 'topology_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV14_HP', 'config_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV14_HP/config.csv', 'data_path': 'input_files/models/prosumer_models/SCN2_CAT1_PV14_HP/data_path.csv', 'rolling_horizon': False}} + 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 @@ -234,18 +230,25 @@ 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-7-10 23:00:00") + pd.Timedelta(hours=1) +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/district_models/jbr_test_ca' +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': {'topology_path': topology_path, 'config_path': config_path, 'data_path': data_path}} -ca_dict = {} +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', @@ -263,14 +266,8 @@ storage_states = {} interim_results = {} final_iteration = False -# ca_strategy = 'sizing_min_costs' -# ca_strategy = 'sizing_max_wholesale_profit' ca_strategy = 'sizing_max_operational_profit' -comm_strategy_list = ['max_operational_profit'] - -tax_model = 'no internal taxes' # no internal taxes - # create time steps list time_steps = [] for t in pd.date_range(pd.Timestamp(t_start), @@ -284,255 +281,32 @@ t_rh_shift = 0 t_current_value_length = (t_end-t_start)/np.timedelta64(t_step, 'h') t_history = t_horizon/24 -"""---------------------------COMMUNITY-LEVEL----------------------""" -"""----------------------------------------------------------------""" - # initialize community component in the same way prosumers are. # The difference is that they are not directly optimized -start_ca_init = time.time() -comm_assets = main_ca.Main(data_source, ca_dict, t_start, t_end, t_step, predictions, t_current_value_length, t_end, +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) -end_ca_init = time.time() -topology_path = 'input_files/models/district_models/jbr_test_comm' + +"""---------------------------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}} -# Initialize community -# injection price: 2019 # changes with size! -# bis10kwp: 8.16 (01.01.21), bis 40: 7.93 -# (https://www.solaranlagen-portal.com/photovoltaik/wirtschaftlichkeit/einspeiseverguetung) -# network usage fees: all from Regionetz -# levy reduction: just 40% of EEG is calculated for self consumed electricity -# (as in https://www.buendnis-buergerenergie.de/fileadmin/user_upload/2020-03-06_EnergyBrainpool_Impulspapier-Energy-Sharing.pdf) -# general levies: https://www.netztransparenz.de/ -# consession fees: city of Aachen ( < 500000 people) # (ct/kWh) -# https://www.acteno.de/ecms/de/energieanwendungen-4-0/konzessionsabgabe.html -# electrixity tax reduction: assumption from https://www.buendnis-buergerenergie.de/fileadmin/user_upload/2020-03-06_EnergyBrainpool_Impulspapier-Energy-Sharing.pdf -comm_config = {'injection_price': pd.Series(data=0.0793, index=time_steps), - 'injection/pvpeak': 0.7, - 'gas_price': 0.0606, # 2019 https://www.verivox.de/gas/verbraucherpreisindex/ - 'network_usage_capacity_fee_low': 14.79, # in €/kWa if yearly full load hours are less than 2500 h - 'network_usage_energy_fee_low': 0.0506, # in €/kWh if yearly full load hours are less than 2500 h - # high tariffs are not used for now. - # The program does not know if the community has less or more than 2500 full load hours - 'network_usage_capacity_fee_high': 50.54, # in €/kWa if yearly full load hours are more than 2500 h - 'network_usage_energy_fee_high': 0.0363, # in €/kWh if yearly full load hours are more than 2500 h - 'levies_int': 0.0276, - 'levies_ext': 0.0496, # in ct/kWh (KWK Umlage + Offshore Umlage + AbLV Umlage + StromNEV Umlage + EEG) - 'concession': 0.0199, - 'electricity_tax_int': 0, - 'electricity_tax_ext': 0.0205, # in ct/kWh if not self consumed - 'VAT': 0.19, # in % - 'heat_price': 0, - 'cooling_price': 0, - 'injection_price_gas': 0, - 'injection_price_heat': 0, - 'injection_price_cooling': 0, - 'elec_emission': 0.401, # 2019 - 'gas_emission': 0.21, - 'yearly_interest': 0.03, # letmathe - 'planning_horizon': 20} - -comm_data_path_dict = dict.fromkeys('community') -comm_data_path_dict['community'] = scripts.extract_inputs.get_path(data_path_comm) -comm_data = scripts.extract_inputs.run(comm_data_path_dict, 'community', 1) -elec_price = comm_data['elec_price'].iloc[:,0] - -comm_config['spot_price'] = elec_price -comm_config['injection_price'] = elec_price - -if tax_model == 'no internal taxes': - comm_config['elec_price_int_low'] = comm_config['spot_price'] - comm_config['elec_price_int_high'] = comm_config['spot_price'] - -elif tax_model == 'internal taxes': - comm_config['elec_price_int_low'] = (comm_config['spot_price'] + comm_config['network_usage_energy_fee_low'] - + comm_config['levies_int'] + comm_config['concession'] + comm_config[ - 'electricity_tax_int']) \ - * (1 + comm_config['VAT']) - comm_config['elec_price_int_high'] = (comm_config['spot_price'] + comm_config['network_usage_energy_fee_high'] - + comm_config['levies_int'] + comm_config['concession'] + comm_config[ - 'electricity_tax_int']) \ - * (1 + comm_config['VAT']) - -else: - print('No valid tax model') - -comm_config['elec_price_ext_low'] = (comm_config['spot_price'] + comm_config['network_usage_energy_fee_low'] - + comm_config['levies_ext'] + comm_config['concession'] + comm_config[ - 'electricity_tax_ext']) \ - * (1 + comm_config['VAT']) -comm_config['elec_price_ext_high'] = (comm_config['spot_price'] + comm_config['network_usage_energy_fee_high'] - + comm_config['levies_ext'] + comm_config['concession'] + comm_config[ - 'electricity_tax_ext']) \ - * (1 + comm_config['VAT']) - -# Create object of BaseCommunity-class -#ToDo JBR: has to happen in community main -start_comm_init = time.time() - -community = comm_model.BaseComm('TestComm', {'Prosumer': final_prosumer_dict, 'Comm_Comps': comm_assets.comm_assets}, - time_steps, {'Prosumer': final_prosumer_dict.keys(), 'Comm_Comps': comm_assets.comm_assets.keys()}, - t_step, comm_config, ca_strategy) -end_comm_init = time.time() - -"""---------------------ROLLING HORIZON (RH) ------------------------------------------------------------------------""" -"""-----------------------------------------------------------------------------------------------------------------""" - -t_overlap_default = 0 # deafult: 0; nr of timesteps the starting point of each interval is shifted into the prior interval -t_interval_default = 4*24 # default: 4*24; number of time steps in one interval of the RH - -t_start_rh = time_steps[0] # start of -t_last = 0 - -t_interval = t_interval_default / t_step -last_t_interval = t_interval_default / t_step - -last_t_overlap = t_overlap_default / t_step -t_overlap = t_overlap_default / t_step - -start_rh = time.time() -n_change = 0 - -while t_last * t_step < t_horizon: - print('-------------------' + str(t_last) + '-----------------') - - # PREPARE INTERVAL - if (t_last + t_interval - t_overlap) * t_step < t_horizon and (t_last + t_interval) * t_step <= t_horizon: - # interval does not reach overall end - t_horizon_rh = int(t_interval) # number of time steps in this RH-interval - t_fix = max(t_horizon_rh - int(t_overlap), 1) # number of fixed time steps of this RH-interval - elif (t_last + t_interval - t_overlap) * t_step < t_horizon and (t_last + t_interval) * t_step > t_horizon: - # interval reaches end of horizon, but just without overlap - t_horizon_rh = int(len(time_steps) - t_last) # interval length is adapted - t_fix = max(int(t_interval) - int(t_overlap), 1) # but not the number of fixed time steps - else: - # fixed time steps hit overall time horizon --> adapt also the fixed time steps - t_horizon_rh = int(len(time_steps) - t_last) - t_fix = t_horizon_rh - - # extract relevant timesteps values from overall time series - time_steps_rh = time_steps[t_last:t_last + t_horizon_rh] # whole interval size - time_steps_fix = time_steps[t_last:t_last + t_fix] # without overlap - - # STEP 1 --> SCHEDULE EXTRACTION - start_schedule = time.time() - for ps in final_prosumer_dict.values(): - valid = ps.calc_rh_step_schedule(time_steps_rh) - if not valid: - n_change += 1 - t_interval = int(math.floor(t_interval / 2)) - if t_interval == 0: - t_interval = 1 - if t_interval < t_overlap: - t_overlap = t_interval - 1 - break - - if not valid: - continue - - for cc in community.comm_assets.values(): - valid = cc.calc_rh_step_schedule(time_steps_rh) - if not valid: - n_change += 1 - t_interval = int(math.floor(t_interval / 2)) - if t_interval == 0: - t_interval = 1 - if t_interval < t_overlap: - t_overlap = t_interval - 1 - break - - if not valid: - continue - - end_schedule = time.time() - - # STEP 2 --> DF IDENTIFICATION - start_flex_calc = time.time() - for ps in final_prosumer_dict.values(): - ps.calc_flex(time_steps_rh) - - for cc in community.comm_assets.values(): - cc.calc_flex(time_steps_rh) - - # aggregate prosumer DFs in community - community.aggregate_temp(time_steps_rh, final_prosumer_dict, community.comm_assets) - end_flex_calc = time.time() - - # COMMUNITY OPTIMIZATION - start_opt = time.time() - valid = community.run_optimization(time_steps_rh, comm_strategy_list, timelimit=200) - - if not valid: - n_change += 1 - t_interval = int(math.floor(t_interval / 2)) - if t_interval == 0: - t_interval = 1 - if t_interval < t_overlap: - t_overlap = t_interval - 1 - continue - end_opt = time.time() - - # VALIDATION - start_validation = time.time() - valid = community.validate_result(time_steps_fix) - if valid: - # fix results... - for ps in final_prosumer_dict.values(): - ps.fix_results(time_steps_fix) - for cc in community.comm_assets.values(): - cc.fix_results(time_steps_fix) - community.aggregate_fix(time_steps_fix) - - # ...and go to next interval - t_last = int(t_last + max(t_interval - t_overlap, 1)) - t_interval = t_interval_default * 1 / t_step - t_overlap = t_overlap_default * 1 / t_step - - elif not valid: - # nr of interval changes - n_change += 1 - t_interval = int(math.floor(t_interval / 2)) - if t_interval == 0: - t_interval = 1 - if t_interval < t_overlap: - t_overlap = t_interval - 1 - - if not valid and t_interval < 1: - print('Unteres Limit erreicht') - end_validation = time.time() - -end_rh = time.time() +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----------------- -start_analysis = time.time() -community.analyze_results_new() -# community.plot_grid_exchange() -end_analysis = time.time() - -start_write = time.time() -folder_name = 'EC_' + str(len(final_prosumer_dict)) + '_' + str(t_horizon / 24) + '_' + str(t_interval_default) + '_' + str(t_overlap_default) -flag = True -iter = 0 -while flag: - #ToDo JBR: apply Felix changes - try: - os.mkdir('output_files/' + folder_name) - flag = False - except FileExistsError: - iter += 1 - folder_name = folder_name + '_' + str(iter) -#ToDO jbr: fix this later when the new main is working -""" -prosumers.show_results_agents(final_prosumer_dict.keys(), folder_name) -if comm_assets: - comm_assets.show_results_agents(comm_assets.comm_assets.keys(), folder_name) -#Todo JBR: change to community main -prosumers.export_comm(community, time_steps, folder_name) -""" -end_write = time.time() -end_total = time.time() + diff --git a/runme_community_new.py b/runme_community_new.py deleted file mode 100644 index cb2fea46b0..0000000000 --- a/runme_community_new.py +++ /dev/null @@ -1,315 +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----------------- - - - - - -- GitLab