"""Script containing functions to calculate load factors and
also peak shifting methods which are used to implement
demand management"""
import numpy as np
[docs]def peak_shaving_max_min(
loadfactor_yd_cy_improved,
average_yd,
fuel_yh,
mode_constrained
):
"""Shift demand with help of load factor. All demand above
the maximum load is shifted proportionally to all hours
having below average demand.
Arguments
----------
loadfactor_yd_cy_improved : array
Improved shifted daily load fuel
average_yd : array
Average load for every day in year
fuel_yh : array
Fuel for every hour
mode_constrained : bool
Running mode information
Returns
-------
shifted_fuel_yh : array
Shifted fuel
Info
----
Steps:
- Calculate new maximum demand for every hour and fueltype
- Calculate difference in demand to mean for every day and fueltype
- Calculate percentage of demand for every hour with lower demand than average
- Calculate total demand above average and shift to yh
- Set all hours with more demand than maximum peak to maximum peak demand
"""
# ------------------------------------------
# Calculate new maximum demand for every day
# and fueltype with help of newly adaped load factor
# ------------------------------------------
allowed_demand_max_d = average_yd / loadfactor_yd_cy_improved
allowed_demand_max_d[np.isnan(allowed_demand_max_d)] = 0
if mode_constrained:
average_yd = average_yd[:, np.newaxis]
allowed_demand_max_d = allowed_demand_max_d[:, np.newaxis]
else:
average_yd = average_yd[:, :, np.newaxis]
allowed_demand_max_d = allowed_demand_max_d[:, :, np.newaxis]
# ------------------------------------------
# Calculate difference to daily mean for every hour
# for every fueltype (hourly value - daily mean)
# ------------------------------------------
diff_to_mean = fuel_yh - average_yd
# ------------------------
# Calculate areas of lp below average for every day
# all lp higher than average are set to zero
# ------------------------
diff_to_mean[diff_to_mean > 0] = 0
diff_to_mean = np.abs(diff_to_mean)
# Sum along all fueltypes the total fuels which are lp below average
# Calculate percentage of total shiftable from above average to
# below average for all hours which can take on fuel
if mode_constrained:
tot_area_below_mean = np.sum(diff_to_mean, axis=1) #one fueltype
tot_area_below_mean = tot_area_below_mean[:, np.newaxis]
else:
tot_area_below_mean = np.sum(diff_to_mean, axis=2) #multiple fueltypes
tot_area_below_mean = tot_area_below_mean[:, :, np.newaxis]
area_below_mean_p = diff_to_mean / tot_area_below_mean
area_below_mean_p[np.isnan(area_below_mean_p)] = 0
# Calculate diff to newmax for every hour
diff_to_max_demand_d = fuel_yh - allowed_demand_max_d
diff_to_max_demand_d[diff_to_max_demand_d < 0] = 0
# -----------------------------------------
# Start with largest deviation to mean
# and shift to all hours below average
# -----------------------------------------
# Calculate total demand which is to be shifted
if mode_constrained:
tot_demand_to_shift = np.sum(diff_to_max_demand_d, axis=1) # one fueltype
tot_demand_to_shift = tot_demand_to_shift[:, np.newaxis]
else:
tot_demand_to_shift = np.sum(diff_to_max_demand_d, axis=2) # multiple fueltypes
tot_demand_to_shift = tot_demand_to_shift[:, :, np.newaxis]
# Add fuel below average:
# Distribute shiftable demand to all hours which are below average
# according to percentage contributing to lf which is below average
shifted_fuel_yh = fuel_yh + (area_below_mean_p * tot_demand_to_shift)
# Set all fuel hours whih are above max to max (substract diff)
shifted_fuel_yh = shifted_fuel_yh - diff_to_max_demand_d
#assert np.sum(shifted_fuel_yh) == np.sum(fuel_yh)
return shifted_fuel_yh
[docs]def calc_lf_y(fuel_yh):
"""Calculate the yearly load factor for every fueltype
by dividing the yearly average load by the peak hourly
load in a year.
Arguments
---------
fuel_yh : array (fueltypes, 365, 24) or (fueltypes, 8760)
Yh fuel
Returns
-------
load_factor_y : array
Yearly load factors as percentage (100% = 1)
Note
-----
Load factor = average load / peak load
https://en.wikipedia.org/wiki/Load_factor_(electrical)
https://circuitglobe.com/load-factor.html
"""
if fuel_yh.shape[1] == 365:
fuel_yh_8760 = fuel_yh.reshape(fuel_yh.shape[0], 8760)
else:
fuel_yh_8760 = fuel_yh
# Get total sum per fueltype
tot_load_y = np.sum(fuel_yh_8760, axis=1)
# Calculate maximum hour in every day of a year
max_load_h = np.max(fuel_yh_8760, axis=1)
# Caclualte yearly load factor for every fueltype
with np.errstate(divide='ignore', invalid='ignore'):
load_factor_y = (tot_load_y / 8760) / max_load_h
load_factor_y[np.isnan(load_factor_y)] = 0
return load_factor_y
[docs]def calc_lf_y_8760(fuel_yh_8760):
"""Calculate the yearly load factor for every fueltype
by dividing the yearly average load by the peak hourly
load in a year.
Arguments
---------
fuel_yh_8760 : array
Fueltypes, regions, 8760hours
Returns
-------
load_factor_y : array
Yearly load factors as percentage (100% = 1)
Note
-----
Load factor = average load / peak load
https://en.wikipedia.org/wiki/Load_factor_(electrical)
https://circuitglobe.com/load-factor.html
"""
# Get total sum per fueltype
tot_load_y = np.sum(fuel_yh_8760)
# Calculate maximum hour in every day of a year
max_load_h = np.max(fuel_yh_8760)
# Caclualte yearly load factor for every fueltype
with np.errstate(divide='ignore', invalid='ignore'):
load_factor_y = (tot_load_y / 8760) / max_load_h
if np.isnan(load_factor_y):
load_factor_y = 0
return load_factor_y
[docs]def calc_lf_season(seasons, fuel_region_yh, average_fuel_yd):
"""Calculate load factors per fueltype per region.
The load factor is calculated based on average
yearly load and maximum saisonal peak factor.
Arguments
---------
seasons : dict
Seasons containing yeardays for four seasons
fuel_region_yh : array
Fuels
average_fuel_yd : array
Average fuels
Returns
-------
seasons_lfs : dict
Load factors per fueltype and season
Note
----
If not the yearly average is used for calculation,
only the load factors within the regions are calculated.
"""
seasons_lfs = {}
for season, yeardays_modelled in seasons.items():
average_fuel_yd_full_year = np.average(
average_fuel_yd[:, ],
axis=1)
# Calculate maximum hour in year
max_load_h_days_season = np.max(
fuel_region_yh[:, yeardays_modelled],
axis=2)
max_load_h_season = np.max(max_load_h_days_season, axis=1)
# Unable local RuntimeWarning: divide by zero encountered
with np.errstate(divide='ignore', invalid='ignore'):
#convert to decimal
season_lf = (average_fuel_yd_full_year / max_load_h_season)
# Replace
season_lf[np.isinf(season_lf)] = 0
season_lf[np.isnan(season_lf)] = 0
seasons_lfs[season] = season_lf
return seasons_lfs
[docs]def calc_lf_d(fuel_yh, average_fuel_yd, mode_constrained):
"""Calculate the daily load factor for every day in a year
by dividing for each day the daily average by the daily peak
hour load. The load factor is given in %
Arguments
---------
fuel_yh : array
Fuel for every hour in a year
average_fuel_yd : array
Average load per day
mode_constrained : bool
Mode information
Returns
-------
daily_lf : array
Laod factor calculated for every modelled day [in %]
average_fuel_yd : array
Average fuel for every day
"""
# Get maximum hours in every day
if mode_constrained:
max_load_yd = np.max(fuel_yh, axis=1) #single fueltype
else:
max_load_yd = np.max(fuel_yh, axis=2) #multiple fueltypes
# Unable local RuntimeWarning: divide by zero encountered
with np.errstate(divide='ignore', invalid='ignore'):
#convert to decimal
daily_lf = (average_fuel_yd / max_load_yd)
# Replace by zero
daily_lf[np.isinf(daily_lf)] = 0
daily_lf[np.isnan(daily_lf)] = 0
return daily_lf
[docs]def calc_lf_d_8760(fuel_yh):
"""Calculate the daily load factor for every day in a year
by dividing for each day the daily average by the daily peak
hour load. The load factor is given in %
Arguments
---------
fuel_yh : array
Fuel for every hour in a year
average_fuel_yd : array
Average load per day
mode_constrained : bool
Mode information
Returns
-------
daily_lf : array
Laod factor calculated for every modelled day [in %]
average_fuel_yd : array
Average fuel for every day
"""
# Get maximum hours in every day
fuel_yh = fuel_yh.reshape(365, 24)
max_load_yd = np.max(fuel_yh, axis=1)
average_fuel_yd = np.average(fuel_yh, axis=1)
# Unable local RuntimeWarning: divide by zero encountered
with np.errstate(divide='ignore', invalid='ignore'):
#convert to decimal
daily_lf = (average_fuel_yd / max_load_yd)
# Replace by zero
daily_lf[np.isinf(daily_lf)] = 0
daily_lf[np.isnan(daily_lf)] = 0
return daily_lf
[docs]def calc_lf_season_8760(seasons, fuel_region_yh):
"""Calculate load factors per fueltype per region.
The load factor is calculated based on average
yearly load and maximum saisonal peak factor.
Arguments
---------
seasons : dict
Seasons containing yeardays for four seasons
fuel_region_yh : array
Fuels
Returns
-------
seasons_lfs : dict
Load factors per fueltype and season
Note
----
If not the yearly average is used for calculation,
only the load factors within the regions are calculated.
"""
fuel_region_yh_365_24 = fuel_region_yh.reshape(365, 24)
seasons_lfs = {}
for season, yeardays_modelled in seasons.items():
average_fuel_yd = np.average(fuel_region_yh_365_24, axis=1)
# Calculate maximum hour in year
max_load_h_days_season = np.max(
fuel_region_yh_365_24[yeardays_modelled], axis=1)
max_load_h_season = np.max(max_load_h_days_season)
# Unable local RuntimeWarning: divide by zero encountered
with np.errstate(divide='ignore', invalid='ignore'):
season_lf = (average_fuel_yd / max_load_h_season)
# Replace
season_lf[np.isinf(season_lf)] = 0
season_lf[np.isnan(season_lf)] = 0
seasons_lfs[season] = season_lf
return seasons_lfs