Source code for pyH2A.Plugins.Photovoltaic_Plugin

from pyH2A.Utilities.input_modification import insert, process_table, read_textfile
import numpy as np

[docs]class Photovoltaic_Plugin: '''Simulation of hydrogen production using PV + electrolysis. Parameters ---------- Financial Input Values > construction time > Value : int Construction time of hydrogen production plant in years. Irradiation Used > Data > Value : str or ndarray Hourly power ratio data for electricity production calculation. Either a path to a text file containing the data or ndarray. A suitable array can be retrieved from "Hourly Irradiation > *type of tracking* > Value". CAPEX Multiplier > Multiplier > Value : float Multiplier to describe cost reduction of PV and electrolysis CAPEX for every ten-fold increase of power relative to CAPEX reference power. Based on the multiplier the CAPEX scaling factor is calculated as: multiplier ^ (number of ten-fold increases). A value of 1 leads to no CAPEX reduction, a value < 1 enables cost reduction. Electrolyzer > Nominal Power (kW) > Value : float Nominal power of electrolyzer in kW. Electrolyzer > CAPEX Reference Power (kW) > Value : float Reference power of electrolyzer in kW for cost reduction calculation. Electrolyzer > Power requirement increase per year > Value : float Electrolyzer power requirement increase per year due to stack degradation. Percentage or value > 0. Increase calculated as: (1 + increase per year) ^ year. Electrolyzer > Minimum capacity > Value : float Minimum capacity required for electrolyzer operation. Percentage or value between 0 and 1. Electrolyzer > Conversion efficiency (kg H2/kWh) > Value : float Electrical conversion efficiency of electrolyzer in (kg H2)/kWh. Electrolyzer > Replacement time (h) > Value : float Operating time in hours before stack replacement of electrolyzer is required. Photovoltaic > Nominal Power (kW) > Value : float Nominal power of PV array in kW. Photovoltaic > CAPEX Reference Power (kW) > Value : float Reference power of PV array for cost reduction calculations. Photovoltaic > Power loss per year > Value : float Reduction in power produced by PV array per year due to degradation. Percentage or value > 0. Reduction calculated as: (1 - loss per year) ^ year. Photovoltaic > Efficiency > Value : float Power conversion efficiency of used solar cells. Percentage or value between 0 and 1. Returns ------- Technical Operating Parameters and Specifications > Plant Design Capacity (kg of H2/day) > Value : float Plant design capacity in (kg of H2)/day calculated from installed PV + electrolysis power capacity and hourly irradiation data. Technical Operating Parameters and Specifications > Operating Capacity Factor (%) > Value : float Operating capacity factor is set to 1 (100%). Planned Replacement > Electrolyzer Stack Replacement > Frequency (years) : float Frequency of electrolyzer stack replacements in years, calculated from replacement time and hourly irradiation data. Electrolyzer > Scaling Factor > Value : float CAPEX scaling factor for electrolyzer calculated based on CAPEX multiplier, reference and nominal power. Photovoltaic > Scaling Factor > Value : float CAPEX scaling factor for PV array calculated based on CAPEX multiplier, reference and nominal power. Non-Depreciable Capital Costs > Land required (acres) > Value : float Total land required in acres. Non-Depreciable Capital Costs > Solar Collection Area (m2) > Value : float Solar collection area in m2. ''' def __init__(self, dcf, print_info): process_table(dcf.inp, 'Irradiation Used', 'Value') process_table(dcf.inp, 'CAPEX Multiplier', 'Value') process_table(dcf.inp, 'Electrolyzer', 'Value') process_table(dcf.inp, 'Photovoltaic', 'Value') self.calculate_H2_production(dcf) self.calculate_stack_replacement(dcf) self.calculate_scaling_factors(dcf) self.calculate_area(dcf) insert(dcf, 'Technical Operating Parameters and Specifications', 'Plant Design Capacity (kg of H2/day)', 'Value', self.h2_production/365., __name__, print_info = print_info) insert(dcf, 'Technical Operating Parameters and Specifications', 'Operating Capacity Factor (%)', 'Value', 1., __name__, print_info = print_info) insert(dcf, 'Planned Replacement', 'Electrolyzer Stack Replacement', 'Frequency (years)', self.replacement_frequency, __name__, print_info = print_info, add_processed = False, insert_path = False) insert(dcf, 'Electrolyzer', 'Scaling Factor', 'Value', self.electrolyzer_scaling_factor, __name__, print_info = print_info) insert(dcf, 'Photovoltaic', 'Scaling Factor', 'Value', self.pv_scaling_factor, __name__, print_info = print_info) insert(dcf, 'Non-Depreciable Capital Costs', 'Land required (acres)', 'Value', self.area_acres, __name__, print_info = print_info) insert(dcf, 'Non-Depreciable Capital Costs', 'Solar Collection Area (m2)', 'Value', self.area_m2, __name__, print_info = print_info)
[docs] def calculate_H2_production(self, dcf): '''Using hourly irradiation data and electrolyzer as well as PV array parameters, H2 production is calculated. ''' if isinstance(dcf.inp['Irradiation Used']['Data']['Value'], str): data = read_textfile(dcf.inp['Irradiation Used']['Data']['Value'], delimiter = ' ')[:,1] else: data = dcf.inp['Irradiation Used']['Data']['Value'] yearly_data = [] for year in dcf.operation_years: data_loss_corrected = self.calculate_photovoltaic_loss_correction(dcf, data, year) power_generation = data_loss_corrected * dcf.inp['Photovoltaic']['Nominal Power (kW)']['Value'] electrolyzer_power_demand, power_increase = self.calculate_electrolyzer_power_demand(dcf, year) electrolyzer_power_demand *= np.ones(len(power_generation)) electrolyzer_power_consumption = np.amin(np.c_[power_generation, electrolyzer_power_demand], axis = 1) threshold = dcf.inp['Electrolyzer']['Minimum capacity']['Value'] electrolyzer_capacity = electrolyzer_power_consumption / electrolyzer_power_demand electrolyzer_capacity[electrolyzer_capacity > threshold] = 1 electrolyzer_capacity[electrolyzer_capacity <= threshold] = 0 h2_produced = electrolyzer_power_consumption * dcf.inp['Electrolyzer']['Conversion efficiency (kg H2/kWh)']['Value'] / power_increase h2_produced *= electrolyzer_capacity yearly_data.append([year, np.sum(h2_produced), np.sum(electrolyzer_capacity)]) self.yearly_data = np.asarray(yearly_data) self.h2_production = np.concatenate([np.zeros(dcf.inp['Financial Input Values']['construction time']['Value']), self.yearly_data[:,1]])
[docs] def calculate_photovoltaic_loss_correction(self, dcf, data, year): '''Calculation of yearly reduction in electricity production by PV array. ''' return data * (1. - dcf.inp['Photovoltaic']['Power loss per year']['Value']) ** year
[docs] def calculate_electrolyzer_power_demand(self, dcf, year): '''Calculation of yearly increase in electrolyzer power demand. ''' increase = (1. + dcf.inp['Electrolyzer']['Power requirement increase per year']['Value']) ** year demand = increase * dcf.inp['Electrolyzer']['Nominal Power (kW)']['Value'] return demand, increase
[docs] def calculate_stack_replacement(self, dcf): '''Calculation of stack replacement frequency for electrolyzer. ''' cumulative_running_time = np.cumsum(self.yearly_data[:,2]) stack_usage = cumulative_running_time / dcf.inp['Electrolyzer']['Replacement time (h)']['Value'] number_of_replacements = np.floor_divide(stack_usage[-1], 1) self.replacement_frequency = len(stack_usage) / (number_of_replacements + 1.)
[docs] def calculate_scaling_factors(self, dcf): '''Calculation of electrolyzer and PV CAPEX scaling factors. ''' self.pv_scaling_factor = self.scaling_factor(dcf, dcf.inp['Photovoltaic']['Nominal Power (kW)']['Value'], dcf.inp['Photovoltaic']['CAPEX Reference Power (kW)']['Value']) self.electrolyzer_scaling_factor = self.scaling_factor(dcf, dcf.inp['Electrolyzer']['Nominal Power (kW)']['Value'], dcf.inp['Electrolyzer']['CAPEX Reference Power (kW)']['Value'])
[docs] def scaling_factor(self, dcf, power, reference): '''Calculation of CAPEX scaling factor based on nominal and reference power. ''' number_of_tenfold_increases = np.log10(power/reference) return dcf.inp['CAPEX Multiplier']['Multiplier']['Value'] ** number_of_tenfold_increases
[docs] def calculate_area(self, dcf): '''Area requirement calculation assuming 1000 W/m2 peak power.''' peak_kW_per_m2 = dcf.inp['Photovoltaic']['Efficiency']['Value'] * 1. self.area_m2 = dcf.inp['Photovoltaic']['Nominal Power (kW)']['Value'] / peak_kW_per_m2 self.area_acres = self.area_m2 * 0.000247105