Source code for onsset.runner

# Defines the modules

import logging
import os

import pandas as pd
from onsset import (SET_ELEC_ORDER, SET_LCOE_GRID, SET_MIN_GRID_DIST, SET_GRID_PENALTY,
                    SET_MV_CONNECT_DIST, SET_WINDVEL, SET_WINDCF, SettlementProcessor, Technology)

try:
    from onsset.specs import (SPE_COUNTRY, SPE_ELEC, SPE_ELEC_MODELLED,
                              SPE_ELEC_RURAL, SPE_ELEC_URBAN, SPE_END_YEAR,
                              SPE_GRID_CAPACITY_INVESTMENT, SPE_GRID_LOSSES,
                              SPE_MAX_GRID_EXTENSION_DIST,
                              SPE_NUM_PEOPLE_PER_HH_RURAL,
                              SPE_NUM_PEOPLE_PER_HH_URBAN, SPE_POP, SPE_POP_FUTURE,
                              SPE_START_YEAR, SPE_URBAN, SPE_URBAN_FUTURE,
                              SPE_URBAN_MODELLED)
except ImportError:
    from specs import (SPE_COUNTRY, SPE_ELEC, SPE_ELEC_MODELLED,
                       SPE_ELEC_RURAL, SPE_ELEC_URBAN, SPE_END_YEAR,
                       SPE_GRID_CAPACITY_INVESTMENT, SPE_GRID_LOSSES,
                       SPE_MAX_GRID_EXTENSION_DIST,
                       SPE_NUM_PEOPLE_PER_HH_RURAL,
                       SPE_NUM_PEOPLE_PER_HH_URBAN, SPE_POP, SPE_POP_FUTURE,
                       SPE_START_YEAR, SPE_URBAN, SPE_URBAN_FUTURE,
                       SPE_URBAN_MODELLED)
from openpyxl import load_workbook

logging.basicConfig(format='%(asctime)s\t\t%(message)s', level=logging.DEBUG)


[docs]def calibration(specs_path, csv_path, specs_path_calib, calibrated_csv_path): """ Arguments --------- specs_path csv_path specs_path_calib calibrated_csv_path """ specs_data = pd.read_excel(specs_path, sheet_name='SpecsData') settlements_in_csv = csv_path settlements_out_csv = calibrated_csv_path onsseter = SettlementProcessor(settlements_in_csv) num_people_per_hh_rural = float(specs_data.iloc[0][SPE_NUM_PEOPLE_PER_HH_RURAL]) num_people_per_hh_urban = float(specs_data.iloc[0][SPE_NUM_PEOPLE_PER_HH_URBAN]) # RUN_PARAM: these are the annual household electricity targets tier_1 = 38.7 # 38.7 refers to kWh/household/year. It is the mean value between Tier 1 and Tier 2 tier_2 = 219 tier_3 = 803 tier_4 = 2117 tier_5 = 2993 onsseter.prepare_wtf_tier_columns(num_people_per_hh_rural, num_people_per_hh_urban, tier_1, tier_2, tier_3, tier_4, tier_5) onsseter.condition_df() onsseter.df[SET_GRID_PENALTY] = onsseter.grid_penalties(onsseter.df) onsseter.df[SET_WINDCF] = onsseter.calc_wind_cfs(onsseter.df[SET_WINDVEL]) pop_actual = specs_data.loc[0, SPE_POP] urban_current = specs_data.loc[0, SPE_URBAN] start_year = int(specs_data.loc[0, SPE_START_YEAR]) elec_actual = specs_data.loc[0, SPE_ELEC] elec_actual_urban = specs_data.loc[0, SPE_ELEC_URBAN] elec_actual_rural = specs_data.loc[0, SPE_ELEC_RURAL] pop_modelled, urban_modelled = onsseter.calibrate_current_pop_and_urban(pop_actual, urban_current) specs_data.loc[0, SPE_URBAN_MODELLED] = urban_modelled elec_calibration_results = onsseter.calibrate_elec_current(elec_actual, elec_actual_urban, elec_actual_rural, start_year, buffer=True) specs_data.loc[0, SPE_ELEC_MODELLED] = elec_calibration_results[0] specs_data.loc[0, 'rural_elec_ratio_modelled'] = elec_calibration_results[1] specs_data.loc[0, 'urban_elec_ratio_modelled'] = elec_calibration_results[2] specs_data['grid_data_used'] = elec_calibration_results[3] specs_data['grid_distance_used'] = elec_calibration_results[4] specs_data['ntl_limit'] = elec_calibration_results[5] specs_data['pop_limit'] = elec_calibration_results[6] specs_data['Buffer_used'] = elec_calibration_results[7] specs_data['buffer_distance'] = elec_calibration_results[8] book = load_workbook(specs_path) writer = pd.ExcelWriter(specs_path_calib, engine='openpyxl') writer.book = book # RUN_PARAM: Here the calibrated "specs" data are copied to a new tab called "SpecsDataCalib". # This is what will later on be used to feed the model specs_data.to_excel(writer, sheet_name='SpecsDataCalib', index=False) writer.save() writer.close() logging.info('Calibration finished. Results are transferred to the csv file') onsseter.df.to_csv(settlements_out_csv, index=False)
[docs]def scenario(specs_path, calibrated_csv_path, results_folder, summary_folder): """ Arguments --------- specs_path : str calibrated_csv_path : str results_folder : str summary_folder : str """ scenario_info = pd.read_excel(specs_path, sheet_name='ScenarioInfo') scenarios = scenario_info['Scenario'] scenario_parameters = pd.read_excel(specs_path, sheet_name='ScenarioParameters') specs_data = pd.read_excel(specs_path, sheet_name='SpecsDataCalib') print(specs_data.loc[0, SPE_COUNTRY]) for scenario in scenarios: print('Scenario: ' + str(scenario + 1)) country_id = specs_data.iloc[0]['CountryCode'] pop_future = specs_data.loc[0, SPE_POP_FUTURE] urban_future = specs_data.loc[0, SPE_URBAN_FUTURE] pop_index = scenario_info.iloc[scenario]['Population_Growth'] tier_index = scenario_info.iloc[scenario]['Target_electricity_consumption_level'] five_year_index = scenario_info.iloc[scenario]['Electrification_target_5_years'] grid_index = scenario_info.iloc[scenario]['Grid_electricity_generation_cost'] pv_index = scenario_info.iloc[scenario]['PV_cost_adjust'] diesel_index = scenario_info.iloc[scenario]['Diesel_price'] productive_index = scenario_info.iloc[scenario]['Productive_uses_demand'] prio_index = scenario_info.iloc[scenario]['Prioritization_algorithm'] end_year_pop = scenario_parameters.iloc[pop_index]['PopEndYear'] rural_tier = scenario_parameters.iloc[tier_index]['RuralTargetTier'] urban_tier = scenario_parameters.iloc[tier_index]['UrbanTargetTier'] five_year_target = scenario_parameters.iloc[five_year_index]['5YearTarget'] annual_new_grid_connections_limit = scenario_parameters.iloc[five_year_index][ 'GridConnectionsLimitThousands'] * 1000 grid_price = scenario_parameters.iloc[grid_index]['GridGenerationCost'] pv_capital_cost_adjust = scenario_parameters.iloc[pv_index]['PV_Cost_adjust'] diesel_price = scenario_parameters.iloc[diesel_index]['DieselPrice'] productive_demand = scenario_parameters.iloc[productive_index]['ProductiveDemand'] prioritization = scenario_parameters.iloc[prio_index]['PrioritizationAlgorithm'] auto_intensification = scenario_parameters.iloc[prio_index]['AutoIntensificationKM'] settlements_in_csv = calibrated_csv_path settlements_out_csv = os.path.join(results_folder, '{}-1-{}_{}_{}_{}_{}_{}.csv'.format(country_id, pop_index, tier_index, five_year_index, grid_index, pv_index, prio_index)) summary_csv = os.path.join(summary_folder, '{}-1-{}_{}_{}_{}_{}_{}_summary.csv'.format(country_id, pop_index, tier_index, five_year_index, grid_index, pv_index, prio_index)) onsseter = SettlementProcessor(settlements_in_csv) start_year = specs_data.iloc[0][SPE_START_YEAR] end_year = specs_data.iloc[0][SPE_END_YEAR] num_people_per_hh_rural = float(specs_data.iloc[0][SPE_NUM_PEOPLE_PER_HH_RURAL]) num_people_per_hh_urban = float(specs_data.iloc[0][SPE_NUM_PEOPLE_PER_HH_URBAN]) max_grid_extension_dist = float(specs_data.iloc[0][SPE_MAX_GRID_EXTENSION_DIST]) annual_grid_cap_gen_limit = specs_data.loc[0, 'NewGridGenerationCapacityAnnualLimitMW'] * 1000 # RUN_PARAM: Fill in general and technology specific parameters (e.g. discount rate, losses etc.) Technology.set_default_values(base_year=start_year, start_year=start_year, end_year=end_year, discount_rate=0.08) grid_calc = Technology(om_of_td_lines=0.02, distribution_losses=float(specs_data.iloc[0][SPE_GRID_LOSSES]), connection_cost_per_hh=125, base_to_peak_load_ratio=0.8, capacity_factor=1, tech_life=30, grid_capacity_investment=float(specs_data.iloc[0][SPE_GRID_CAPACITY_INVESTMENT]), grid_penalty_ratio=1, grid_price=grid_price) mg_hydro_calc = Technology(om_of_td_lines=0.02, distribution_losses=0.05, connection_cost_per_hh=100, base_to_peak_load_ratio=0.85, capacity_factor=0.5, tech_life=30, capital_cost={float("inf"): 3000}, om_costs=0.03, mini_grid=True) mg_wind_calc = Technology(om_of_td_lines=0.02, distribution_losses=0.05, connection_cost_per_hh=100, base_to_peak_load_ratio=0.85, capital_cost={float("inf"): 3750}, om_costs=0.02, tech_life=20, mini_grid=True) mg_pv_calc = Technology(om_of_td_lines=0.02, distribution_losses=0.05, connection_cost_per_hh=100, base_to_peak_load_ratio=0.85, tech_life=20, om_costs=0.015, capital_cost={float("inf"): 2950 * pv_capital_cost_adjust}, mini_grid=True) sa_pv_calc = Technology(base_to_peak_load_ratio=0.9, tech_life=15, om_costs=0.02, capital_cost={float("inf"): 6950 * pv_capital_cost_adjust, 1: 4470 * pv_capital_cost_adjust, 0.100: 6380 * pv_capital_cost_adjust, 0.050: 8780 * pv_capital_cost_adjust, 0.020: 9620 * pv_capital_cost_adjust }, standalone=True) mg_diesel_calc = Technology(om_of_td_lines=0.02, distribution_losses=0.05, connection_cost_per_hh=100, base_to_peak_load_ratio=0.85, capacity_factor=0.7, tech_life=15, om_costs=0.1, capital_cost={float("inf"): 721}, mini_grid=True) sa_diesel_calc = Technology(base_to_peak_load_ratio=0.9, capacity_factor=0.5, tech_life=10, om_costs=0.1, capital_cost={float("inf"): 938}, standalone=True) sa_diesel_cost = {'diesel_price': diesel_price, 'efficiency': 0.28, 'diesel_truck_consumption': 14, 'diesel_truck_volume': 300} mg_diesel_cost = {'diesel_price': diesel_price, 'efficiency': 0.33, 'diesel_truck_consumption': 33.7, 'diesel_truck_volume': 15000} # RUN_PARAM: One shall define here the years of analysis (excluding start year), # together with access targets per interval and timestep duration yearsofanalysis = [2025, 2030] eleclimits = {2025: five_year_target, 2030: 1} time_steps = {2025: 7, 2030: 5} elements = ["1.Population", "2.New_Connections", "3.Capacity", "4.Investment"] techs = ["Grid", "SA_Diesel", "SA_PV", "MG_Diesel", "MG_PV", "MG_Wind", "MG_Hydro"] tech_codes = [1, 2, 3, 4, 5, 6, 7] sumtechs = [] for element in elements: for tech in techs: sumtechs.append(element + "_" + tech) total_rows = len(sumtechs) df_summary = pd.DataFrame(columns=yearsofanalysis) for row in range(0, total_rows): df_summary.loc[sumtechs[row]] = "Nan" onsseter.current_mv_line_dist() onsseter.project_pop_and_urban(pop_future, urban_future, start_year, yearsofanalysis) for year in yearsofanalysis: eleclimit = eleclimits[year] time_step = time_steps[year] if year - time_step == start_year: grid_cap_gen_limit = time_step * annual_grid_cap_gen_limit grid_connect_limit = time_step * annual_new_grid_connections_limit else: grid_cap_gen_limit = 9999999999 grid_connect_limit = 9999999999 onsseter.set_scenario_variables(year, num_people_per_hh_rural, num_people_per_hh_urban, time_step, start_year, urban_tier, rural_tier, end_year_pop, productive_demand) onsseter.diesel_cost_columns(sa_diesel_cost, mg_diesel_cost, year) sa_diesel_investment, sa_diesel_capacity, sa_pv_investment, sa_pv_capacity, mg_diesel_investment, \ mg_diesel_capacity, mg_pv_investment, mg_pv_capacity, mg_wind_investment, mg_wind_capacity, \ mg_hydro_investment, mg_hydro_capacity = onsseter.calculate_off_grid_lcoes(mg_hydro_calc, mg_wind_calc, mg_pv_calc, sa_pv_calc, mg_diesel_calc, sa_diesel_calc, year, end_year, time_step, techs, tech_codes) grid_investment, grid_capacity, grid_cap_gen_limit, grid_connect_limit = \ onsseter.pre_electrification(grid_price, year, time_step, end_year, grid_calc, grid_cap_gen_limit, grid_connect_limit) onsseter.df[SET_LCOE_GRID + "{}".format(year)], onsseter.df[SET_MIN_GRID_DIST + "{}".format(year)], \ onsseter.df[SET_ELEC_ORDER + "{}".format(year)], onsseter.df[SET_MV_CONNECT_DIST], grid_investment,\ grid_capacity = \ onsseter.elec_extension(grid_calc, max_grid_extension_dist, year, start_year, end_year, time_step, grid_cap_gen_limit, grid_connect_limit, auto_intensification=auto_intensification, prioritization=prioritization, new_investment=grid_investment, new_capacity=grid_capacity) onsseter.results_columns(techs, tech_codes, year, time_step, prioritization, auto_intensification) onsseter.calculate_investments_and_capacity(sa_diesel_investment, sa_diesel_capacity, sa_pv_investment, sa_pv_capacity, mg_diesel_investment, mg_diesel_capacity, mg_pv_investment, mg_pv_capacity, mg_wind_investment, mg_wind_capacity, mg_hydro_investment, mg_hydro_capacity, grid_investment, grid_capacity, year) onsseter.apply_limitations(eleclimit, year, time_step, prioritization, auto_intensification) onsseter.calc_summaries(df_summary, sumtechs, tech_codes, year) for i in range(len(onsseter.df.columns)): if onsseter.df.iloc[:, i].dtype == 'float64': onsseter.df.iloc[:, i] = pd.to_numeric(onsseter.df.iloc[:, i], downcast='float') elif onsseter.df.iloc[:, i].dtype == 'int64': onsseter.df.iloc[:, i] = pd.to_numeric(onsseter.df.iloc[:, i], downcast='signed') df_summary.to_csv(summary_csv, index=sumtechs) onsseter.df.to_csv(settlements_out_csv, index=False) logging.info('Finished')