Source code for pyH2A.Plugins.Electrolyzer_Plugin

from pyH2A.Utilities.input_modification import hourly_to_daily_power
from pyH2A.Utilities.IO import input_resolver_function, output_inserter_function
from pyH2A.Utilities.Unit_Handler.quantity import Quantity
import numpy as np

input_dict = {
    "Electrolyzer": {
        "Nominal power": {
            "Value": {
                "type": {int,float,},
                "bounds": (0, None),
            },
            "Unit": {
                "dimension": "power",
            },
            "optional": False,
            "description": "Nominal power of electrolyzer."
        },
        "Power requirement increase per year": {
            "Value": {
                "type": {int,float,},
                "bounds": (0, None),
            },
            "Unit": {
                "dimension": "dimensionless",
            },
            "optional": False,
            "description": "Electrolyzer power requirement increase per year due to stack degradation.\
                            Percentage or value > 0. Increase calculated as: (1 + increase per year) ^ year."
        },
        "Minimum capacity": {
            "Value": {
                "type": {int,float,},
                "bounds": (0, 1),
            },
            "Unit": {
                "dimension": "dimensionless",
            },
            "optional": False,
            "description": "Minimum capacity required for electrolyzer operation. Percentage or value between 0 and 1."
        },
        "Hydrogen yield per unit energy": {
            "Value": {
                "type": {int,float,},
                "bounds": (0, None),
            },
            "Unit": {
                "dimension": "mass / energy",
            },
            "optional": False,
            "description": "Electrical conversion efficiency of electrolyzer in mass(H2)/energy(electrical)."
        },
        "Replacement time": {
            "Value": {
                "type": {int,float,},
                "bounds": (0, None),
            },
            "Unit": {
                "dimension": "time",
            },
            "optional": False,
            "description": "Operating time before stack replacement of electrolyzer is required."
        },
    },
    "Power Generation": {
        "Available energy (hourly)": {
            "Value": {
                "type": {dict,},
                "bounds": (0, None),
            },
            "Unit": {
                "dimension": "energy",
            },
            "optional": False,
            "description": "Available energy, hourly basis, dictionary of years in (energy)."
        },
    },
}

output_dict = {
    "Technical Operating Parameters and Specifications": {
        "Design output by year": {
            "Value": {
                "inserted_value": "h2_production",
                "type": {np.ndarray,},
                "dimension": "mass",
            },
            "optional": False,
            "description": "Design output by year calculated from installed \
                            electrolysis power capacity and hourly power generation data."
        },
        "Operating capacity factor": {
            "Value": {
                "inserted_value": Quantity(1., '-'),
                "type": {float,},
                "dimension": "dimensionless",
            },
            "optional": False,
            "description": "Operating capacity factor is set to 1."
        },
    },
    "Electrolyzer": {
        "Yearly operation data": {
            "Year_Value": {
                "inserted_value": "yearly_data_year",
                "type": {np.ndarray,},
                "dimension": "dimensionless", 
            },
            "Production_Value": {
                "inserted_value": "yearly_data_production",
                "type": {np.ndarray,},
                "dimension": "mass", 
            },  
            "Duration_Value": {
                "inserted_value": "yearly_data_duration",
                "type": {np.ndarray,},
                "dimension": "time", 
            },                      
            "optional": False,
            "description": "Yearly operation data of electrolyzer: year, H2 produced, duration of operation."
        },
        "H2 production (yearly)": {
            "Value": {
                "inserted_value": "h2_production",
                "type": {np.ndarray,},
                "dimension": "mass",
            },
            "optional": False,
            "description": "Yearly hydrogen production."
        },
        "Actual stack replacement time": {
            "Value": {
                "inserted_value": "replacement_frequency",
                "type": {float,},
                "dimension": "time",
            },
            "description": "Actual stack replacement time, \
                            calculated from replacement time and operation data."
        },
    },
    "Power Generation": {
        "Available energy (hourly)": {
            "Value": {
                "inserted_value": "yearly_data_unused_energy",
                "type": {dict,},
                "dimension": "energy",
            },
            "optional": False,
            "description": "Available energy (hourly) after subtracting power consumed by electrolyzer. (dictionary of years)."
        },
        "Available energy (daily)": {
            "Value": {
                "inserted_value": "yearly_data_unused_energy_daily",
                "type": {dict,},
                "dimension": "energy",
            },
            "optional": False,
            "description": "Available energy (daily) after subtracting power consumed by electrolyzer. (dictionary of years)."
        },
    },
}

[docs] class Electrolyzer_Plugin: '''Simulation of hydrogen production using electrolysis. Parameters ---------- Financial Input Values > Construction time > Value : int Construction time of hydrogen production plant in years. Electrolyzer > Nominal power > Value : float Nominal power of electrolyzer. Electrolyzer > Power requirement increase per year > Value : float Electrolyzer power requirement increase per year due to stack degradation. Dimensioless value > 0. Increase calculated as: (1 + increase per year) ^ year. Electrolyzer > Minimum capacity > Value : float Minimum capacity required for electrolyzer operation. Dimensionless value between 0 and 1. Electrolyzer > Hydrogen yield per unit energy > Value : float Electrical conversion efficiency of electrolyzer in (mass H2)/energy. Electrolyzer > Replacement time > Value : float Operating time before stack replacement of electrolyzer is required. Power Generation > Available energy (hourly) > Value : dict Available energy, hourly basis, dictionary of years. Returns ------- Technical Operating Parameters and Specifications > Design output by year > Value : nd.array Design output by year calculated from installed electrolysis power capacity and hourly power generation data. Technical Operating Parameters and Specifications > Operating capacity factor > Value : float Operating capacity factor is set to 1. Electrolyzer > Actual stack replacement time > Value : float Actual stack replacement time, calculated from replacement time and operation data. Electrolyzer > Yearly operation data > Year_Value : nd.array Yearly operation data of electrolyzer : year. Electrolyzer > Yearly operation data > Production_Value : nd.array Yearly operation data of electrolyzer : H2 produced during the year. Electrolyzer > Yearly operation data > Duration_Value : nd.array Yearly operation data of electrolyzer : duration of operation during the year. Electrolyzer > H2 production (yearly) > Value : nd.array Yearly hydrogen production. Power Generation > Available energy (hourly) > Value : dict Available energy (hourly) after subtracting power consumed by electrolyzer. (dictionary of years). Power Generation > Available energy (daily) > Value : dict Available power (daily) after subtracting power consumed by electrolyzer. ''' def __init__(self, dcf, print_info): self.input_dict_resolved = input_resolver_function(input_dict, dcf, 'Electrolyzer_Plugin') self.calculate_H2_production(dcf) self.replacement_frequency = calculate_stack_replacement(self.yearly_data_duration, self.input_dict_resolved['Electrolyzer']['Replacement time']['Value'].unit['h']) output_inserter_function(output_dict, self, dcf, 'Electrolyzer_Plugin')
[docs] def calculate_H2_production(self, dcf): '''Using hourly power generation data and electrolyzer parameters, H2 production is calculated. ''' energy_generation_yearly_data = self.input_dict_resolved['Power Generation']['Available energy (hourly)']['Value'] yearly_data_year = [] yearly_data_production = [] yearly_data_duration = [] yearly_data_unused_energy = {} yearly_data_unused_energy_daily = {} for year in dcf.operation_years: energy_generation = energy_generation_yearly_data[year].unit['J'] electrolyzer_power_demand, power_increase_ratio = calculate_electrolyzer_power_demand( self.input_dict_resolved['Electrolyzer']['Power requirement increase per year']['Value'].unit['-'], self.input_dict_resolved['Electrolyzer']['Nominal power']['Value'].unit['W'], year) # returns: power (Watt), dimensionless electrolyzer_energy_demand = 3600*electrolyzer_power_demand # integrate the power over 1 hour, since we ultimately think in terms of energy involved in each 1-hour slot electrolyzer_energy_demand *= np.ones(len(energy_generation)) electrolyzer_energy_consumption = np.amin(np.c_[energy_generation, electrolyzer_energy_demand], axis = 1) threshold = self.input_dict_resolved['Electrolyzer']['Minimum capacity']['Value'].unit['-'] electrolyzer_capacity = electrolyzer_energy_consumption / electrolyzer_energy_demand electrolyzer_capacity[electrolyzer_capacity > threshold] = 1 electrolyzer_capacity[electrolyzer_capacity <= threshold] = 0 electrolyzer_energy_consumption *= electrolyzer_capacity h2_produced = calculate_hydrogen_production( electrolyzer_energy_consumption, self.input_dict_resolved['Electrolyzer']['Hydrogen yield per unit energy']['Value'].unit['kg/J'], power_increase_ratio) # returns an array of kg of H2 produced during each hour yearly_data_year.append(year) yearly_data_production.append(np.sum(h2_produced)) yearly_data_duration.append(np.sum(electrolyzer_capacity)) # Calculation of unused energy unused_energy = energy_generation - electrolyzer_energy_consumption yearly_data_unused_energy[year] = Quantity(unused_energy, 'J') yearly_data_unused_energy_daily[year] = Quantity(hourly_to_daily_power(unused_energy), 'J') self.yearly_data_year = Quantity(np.asarray(yearly_data_year), '-') self.yearly_data_production = Quantity(np.asarray(yearly_data_production), 'kg') self.yearly_data_duration = Quantity(np.asarray(yearly_data_duration), 'h') self.h2_production = np.concatenate([ np.zeros(dcf.inp['Financial Input Values']['Construction time']['Value']), self.yearly_data_production.unit['kg'] ]) self.h2_production = Quantity(self.h2_production, 'kg') self.yearly_data_unused_energy = yearly_data_unused_energy self.yearly_data_unused_energy_daily = yearly_data_unused_energy_daily
[docs] def calculate_electrolyzer_power_demand(power_requirement_increase, nominal_power, year): '''Calculation of yearly increase in electrolyzer power demand. ''' increase = (1. + power_requirement_increase) ** year demand = increase * nominal_power return demand, increase
[docs] def calculate_hydrogen_production(energy_consumption, conversion_efficiency, power_increase_ratio): '''Calculation of hydrogen production based on power consumption, conversion efficiency and power increase. ''' h2_production = energy_consumption * conversion_efficiency / power_increase_ratio return h2_production
[docs] def calculate_stack_replacement(operation_hours, replacement_time): '''Calculation of stack replacement frequency for electrolyzer. ''' cumulative_running_time = np.cumsum(operation_hours.unit['h']) # operation_hours is a Quantity stack_usage = cumulative_running_time / replacement_time number_of_replacements = np.floor_divide(stack_usage[-1], 1) replacement_frequency = len(stack_usage) / (number_of_replacements + 1.) return Quantity(replacement_frequency, 'year') # the inputs being : (hours of operation in the year, hours of operation before replacement),
# the result corresponds to the number of years between replacements