From 36302210d3ba874edb211896cfc2760b752f1f97 Mon Sep 17 00:00:00 2001 From: FranziPl Date: Mon, 7 Sep 2020 14:25:16 +0200 Subject: [PATCH] Add the model for solar cooling --- .../experiment_config/experiment_0.yml | 30 ++ solar_cooling/src/electric_model.py | 314 +++++++++++++ .../src/electric_results_processing.py | 354 ++++++++++++++ solar_cooling/src/main.py | 58 +++ solar_cooling/src/thermal_model.py | 434 +++++++++++++++++ .../src/thermal_results_processing.py | 437 ++++++++++++++++++ 6 files changed, 1627 insertions(+) create mode 100644 solar_cooling/experiment_config/experiment_0.yml create mode 100644 solar_cooling/src/electric_model.py create mode 100644 solar_cooling/src/electric_results_processing.py create mode 100644 solar_cooling/src/main.py create mode 100644 solar_cooling/src/thermal_model.py create mode 100644 solar_cooling/src/thermal_results_processing.py diff --git a/solar_cooling/experiment_config/experiment_0.yml b/solar_cooling/experiment_config/experiment_0.yml new file mode 100644 index 0000000..16fabf8 --- /dev/null +++ b/solar_cooling/experiment_config/experiment_0.yml @@ -0,0 +1,30 @@ +# Configuration for Oman_model +# Date: Thu 26th of November 2018 +# Author: Franziska + +exp_name: Referenz +exp_number: 0 +number_of_variations: 1 + +run_model_thermal: False +run_postprocessing_thermal: True + +run_model_electric: False +run_postprocessing_electric: True + +debug: False +solver: 'cbc' +solver_verbose: True +number_timesteps: 8760 + +# Parameters for the energy system +parameters_system: 'parameters_experiment_0.csv' +parameters_variation: + - 'parameters_variation_base.csv' + +# Preprocessed data +time_series_file_name: 'time_series.csv' + +# plot data +start_of_plot: 4000 +end_of_plot: 4100 diff --git a/solar_cooling/src/electric_model.py b/solar_cooling/src/electric_model.py new file mode 100644 index 0000000..7d781ef --- /dev/null +++ b/solar_cooling/src/electric_model.py @@ -0,0 +1,314 @@ +# -*- coding: utf-8 -*- +""" +Created on Dez 06 2018 + +@author: Franziska Pleissner + +System C: concrete example: Model of cooling process + with a compression chiller and a pv modul + + + input/output electr. cool waste ambient(/ground) + +grid_el |---------->| | | + | | | | +pv |---------->| | | + | | | | + |<----------| | | +compression_chiller|------------------>| | + |-------------------------->| + | | | | +cooling_tower |<--------------------------| + |<----------| | | | + |---------------------------------->| + | | | | +aquifer |<--------------------------| + |<----------| | | | + |---------------------------------->| + | | | | +storage_electricity|---------->| | | + |<----------| | | + | | | | +storage_cool |------------------>| | + |<------------------| | + | | | | +demand |<------------------| | + | | | | +excess |<----------| | | + + +""" + +############ +# Preamble # +############ + +# Import packages +from oemof.tools import logger, economics +import oemof.solph as solph +import oemof.solph.processing as processing + +import logging +import os +import yaml +import pandas as pd +import pyomo.environ as po + +# import oemof plots +try: + import matplotlib.pyplot as plt +except ImportError: + plt = None + + +def ep_costs_func(capex, n, opex, wacc): + ep_costs = economics.annuity(capex, n, wacc) + capex * opex + return ep_costs + + +def run_model_electric(config_path, var_number): + + with open(config_path, 'r') as ymlfile: + cfg = yaml.load(ymlfile) + + if cfg['debug']: + number_of_time_steps = 3 + else: + number_of_time_steps = cfg['number_timesteps'] + + solver = cfg['solver'] + debug = cfg['debug'] + solver_verbose = cfg['solver_verbose'] # show/hide solver output + + # ## Read data and parameters ## # + + # define the used directories + abs_path = os.path.dirname(os.path.abspath(os.path.join(__file__, '..'))) + results_path = abs_path + '/results' + data_ts_path = abs_path + '/data/data_confidential/' + data_param_path = abs_path + '/data/data_public/' + + # Read parameter values from parameter file + if type(cfg['parameters_variation']) == list: + file_path_param_01 = data_param_path + cfg['parameters_system'] + file_path_param_02 = data_param_path + cfg['parameters_variation'][ + var_number] + elif type(cfg['parameters_system']) == list: + file_path_param_01 = data_param_path + cfg['parameters_system'][ + var_number] + file_path_param_02 = data_param_path + cfg['parameters_variation'] + else: + file_path_param_01 = data_param_path + cfg['parameters_system'] + file_path_param_02 = data_param_path + cfg['parameters_variation'] + param_df_01 = pd.read_csv(file_path_param_01, index_col=1) + param_df_02 = pd.read_csv(file_path_param_02, index_col=1) + param_df = pd.concat([param_df_01, param_df_02], sort=True) + param_value = param_df['value'] + + # Import PV and demand data + data = pd.read_csv((data_ts_path + cfg['time_series_file_name'])) + + # Redefine ep_costs_function: + def ep_costs_f(capex, n, opex): + return ep_costs_func(capex, n, opex, param_value['wacc']) + + # Initiate the logger + logger.define_logging( + logfile='electric_model_{0}_{1}.log'.format( + cfg['exp_number'], var_number), + logpath=results_path + '/logs', + screen_level=logging.INFO, + file_level=logging.DEBUG) + + date_time_index = pd.date_range('1/1/2017', + periods=number_of_time_steps, + freq='H') + + # Initialise the energysystem + logging.info('Initialize the energy system') + + energysystem = solph.EnergySystem(timeindex=date_time_index) + + ####################### + # Build up the system # + ####################### + + # Busses + + bco = solph.Bus(label="cool") + bwh = solph.Bus(label="waste") + bel = solph.Bus(label="electricity") + bam = solph.Bus(label="ambient") + + energysystem.add(bco, bwh, bel, bam) + + # Sinks and sources + + ambience = solph.Sink( + label='ambience', + inputs={bam: solph.Flow()}) + + grid_el = solph.Source( + label='grid_el', + outputs={bel: solph.Flow( + variable_costs=(param_value['price_electr'] + * float(param_value['price_electr_variation'])))}) + + pv = solph.Source( + label='pv', + outputs={bel: solph.Flow( + fix=data['pv_normiert'], + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_pv_output_el_09708'], + param_value['lifetime_pv'], + param_value['opex_pv'])))}) # Einheit: 0,9708 kWpeak + + demand = solph.Sink( + label='demand', + inputs={bco: solph.Flow( + fix=data['Cooling load kW'], + nominal_value=1)}) + + excess_el = solph.Sink( + label='excess_el', + inputs={bel: solph.Flow()}) + + energysystem.add(ambience, grid_el, pv, demand, excess_el) + + # Transformers + + chil = solph.Transformer( + label='compression_chiller', + inputs={bel: solph.Flow()}, + outputs={ + bco: solph.Flow( + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_compression_output_cool'], + param_value['lifetime_compression'], + param_value['opex_compression']))), + bwh: solph.Flow()}, + conversion_factors={ + bco: param_value['conv_factor_compression_output_cool'], + bwh: param_value['conv_factor_compression_output_waste']}) + + towe = solph.Transformer( + label='cooling_tower', + inputs={ + bwh: solph.Flow( + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_tower_input_th'], + param_value['lifetime_tower'], + param_value['opex_tower']))), + bel: solph.Flow()}, + outputs={bam: solph.Flow()}, + conversion_factors={ + bwh: param_value['conv_factor_tower_input_waste'], + bel: param_value['conv_factor_tower_input_el']}) + + energysystem.add(chil, towe) + + # storages + + if param_value['nominal_capacitiy_stor_cool'] == 0: + stor_co = solph.components.GenericStorage( + label='storage_cool', + inputs={bco: solph.Flow()}, + outputs={bco: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_cool'], + # invest_relation_input_capacity=1 / 6, + # invest_relation_output_capacity=1 / 6, + inflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_output'], + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_stor_cool_capacity'], + param_value['lifetime_stor_cool'], + param_value['opex_stor_cool']))) + else: + stor_co = solph.components.GenericStorage( + label='storage_cool', + inputs={bco: solph.Flow()}, + outputs={bco: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_cool'], + inflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_output'], + nominal_capacity=param_value['nominal_capacitiy_stor_cool']) + + if param_value['nominal_capacitiy_stor_el'] == 0: + stor_el = solph.components.GenericStorage( + label='storage_electricity', + inputs={bel: solph.Flow()}, + outputs={bel: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_el'], + inflow_conversion_factor=param_value[ + 'conv_factor_stor_el_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_el_output'], + investment=solph.Investment( + ep_costs=ep_costs_f( + (param_value['invest_costs_stor_el_capacity'] + * float(param_value['capex_stor_el_variation'])), + param_value['lifetime_stor_el'], + param_value['opex_stor_el']))) + + else: + stor_el = solph.components.GenericStorage( + label='storage_electricity', + inputs={bel: solph.Flow()}, + outputs={bel: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_el'], + inflow_conversion_factor=param_value[ + 'conv_factor_stor_el_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_el_output'], + nominal_capacity=param_value['nominal_capacitiy_stor_el']) + + energysystem.add(stor_co, stor_el) + + ######################################## + # Create a model and solve the problem # + ######################################## + + # Initialise the operational model (create the problem) with constrains + model = solph.Model(energysystem) + + # ## Add own constrains ## # + # Create a block and add it to the system + myconstrains = po.Block() + model.add_component('MyBlock', myconstrains) + demand_sum = sum(data['Cooling load kW']) + myconstrains.solar_constr = po.Constraint( + expr=((sum(model.flow[grid_el, bel, t] for t in model.TIMESTEPS)) + <= (demand_sum / param_value[ + 'conv_factor_compression_output_cool'] + * param_value['sol_fraction_el'] + * float(param_value['sol_fraction_el_variation'])))) + + logging.info('Solve the optimization problem') + model.solve(solver=solver, solve_kwargs={'tee': solver_verbose}) + + if debug: + filename = (results_path + '/lp_files/' + + 'electric_model_{0}_{1}.lp'.format(cfg['exp_number'], + var_number)) + logging.info('Store lp-file in {0}.'.format(filename)) + model.write(filename, io_options={'symbolic_solver_labels': True}) + + logging.info('Store the energy system with the results.') + + energysystem.results['main'] = processing.results(model) + energysystem.results['meta'] = processing.meta_results(model) + energysystem.results['param'] = ( + processing.parameter_as_dict(model)) + + energysystem.dump( + dpath=(results_path + '/dumps'), + filename='electric_model_{0}_{1}.oemof'.format( + cfg['exp_number'], var_number)) diff --git a/solar_cooling/src/electric_results_processing.py b/solar_cooling/src/electric_results_processing.py new file mode 100644 index 0000000..eb4e648 --- /dev/null +++ b/solar_cooling/src/electric_results_processing.py @@ -0,0 +1,354 @@ +# -*- coding: utf-8 -*- +""" +Created on Dez 06 2018 + +@author: Franziska Pleissner + +System C: concrete example: Plot ocooling process with a solar collector +""" + +############ +# Preamble # +############ + +# Import packages +import oemof.solph as solph +import oemof.solph.views as views +import oemof_visio as oev + +import logging +import os +import yaml +import pandas as pd +from electric_model import ep_costs_func + +# import oemof plots +try: + import matplotlib.pyplot as plt +except ImportError: + plt = None + +df_all_var = pd.DataFrame() + + +def electric_postprocessing(config_path, var_number): + global df_all_var + + with open(config_path, 'r') as ymlfile: + cfg = yaml.load(ymlfile) + + # define the used directories + abs_path = os.path.dirname(os.path.abspath(os.path.join(__file__, '..'))) + results_path = abs_path + '/results' + csv_path = results_path + '/optimisation_results/' + plot_path = results_path + '/plots/' + + energysystem = solph.EnergySystem() + energysystem.restore(dpath=(results_path + '/dumps'), + filename='electric_model_{0}_{1}.oemof'.format( + cfg['exp_number'], var_number)) + + sp = cfg['start_of_plot'] + ep = cfg['end_of_plot'] + + # Look up investment costs. Therefor parameters must read again. + if type(cfg['parameters_variation']) == list: + file_path_param_01 = abs_path + '/data/data_public/' + cfg[ + 'parameters_system'] + file_path_param_02 = abs_path + '/data/data_public/' + cfg[ + 'parameters_variation'][var_number] + elif type(cfg['parameters_system']) == list: + file_path_param_01 = abs_path + '/data/data_public/' + cfg[ + 'parameters_system'][var_number] + file_path_param_02 = abs_path + '/data/data_public/' + cfg[ + 'parameters_variation'] + else: + file_path_param_01 = abs_path + '/data/data_public/' + cfg[ + 'parameters_system'] + file_path_param_02 = abs_path + '/data/data_public/' + cfg[ + 'parameters_variation'] + param_df_01 = pd.read_csv(file_path_param_01, index_col=1) + param_df_02 = pd.read_csv(file_path_param_02, index_col=1) + param_df = pd.concat([param_df_01, param_df_02], sort=True) + param_value = param_df['value'] + + logging.info('results received') + + ######################### + # Work with the results # + ######################### + + cool_bus = views.node(energysystem.results['main'], 'cool') + waste_bus = views.node(energysystem.results['main'], 'waste') + el_bus = views.node(energysystem.results['main'], 'electricity') + ambient_res = views.node(energysystem.results['main'], 'ambient') + none_res = views.node(energysystem.results['main'], 'None') + + # sequences: + cool_seq = cool_bus['sequences'] + waste_seq = waste_bus['sequences'] + el_seq = el_bus['sequences'] + ambient_seq = ambient_res['sequences'] + + # scalars + cool_scal = cool_bus['scalars'] + waste_scal = waste_bus['scalars'] + el_scal = el_bus['scalars'] + none_scal = none_res['scalars'] + none_scal_given = views.node( + energysystem.results['param'], 'None')['scalars'] + el_scal[(('pv', 'electricity'), 'invest')] = ( + el_scal[(('pv', 'electricity'), 'invest')]*param_value['size_pv']) + # Conversion of the pv-investment-size, because Invest-object is normalized + # at 0.970873786 kWpeak + + # solar fraction + # electric: + # control_el (No Power must go from grid to excess) + df_control_el = pd.DataFrame() + df_control_el['grid_el'] = el_seq[(('grid_el', 'electricity'), 'flow')] + df_control_el['excess'] = el_seq[(('electricity', 'excess_el'), 'flow')] + df_control_el['Product'] = (df_control_el['grid_el'] + * df_control_el['excess']) + + el_from_grid = el_seq[(('grid_el', 'electricity'), 'flow')].sum() + el_from_pv = el_seq[(('pv', 'electricity'), 'flow')].sum() + el_to_excess = el_seq[(('electricity', 'excess_el'), 'flow')].sum() + el_pv_used = el_from_pv - el_to_excess + sol_fraction_el = el_pv_used / (el_pv_used + el_from_grid) + + # Power usage: + el_used = el_seq[(('grid_el', 'electricity'), 'flow')].sum() + + # Power to the output: + electricity_output = el_seq[(('electricity', 'excess_el'), 'flow')].sum() + electricity_output_pv = el_seq[(('pv', 'electricity'), 'flow')].sum() + + # ## costs ## # + + costs_total = energysystem.results['meta']['objective'] + + # storage costs must be subtract for reference scenario or added + # for the other scenarios. + + # reference scenario: + if param_value['nominal_capacitiy_stor_el'] == 0: + costs_total_wo_stor = ( + costs_total + - (none_scal[(('storage_electricity', 'None'), 'invest')] + * none_scal_given[ + (('storage_electricity', 'None'), 'investment_ep_costs')]) + - (none_scal[(('storage_cool', 'None'), 'invest')] + * none_scal_given[ + (('storage_cool', 'None'), 'investment_ep_costs')])) + # other scenarios: + else: + # calculation of ep_costs + ep_costs_el_stor = ep_costs_func( + param_value['invest_costs_stor_el_capacity'], + param_value['lifetime_stor_el'], + param_value['opex_stor_el'], + param_value['wacc']) + ep_costs_cool_stor = ep_costs_func( + param_value['invest_costs_stor_cool_capacity'], + param_value['lifetime_stor_cool'], + param_value['opex_stor_cool'], + param_value['wacc']) + # calculation of the scenario costs inclusive storage costs + costs_total_w_stor = ( + costs_total + + (none_scal_given[ + (('storage_cool', 'None'), 'nominal_capacity')] + * ep_costs_cool_stor) + + (none_scal_given[ + (('storage_electricity', 'None'), 'nominal_capacity')] + * ep_costs_el_stor)) + + ######################## + # Write results in csv # + ######################## + + # ## scalars ## # + # base scalars: + scalars_all = cool_scal\ + .append(waste_scal)\ + .append(el_scal)\ + .append(none_scal) + for i in range(0, none_scal_given.count()): + if 'nominal_capacity' in none_scal_given.index[i]: + scalars_all = pd.concat( + [scalars_all, + pd.Series([none_scal_given[i]], + index=[none_scal_given.index[i]])]) + + # solar fractions + scalars_all = pd.concat( + [scalars_all, + pd.Series([sol_fraction_el], + index=["('solar fraction', 'electric'), ' ')"])]) + if df_control_el['Product'].sum() != 0: + scalars_all = pd.concat( + [scalars_all, + pd.Series([df_control_el['Product'].sum()], + index=["Has to be 0!!!"])]) + + # various results + scalars_all = pd.concat( + [scalars_all, + pd.Series([el_used], + index=["('grid_el', 'electricity'), 'summe')"])]) + scalars_all = pd.concat( + [scalars_all, + pd.Series([electricity_output], + index=["('electricity', 'output'), 'summe')"])]) + scalars_all = pd.concat( + [scalars_all, + pd.Series([electricity_output_pv], + index=["('pv', 'electricity'), 'summe')"])]) + + # costs with or without storage (depends on reference scenario or not) + if param_value['nominal_capacitiy_stor_el'] != 0: + scalars_all = pd.concat( + [scalars_all, + pd.Series([costs_total_w_stor], + index=["('costs', 'w_stor'), 'per year')"])]) + scalars_all = pd.concat( + [scalars_all, + pd.Series([costs_total], + index=["('costs', 'wo_stor'), 'per year')"])]) + if param_value['nominal_capacitiy_stor_el'] == 0: + scalars_all = pd.concat( + [scalars_all, + pd.Series([costs_total_wo_stor], + index=["('costs', 'wo stor'), 'per year')"])]) + + # experiment number and variation + scalars_all = pd.concat( + [scalars_all, + pd.Series(['{0}_{1}'.format(cfg['exp_number'], var_number)], + index=["('Exp', 'Var'), 'number')"])]) + + # write scalars into csv for this experiment and variation + scalars_all.to_csv( + csv_path + 'electric_model_{0}_{1}_scalars.csv'.format( + cfg['exp_number'], var_number)) + + # write scalars for all variations of the experiment into csv + df_all_var = pd.concat([df_all_var, scalars_all], axis=1, sort=True) + if var_number == (cfg['number_of_variations']-1): + df_all_var.to_csv( + csv_path + + 'electric_model_{0}_scalars_all_variations.csv'.format( + cfg['exp_number'])) + logging.info('Writing DF_all_variations into csv') + + # ## sequences ## # + sequences_df = pd.merge(ambient_seq, waste_seq, left_index=True, + right_index=True) + sequences_df = pd.merge(sequences_df, el_seq, left_index=True, + right_index=True) + sequences_df = pd.merge(sequences_df, cool_seq, + left_index=True, right_index=True) + sequences_df.to_csv( + csv_path + 'electric_model_{0}_{1}_sequences.csv'.format( + cfg['exp_number'], var_number)) + + ######################## + # Plotting the results # # to adapt for the use case + ######################## + + cool_seq_resample = cool_seq.iloc[sp:ep] + waste_seq_resample = waste_seq.iloc[sp:ep] + el_seq_resample = el_seq.iloc[sp:ep] + ambient_seq_resample = ambient_seq.iloc[sp:ep] + + def shape_legend(node, reverse=False, **kwargs): # just copied + handels = kwargs['handles'] + labels = kwargs['labels'] + axes = kwargs['ax'] + parameter = {} + + new_labels = [] + for label in labels: + label = label.replace('(', '') + label = label.replace('), flow)', '') + label = label.replace(node, '') + label = label.replace(',', '') + label = label.replace(' ', '') + new_labels.append(label) + labels = new_labels + + parameter['bbox_to_anchor'] = kwargs.get('bbox_to_anchor', (1, 1)) + parameter['loc'] = kwargs.get('loc', 'upper left') + parameter['ncol'] = kwargs.get('ncol', 1) + plotshare = kwargs.get('plotshare', 0.9) + + if reverse: + handels = handels.reverse() + labels = labels.reverse() + + box = axes.get_position() + axes.set_position([box.x0, box.y0, box.width * plotshare, box.height]) + + parameter['handles'] = handels + parameter['labels'] = labels + axes.legend(**parameter) + return axes + + cdict = { + (('absorption_chiller', 'cool'), 'flow'): '#4682b4', + (('storage_cool', 'cool'), 'flow'): '#555555', + (('cool', 'storage_cool'), 'flow'): '#9acd32', + (('cool', 'demand'), 'flow'): '#cd0000', + (('el_grid', 'electricity'), 'flow'): '#999999', + (('pv', 'electricity'), 'flow'): '#ffde32', + (('storage_el', 'electricity'), 'flow'): '#9acd32', + (('electricity', 'storage_el'), 'flow'): '#9acd32', + (('electricity', 'cooling_tower'), 'flow'): '#ff0000', +# (('electricity', 'aquifer'), 'flow'): '#555555', + (('storage_cool', 'None'), 'capacity'): '#555555', + (('storage_cool', 'cool'), 'flow'): '#9acd32', + (('absorpion_chiller', 'waste'), 'flow'): '#4682b4', + (('waste', 'cool_tower'), 'flow'): '#42c77a'} + + # define order of inputs and outputs + inordercool = [(('absorption_chiller', 'cool'), 'flow'), + (('storage_cool', 'cool'), 'flow')] + outordercool = [(('cool', 'demand'), 'flow'), + (('cool', 'storage_cool'), 'flow')] + inorderel = [(('pv', 'electricity'), 'flow'), + (('storage_electricity', 'electricity'), 'flow'), + (('grid_el', 'electricity'), 'flow')] + outorderel = [(('electricity', 'compression_chiller'), 'flow'), + (('electricity', 'cooling_tower'), 'flow'), + (('electricity', 'storage_electricity'), 'flow'), + (('electricity', 'excess_el'), 'flow')] + # inorderstor = [(('cool', 'storage_cool'), 'flow')] + # outorderstor = [(('storage_cool', 'cool'), 'flow'), + # (('storage_cool', 'None'), 'capacity')] + + fig = plt.figure(figsize=(15, 15)) + + # plot electrical energy + my_plot_el = oev.plot.io_plot('electricity', el_seq_resample, cdict=cdict, + inorder=inorderel, outorder=outorderel, + ax=fig.add_subplot(2, 2, 1), smooth=False) + + ax_el = shape_legend('electricity', **my_plot_el) + + ax_el.set_ylabel('Power in kW') + ax_el.set_xlabel('time') + ax_el.set_title("electricity") + + plt.savefig( + plot_path + 'electric_model_{0}_{1}.png'.format( + cfg['exp_number'], var_number)) + csv_plot = pd.merge(el_seq_resample, cool_seq_resample, + left_index=True, right_index=True) + csv_plot = pd.merge(csv_plot, el_seq_resample, + left_index=True, right_index=True) + csv_plot.to_csv( + plot_path + 'electric_model_plot_{0}_{1}.csv'.format( + cfg['exp_number'], var_number)) + + return df_all_var diff --git a/solar_cooling/src/main.py b/solar_cooling/src/main.py new file mode 100644 index 0000000..cd4c46e --- /dev/null +++ b/solar_cooling/src/main.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +""" +Date: 27,05,2020 +Author: Franziska Pleissner +This App will model a cooling system for Oman. An earlier Version calculated +the results of 'Provision of cooling in Oman - a linear optimisation problem +with special consideration of different storage options' IRES 2019 +This version is adapted for oemof 0.4 and uses the solar_thermal_collector from +the oemof thermal repository. +""" + +from thermal_model import run_model_thermal +from thermal_results_processing import thermal_postprocessing +from electric_model import run_model_electric +from electric_results_processing import electric_postprocessing + +import os +import yaml + + +def main(yaml_file): + # Choose configuration file to run model with + exp_cfg_file_name = yaml_file + config_file_path = ( + os.path.abspath('../experiment_config/' + exp_cfg_file_name)) + with open(config_file_path, 'r') as ymlfile: + cfg = yaml.load(ymlfile) + +# global df_all_var + + if type(cfg['parameters_variation']) == list: + scenarios = range(len(cfg['parameters_variation'])) + elif type(cfg['parameters_system']) == list: + scenarios = range(len(cfg['parameters_system'])) + else: + scenarios = range(1) + + for scenario in scenarios: + if cfg['run_model_thermal']: + run_model_thermal( + config_path=config_file_path, + var_number=scenario) + if cfg['run_model_electric']: + run_model_electric( + config_path=config_file_path, + var_number=scenario) + if cfg['run_postprocessing_thermal']: + thermal_postprocessing( + config_path=config_file_path, + var_number=scenario) + if cfg['run_postprocessing_electric']: + electric_postprocessing( + config_path=config_file_path, + var_number=scenario) + + +main('experiment_0.yml') diff --git a/solar_cooling/src/thermal_model.py b/solar_cooling/src/thermal_model.py new file mode 100644 index 0000000..ee35aa3 --- /dev/null +++ b/solar_cooling/src/thermal_model.py @@ -0,0 +1,434 @@ +# -*- coding: utf-8 -*- +""" + +Date: 27,05,2020 + +@author: Franziska Pleissner + +System C: concrete example: Model of cooling process with absorption chiller, + using thermal solar collector + + + input/output gas thermal electr. cool waste ambient( + /ground) + +naturalgas |---------->| | | | | + | | | | | | +grid_el |-------------------------->| | | + | | | | | | +pv |-------------------------->| | | + | | | | | | +collector |------------------>| | | | + | | | | | | +boiler | |------>| | | | + | | | | | | + |<------------------| | | | +absorption_chiller |<--------------------------| | | + |---------------------------------->| | + |------------------------------------------>| + | | | | | | +cooling_tower |<------------------------------------------| + |<--------------------------| | | | + |-------------------------------------------------->| + | | | | | | +aquifer |<------------------------------------------| + |<--------------------------| | | | + |-------------------------------------------------->| + | | | | | | +storage_thermal |------------------>| | | | + |<------------------| | | | + | | | | | | +storage_electricity|-------------------------->| | | + |<--------------------------| | | + | | | | | | +storage_cool |---------------------------------->| | + |<----------------------------------| | + | | | | | | +demand |<----------------------------------| | + | | | | | | +excess |<------------------| | | | + + +""" + +############ +# Preamble # +############ + +# Import packages +from oemof.tools import logger, economics +import oemof.solph as solph +import oemof.solph.processing as processing +from oemof.thermal.solar_thermal_collector import flat_plate_precalc + +import logging +import os +import yaml +import pandas as pd +import pyomo.environ as po + +# import oemof plots +try: + import matplotlib.pyplot as plt +except ImportError: + plt = None + + +def ep_costs_func(capex, n, opex, wacc): + ep_costs = economics.annuity(capex, n, wacc) + capex * opex + return ep_costs + + +def run_model_thermal(config_path, var_number): + + with open(config_path, 'r') as ymlfile: + cfg = yaml.load(ymlfile) + + solver = cfg['solver'] + debug = cfg['debug'] + solver_verbose = cfg['solver_verbose'] # show/hide solver output + + if debug: + number_of_time_steps = 3 + else: + number_of_time_steps = cfg['number_timesteps'] + + # ## Read data and parameters ## # + # Define the used directories + abs_path = os.path.dirname(os.path.abspath(os.path.join(__file__, '..'))) + results_path = abs_path + '/results' + data_ts_path = abs_path + '/data/data_confidential/' + data_param_path = abs_path + '/data/data_public/' + + # Read parameter values from parameter file + if type(cfg['parameters_variation']) == list: + file_path_param_01 = data_param_path + cfg['parameters_system'] + file_path_param_02 = data_param_path + cfg['parameters_variation'][ + var_number] + elif type(cfg['parameters_system']) == list: + file_path_param_01 = data_param_path + cfg['parameters_system'][ + var_number] + file_path_param_02 = data_param_path + cfg['parameters_variation'] + else: + file_path_param_01 = data_param_path + cfg['parameters_system'] + file_path_param_02 = data_param_path + cfg['parameters_variation'] + param_df_01 = pd.read_csv(file_path_param_01, index_col=1) + param_df_02 = pd.read_csv(file_path_param_02, index_col=1) + param_df = pd.concat([param_df_01, param_df_02], sort=True) + param_value = param_df['value'] + + # Import weather and demand data + data = pd.read_csv(data_ts_path + cfg['time_series_file_name']) + + # Change data for collector + col_data = pd.read_csv(data_ts_path + cfg['time_series_file_name']).head( + number_of_time_steps) + col_data['date'] = pd.to_datetime(col_data['date']) + col_data.set_index('date', inplace=True) + col_data.index = col_data.index.tz_localize(tz='Asia/Muscat') + col_data = col_data.asfreq('H') + + # Calculate collector data + collector_precalc_data = flat_plate_precalc( + param_value['latitude'], + param_value['longitude'], + param_value['collector_tilt'], + param_value['collector_azimuth'], + param_value['eta_0'], + param_value['a_1'], + param_value['a_2'], + param_value['temp_collector_inlet'], + param_value['delta_temp_n'], + irradiance_global=col_data['global_irradiance_kW_per_m2_TMY'], + irradiance_diffuse=col_data['diffus_irradiance_kW_per_m2_TMY'], + temp_amb=col_data['t_amb'], + ) + + # Redefine ep_costs_function: + def ep_costs_f(capex, n, opex): + return ep_costs_func(capex, n, opex, param_value['wacc']) + + # Initiate the logger + logger.define_logging( + logfile='thermal_model_{0}_{1}.log'.format(cfg['exp_number'], + var_number), + logpath=results_path + '/logs', + screen_level=logging.INFO, + file_level=logging.DEBUG) + + date_time_index = pd.date_range('1/1/2017', + periods=number_of_time_steps, + freq='H') + + # Initialise the energysystem + logging.info('Initialize the energy system') + energysystem = solph.EnergySystem(timeindex=date_time_index) + + + ####################### + # Build up the system # + ####################### + + # Busses + + bth = solph.Bus(label='thermal') + bco = solph.Bus(label='cool') + bwh = solph.Bus(label='waste') + bel = solph.Bus(label='electricity') + bga = solph.Bus(label='gas') + bam = solph.Bus(label='ambient') + + energysystem.add(bth, bco, bwh, bel, bga, bam) + + # Sinks and Sources + + ambience = solph.Sink( + label='ambience', + inputs={bam: solph.Flow()}) + + grid_ga = solph.Source( + label='naturalgas', + outputs={bga: solph.Flow( + variable_costs=(param_value['price_gas'] + * float(param_value['price_gas_variation'])))}) + + grid_el = solph.Source( + label='grid_el', + outputs={bel: solph.Flow( + variable_costs=(param_value['price_electr'] + * float(param_value['price_electr_variation'])))}) + + collector = solph.Source( + label='collector', + outputs={bth: solph.Flow( + fix=collector_precalc_data['collectors_heat'], + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_collect_output_th'], + param_value['lifetime_collector'], + param_value['opex_collector'])))}) + + pv = solph.Source( + label='pv', + outputs={bel: solph.Flow( + fix=data['pv_normiert'], + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_pv_output_el_09708'], + param_value['lifetime_pv'], + param_value['opex_pv'])))}) # Einheit: 0.970873786 kWpeak + + demand = solph.Sink( + label='demand', + inputs={bco: solph.Flow( + fix=data['Cooling load kW'], + nominal_value=1)}) + + excess = solph.Sink( + label='excess_thermal', + inputs={bth: solph.Flow()}) + + excess_el = solph.Sink( + label='excess_el', + inputs={bel: solph.Flow()}) + + energysystem.add( + ambience, grid_ga, grid_el, collector, + pv, demand, excess, excess_el) + + # Transformers + + if param_value['nominal_value_boiler_output_thermal'] == 0: + boil = solph.Transformer( + label='boiler', + inputs={bga: solph.Flow()}, + outputs={bth: solph.Flow( + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_boiler_output_th'], + param_value['lifetime_boiler'], + param_value['opex_boiler'])))}, + conversion_factors={ + bth: param_value['conv_factor_boiler_output_thermal']}) + else: + boil = solph.Transformer( + label='boiler', + inputs={bga: solph.Flow()}, + outputs={bth: solph.Flow( + nominal_value=param_value[ + 'nominal_value_boiler_output_thermal'])}, + conversion_factors={ + bth: param_value['conv_factor_boiler_output_thermal']}) + + chil = solph.Transformer( + label='absorption_chiller', + inputs={ + bth: solph.Flow(), + bel: solph.Flow()}, + outputs={ + bco: solph.Flow( + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_absorption_output_cool'], + param_value['lifetime_absorption'], + param_value['opex_absorption']))), + bwh: solph.Flow()}, + conversion_factors={ + bco: param_value['conv_factor_absorption_output_cool'], + bwh: param_value['conv_factor_absorption_output_waste'], + bth: param_value['conv_factor_absorption_input_th'], + bel: param_value['conv_factor_absorption_input_el']}) + + towe = solph.Transformer( + label='cooling_tower', + inputs={ + bwh: solph.Flow( + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_tower_input_th'], + param_value['lifetime_tower'], + param_value['opex_tower']))), + bel: solph.Flow()}, + outputs={bam: solph.Flow()}, + conversion_factors={bwh: param_value['conv_factor_tower_input_waste'], + bel: param_value['conv_factor_tower_input_el']}) + + energysystem.add(chil, boil, towe) + + # storages + + if param_value['nominal_capacitiy_stor_cool'] == 0: + stor_co = solph.components.GenericStorage( + label='storage_cool', + inputs={bco: solph.Flow()}, + outputs={bco: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_cool'], + # invest_relation_input_capacity=1 / 6, + # invest_relation_output_capacity=1 / 6, + inflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_output'], + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_stor_cool_capacity'], + param_value['lifetime_stor_cool'], + param_value['opex_stor_cool']))) + else: + stor_co = solph.components.GenericStorage( + label='storage_cool', + inputs={bco: solph.Flow()}, + outputs={bco: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_cool'], + # invest_relation_input_capacity=1 / 6, + # invest_relation_output_capacity=1 / 6, + inflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_cool_output'], + nominal_capacity=param_value[ + 'nominal_capacitiy_stor_cool']) + + if param_value['nominal_capacitiy_stor_thermal'] == 0: + stor_th = solph.components.GenericStorage( + label='storage_thermal', + inputs={bth: solph.Flow()}, + outputs={bth: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_thermal'], + # invest_relation_input_capacity=1 / 6, + # invest_relation_output_capacity=1 / 6, + inflow_conversion_factor=param_value[ + 'conv_factor_stor_thermal_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_thermal_output'], + investment=solph.Investment( + ep_costs=ep_costs_f( + param_value['invest_costs_stor_thermal_capacity'], + param_value['lifetime_stor_thermal'], + param_value['opex_stor_thermal']))) + else: + stor_th = solph.components.GenericStorage( + label='storage_thermal', + inputs={bth: solph.Flow()}, + outputs={bth: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_thermal'], + # invest_relation_input_capacity=1 / 6, + # invest_relation_output_capacity=1 / 6, + inflow_conversion_factor=param_value[ + 'conv_factor_stor_thermal_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_thermal_output'], + nominal_capacity=param_value['nominal_capacitiy_stor_thermal']) + + if param_value['nominal_capacitiy_stor_el'] == 0: + stor_el = solph.components.GenericStorage( + label='storage_electricity', + inputs={bel: solph.Flow()}, + outputs={bel: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_el'], + # invest_relation_input_capacity=1 / 6, + # invest_relation_output_capacity=1 / 6, + inflow_conversion_factor=param_value[ + 'conv_factor_stor_el_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_el_output'], + investment=solph.Investment( + ep_costs=ep_costs_f( + (param_value['invest_costs_stor_el_capacity'] + * float(param_value['capex_stor_el_variation'])), + param_value['lifetime_stor_el'], + param_value['opex_stor_el']))) + else: + stor_el = solph.components.GenericStorage( + label='storage_electricity', + inputs={bel: solph.Flow()}, + outputs={bel: solph.Flow()}, + loss_rate=param_value['capac_loss_stor_el'], + # invest_relation_input_capacity=1 / 6, + # invest_relation_output_capacity=1 / 6, + inflow_conversion_factor=param_value[ + 'conv_factor_stor_el_input'], + outflow_conversion_factor=param_value[ + 'conv_factor_stor_el_output'], + nominal_capacity=param_value['nominal_capacitiy_stor_el']) + + energysystem.add(stor_co, stor_th, stor_el) + + ######################################## + # Create a model and solve the problem # + ######################################## + + # Initialise the operational model (create the problem) with constrains + model = solph.Model(energysystem) + + # ## Add own constrains ## # + # Create a block and add it to the system + myconstrains = po.Block() + model.add_component('MyBlock', myconstrains) + demand_sum = sum(data['Cooling load kW']) + myconstrains.solar_constr = po.Constraint( + expr=((sum(model.flow[boil, bth, t] for t in model.TIMESTEPS)) + <= (demand_sum * param_value['sol_fraction_thermal'] + * float(param_value['sol_fraction_thermal_variation'])))) + + logging.info('Solve the optimization problem') + model.solve(solver=solver, solve_kwargs={'tee': solver_verbose}) + + if debug: + filename = (results_path + '/lp_files/' + + 'thermal_model_{0}_{1}.lp'.format(cfg['exp_number'], + var_number)) + logging.info('Store lp-file in {0}.'.format(filename)) + model.write(filename, io_options={'symbolic_solver_labels': True}) + + logging.info('Store the energy system with the results.') + + energysystem.results['main'] = solph.results(model) + energysystem.results['meta'] = processing.meta_results(model) + energysystem.results['param'] = ( + processing.parameter_as_dict(model)) + + energysystem.dump( + dpath=(results_path + '/dumps'), + filename='thermal_model_{0}_{1}.oemof'.format( + cfg['exp_number'], var_number)) \ No newline at end of file diff --git a/solar_cooling/src/thermal_results_processing.py b/solar_cooling/src/thermal_results_processing.py new file mode 100644 index 0000000..a3a6a51 --- /dev/null +++ b/solar_cooling/src/thermal_results_processing.py @@ -0,0 +1,437 @@ +# -*- coding: utf-8 -*- +""" + +Date: 27,05,2020 + +@author: Franziska Pleissner + +System C: concrete example: Plot cooling process with a solar collector +""" + +############ +# Preamble # +############ + +# Import packages +import oemof.solph as solph +import oemof.solph.views as views +import oemof_visio as oev + +import logging +import os +import yaml +import pandas as pd +from thermal_model import ep_costs_func + +# import oemof plots +try: + import matplotlib.pyplot as plt +except ImportError: + plt = None + +df_all_var = pd.DataFrame() + + +def thermal_postprocessing(config_path, var_number): + global df_all_var + + with open(config_path, 'r') as ymlfile: + cfg = yaml.load(ymlfile) + + # define the used directories + abs_path = os.path.dirname(os.path.abspath(os.path.join(__file__, '..'))) + results_path = abs_path + '/results' + csv_path = results_path + '/optimisation_results/' + plot_path = results_path + '/plots/' + + energysystem = solph.EnergySystem() + energysystem.restore(dpath=(results_path + '/dumps'), + filename='thermal_model_{0}_{1}.oemof'.format( + cfg['exp_number'], var_number)) + + sp = cfg['start_of_plot'] + ep = cfg['end_of_plot'] + + # Look up investment costs. Therefor parameters must read again. + if type(cfg['parameters_variation']) == list: + file_path_param_01 = abs_path + '/data/data_public/' + cfg[ + 'parameters_system'] + file_path_param_02 = abs_path + '/data/data_public/' + cfg[ + 'parameters_variation'][var_number] + elif type(cfg['parameters_system']) == list: + file_path_param_01 = abs_path + '/data/data_public/' + cfg[ + 'parameters_system'][var_number] + file_path_param_02 = abs_path + '/data/data_public/' + cfg[ + 'parameters_variation'] + else: + file_path_param_01 = abs_path + '/data/data_public/' + cfg[ + 'parameters_system'] + file_path_param_02 = abs_path + '/data/data_public/' + cfg[ + 'parameters_variation'] + param_df_01 = pd.read_csv(file_path_param_01, index_col=1) + param_df_02 = pd.read_csv(file_path_param_02, index_col=1) + param_df = pd.concat([param_df_01, param_df_02], sort=True) + param_value = param_df['value'] + + logging.info('results received') + + ######################### + # Work with the results # + ######################### + + thermal_bus = views.node(energysystem.results['main'], 'thermal') + cool_bus = views.node(energysystem.results['main'], 'cool') + waste_bus = views.node(energysystem.results['main'], 'waste') + el_bus = views.node(energysystem.results['main'], 'electricity') + gas_bus = views.node(energysystem.results['main'], 'gas') + ambient_res = views.node(energysystem.results['main'], 'ambient') + none_res = views.node(energysystem.results['main'], 'None') + + # sequences: + thermal_seq = thermal_bus['sequences'] + cool_seq = cool_bus['sequences'] + waste_seq = waste_bus['sequences'] + el_seq = el_bus['sequences'] + gas_seq = gas_bus['sequences'] + ambient_seq = ambient_res['sequences'] + + # scalars + thermal_scal = thermal_bus['scalars'] + cool_scal = cool_bus['scalars'] + waste_scal = waste_bus['scalars'] + el_scal = el_bus['scalars'] + none_scal = none_res['scalars'] + none_scal_given = views.node( + energysystem.results['param'], 'None')['scalars'] + el_scal[(('pv', 'electricity'), 'invest')] = ( + el_scal[(('pv', 'electricity'), 'invest')]*param_value['size_pv']) + # Conversion of the pv-investment-size, because Invest-object is normalized + # at 0.970873786 kWpeak + + # solar fraction + + # thermal + # control of boiler (No heat must go from boiler to excess) + df_control_th = pd.DataFrame() + df_control_th['boiler'] = thermal_seq[(('boiler', 'thermal'), 'flow')] + df_control_th['excess'] = thermal_seq[ + (('thermal', 'excess_thermal'), 'flow')] + df_control_th['Product'] = (df_control_th['boiler'] + * df_control_th['excess']) + + heat_from_boiler = thermal_seq[(('boiler', 'thermal'), 'flow')].sum() + heat_from_collector = thermal_seq[(('collector', 'thermal'), 'flow')].sum() + heat_to_excess = thermal_seq[(('thermal', 'excess_thermal'), 'flow')].sum() + heat_collector_used = heat_from_collector - heat_to_excess + sol_fraction_th = (heat_collector_used + / (heat_collector_used + heat_from_boiler)) + + # electric: + # control_el (No Power must go from grid to excess) + df_control_el = pd.DataFrame() + df_control_el['grid_el'] = el_seq[(('grid_el', 'electricity'), 'flow')] + df_control_el['excess'] = el_seq[(('electricity', 'excess_el'), 'flow')] + df_control_el['Product'] = (df_control_el['grid_el'] + * df_control_el['excess']) + + el_from_grid = el_seq[(('grid_el', 'electricity'), 'flow')].sum() + el_from_pv = el_seq[(('pv', 'electricity'), 'flow')].sum() + el_to_excess = el_seq[(('electricity', 'excess_el'), 'flow')].sum() + el_pv_used = el_from_pv - el_to_excess + sol_fraction_el = el_pv_used / (el_pv_used + el_from_grid) + + # gas usage: + gas_used = gas_seq[(('naturalgas', 'gas'), 'flow')].sum() + + # Power to the output: + electricity_output = el_seq[(('electricity', 'excess_el'), 'flow')].sum() + electricity_output_pv = el_seq[(('pv', 'electricity'), 'flow')].sum() + + # ## Costs ## # + + costs_total = energysystem.results['meta']['objective'] + + # storage costs must be subtract for reference scenario or added + # for the other scenarios. + + # reference scenario: + if (param_value['nominal_capacitiy_stor_thermal'] == 0 and + param_value['nominal_capacitiy_stor_cool'] == 0): + costs_total_wo_stor = ( + costs_total + - (none_scal[(('storage_thermal', 'None'), 'invest')] + * none_scal_given[ + (('storage_thermal', 'None'), 'investment_ep_costs')]) + - (none_scal[(('storage_cool', 'None'), 'invest')] + * none_scal_given[ + (('storage_cool', 'None'), 'investment_ep_costs')])) + + # other scenarios: + else: + # calculation of ep_costs + ep_costs_th_stor = ep_costs_func( + param_value['invest_costs_stor_thermal_capacity'], + param_value['lifetime_stor_thermal'], + param_value['opex_stor_thermal'], + param_value['wacc']) + ep_costs_cool_stor = ep_costs_func( + param_value['invest_costs_stor_cool_capacity'], + param_value['lifetime_stor_cool'], + param_value['opex_stor_cool'], + param_value['wacc']) + # calculation of the scenario costs inclusive storage costs + costs_total_w_stor = ( + costs_total + + (none_scal_given[ + (('storage_cool', 'None'), 'nominal_capacity')] + * ep_costs_cool_stor) + + (none_scal_given[ + (('storage_thermal', 'None'), 'nominal_capacity')] + * ep_costs_th_stor)) + + ######################## + # Write results in csv # + ######################## + + # ## scalars ## # + # base scalars: + scalars_all = thermal_scal\ + .append(cool_scal)\ + .append(waste_scal)\ + .append(none_scal)\ + .append(el_scal) + for i in range(0, none_scal_given.count()): + if 'nominal_capacity' in none_scal_given.index[i]: + scalars_all = pd.concat( + [scalars_all, + pd.Series([none_scal_given[i]], + index=[none_scal_given.index[i]])]) + + # solar fractions + scalars_all = pd.concat( + [scalars_all, + pd.Series([sol_fraction_th], + index=["('solar fraction', 'thermal'), ' ')"])]) + if df_control_th['Product'].sum() != 0: + scalars_all = pd.concat( + [scalars_all, + pd.Series([df_control_th['Product'].sum()], + index=["Has to be 0!!!"])]) + + scalars_all = pd.concat( + [scalars_all, + pd.Series([sol_fraction_el], + index=["('solar fraction', 'electric'), ' ')"])]) + if df_control_el['Product'].sum() != 0: + scalars_all = pd.concat( + [scalars_all, + pd.Series([df_control_el['Product'].sum()], + index=["Has to be 0!!!"])]) + + # various results + scalars_all = pd.concat( + [scalars_all, + pd.Series([gas_used], + index=["('natural gas', 'gas'), 'summe')"])]) + scalars_all = pd.concat( + [scalars_all, + pd.Series([electricity_output], + index=["('electricity', 'output'), 'summe')"])]) + scalars_all = pd.concat( + [scalars_all, + pd.Series([electricity_output_pv], + index=["('pv', 'electricity'), 'summe')"])]) + + # costs with or without storage (depends on reference scenario or not) + if (param_value['nominal_capacitiy_stor_thermal'] != 0 or + param_value['nominal_capacitiy_stor_cool'] != 0): + scalars_all = pd.concat( + [scalars_all, + pd.Series([costs_total_w_stor], + index=["('costs', 'w_stor'), 'per year')"])]) + scalars_all = pd.concat( + [scalars_all, + pd.Series([costs_total], + index=["('costs', 'wo_stor'), 'per year')"])]) + if (param_value['nominal_capacitiy_stor_thermal'] == 0 and + param_value['nominal_capacitiy_stor_cool'] == 0): + scalars_all = pd.concat( + [scalars_all, + pd.Series([costs_total_wo_stor], + index=["('costs', 'wo stor'), 'per year')"])]) + + # experiment number and variation + scalars_all = pd.concat( + [scalars_all, + pd.Series(['{0}_{1}'.format(cfg['exp_number'], var_number)], + index=["('Exp', 'Var'), 'number')"])]) + + # write scalars into csv for this experiment and variation + scalars_all.to_csv( + csv_path + 'thermal_model_{0}_{1}_scalars.csv'.format( + cfg['exp_number'], var_number)) + + # write scalars for all variations of the experiment into csv + df_all_var = pd.concat([df_all_var, scalars_all], axis=1, sort=True) + if var_number == (cfg['number_of_variations']-1): + df_all_var.to_csv( + csv_path + + 'thermal_model_{0}_scalars_all_variations.csv'.format( + cfg['exp_number'])) + logging.info('Writing DF_all_variations into csv') + + # ## sequences ## # + sequences_df = pd.merge(ambient_seq, waste_seq, left_index=True, + right_index=True) + sequences_df = pd.merge(sequences_df, el_seq, left_index=True, + right_index=True) + sequences_df = pd.merge(sequences_df, cool_seq, left_index=True, + right_index=True) + sequences_df = pd.merge(sequences_df, thermal_seq, left_index=True, + right_index=True) + + sequences_df[('storage_thermal', 'None'), 'storage_content'] = (none_res[ + 'sequences'][(('storage_thermal', 'None'), 'storage_content')]) + sequences_df[('storage_cool', 'None'), 'storage_content'] = (none_res[ + 'sequences'][(('storage_cool', 'None'), 'storage_content')]) + + sequences_df.to_csv( + csv_path + 'thermal_model_{0}_{1}_sequences.csv'.format( + cfg['exp_number'], var_number)) + + ######################## + # Plotting the results # # to adapt for the use case + ######################## + + cool_seq_resample = cool_seq.iloc[sp:ep] + thermal_seq_resample = thermal_seq.iloc[sp:ep] + waste_seq_resample = waste_seq.iloc[sp:ep] + el_seq_resample = el_seq.iloc[sp:ep] + gas_seq_resample = gas_seq.iloc[sp:ep] + ambient_seq_resample = ambient_seq.iloc[sp:ep] + + def shape_legend(node, reverse=False, **kwargs): # just copied + handels = kwargs['handles'] + labels = kwargs['labels'] + axes = kwargs['ax'] + parameter = {} + + new_labels = [] + for label in labels: + label = label.replace('(', '') + label = label.replace('), flow)', '') + label = label.replace(node, '') + label = label.replace(',', '') + label = label.replace(' ', '') + new_labels.append(label) + labels = new_labels + + parameter['bbox_to_anchor'] = kwargs.get('bbox_to_anchor', (1, 1)) + parameter['loc'] = kwargs.get('loc', 'upper left') + parameter['ncol'] = kwargs.get('ncol', 1) + plotshare = kwargs.get('plotshare', 0.9) + + if reverse: + handels = handels.reverse() + labels = labels.reverse() + + box = axes.get_position() + axes.set_position([box.x0, box.y0, box.width * plotshare, box.height]) + + parameter['handles'] = handels + parameter['labels'] = labels + axes.legend(**parameter) + return axes + + cdict = { + (('collector', 'thermal'), 'flow'): '#ffde32', + (('boiler', 'thermal'), 'flow'): '#ff0000', + (('storage_thermal', 'thermal'), 'flow'): '#9acd32', + (('thermal', 'storage_thermal'), 'flow'): '#9acd32', + (('thermal', 'absorption_chiller'), 'flow'): '#4682b4', + (('thermal', 'excess_thermal'), 'flow'): '#4682b4', + (('absorption_chiller', 'cool'), 'flow'): '#4682b4', + (('storage_cool', 'cool'), 'flow'): '#555555', + (('cool', 'storage_cool'), 'flow'): '#9acd32', + (('cool', 'demand'), 'flow'): '#cd0000', + (('el_grid', 'electricity'), 'flow'): '#999999', + (('pv', 'electricity'), 'flow'): '#ffde32', + (('storage_el', 'electricity'), 'flow'): '#9acd32', + (('electricity', 'storage_el'), 'flow'): '#9acd32', + (('electricity', 'cooling_tower'), 'flow'): '#ff0000', + (('electricity', 'aquifer'), 'flow'): '#555555', + (('storage_cool', 'None'), 'capacity'): '#555555', + (('storage_cool', 'cool'), 'flow'): '#9acd32', + (('absorpion_chiller', 'waste'), 'flow'): '#4682b4', + (('waste', 'cool_tower'), 'flow'): '#42c77a'} + + # define order of inputs and outputs + inorderthermal = [(('collector', 'thermal'), 'flow'), + (('storage_thermal', 'thermal'), 'flow'), + (('boiler', 'thermal'), 'flow')] + outorderthermal = [(('thermal', 'absorption_chiller'), 'flow'), + (('thermal', 'storage_thermal'), 'flow'), + (('thermal', 'excess_thermal'), 'flow')] + inordercool = [(('absorption_chiller', 'cool'), 'flow'), + (('storage_cool', 'cool'), 'flow')] + outordercool = [(('cool', 'demand'), 'flow'), + (('cool', 'storage_cool'), 'flow')] + inorderel = [(('pv', 'electricity'), 'flow'), + (('storage_electricity', 'electricity'), 'flow'), + (('grid_el', 'electricity'), 'flow')] + outorderel = [(('electricity', 'cooling_tower'), 'flow'), + (('electricity', 'storage_electricity'), 'flow')] + # inorderstor = [(('cool', 'storage_cool'), 'flow')] + # outorderstor = [(('storage_cool', 'cool'), 'flow'), + # (('storage_cool', 'None'), 'capacity')] + + fig = plt.figure(figsize=(15, 15)) + + # plot thermal energy + my_plot_thermal = oev.plot.io_plot( + 'thermal', thermal_seq_resample, cdict=cdict, + inorder=inorderthermal, outorder=outorderthermal, + ax=fig.add_subplot(2, 2, 2), smooth=False) + + ax_thermal = shape_legend('thermal', **my_plot_thermal) + + ax_thermal.set_ylabel('Power in kW') + ax_thermal.set_xlabel('time') + ax_thermal.set_title("thermal") + + # plot cooling energy + my_plot_cool = oev.plot.io_plot( + 'cool', cool_seq_resample, cdict=cdict, + inorder=inordercool, outorder=outordercool, + ax=fig.add_subplot(2, 2, 1), smooth=False) + + ax_cool = shape_legend('cool', **my_plot_cool) + + ax_cool.set_ylabel('Power in kW') + ax_cool.set_xlabel('time') + ax_cool.set_title("cool") + + # plot electrical energy + my_plot_el = oev.plot.io_plot( + 'electricity', el_seq_resample, cdict=cdict, + inorder=inorderel, outorder=outorderel, + ax=fig.add_subplot(2, 2, 3), smooth=False) + + ax_el = shape_legend('electricity', **my_plot_el) + + ax_el.set_ylabel('Power in kW') + ax_el.set_xlabel('time') + ax_el.set_title("electricity") + + plt.savefig( + plot_path + 'thermal_model_{0}_{1}.png'.format( + cfg['exp_number'], var_number)) + csv_plot = pd.merge(thermal_seq_resample, cool_seq_resample, + left_index=True, right_index=True) + csv_plot = pd.merge(csv_plot, el_seq_resample, + left_index=True, right_index=True) + csv_plot.to_csv( + plot_path + 'thermal_model_plot_{0}_{1}.csv'.format( + cfg['exp_number'], var_number)) + + return df_all_var