diff --git a/flexibleloadtariffs/models.py b/flexibleloadtariffs/models.py index 32beb2b977f6906f12093d0f66bdef27c68e3d96..d2072958f1425fa22e67bdf67886fad8deef0fd4 100644 --- a/flexibleloadtariffs/models.py +++ b/flexibleloadtariffs/models.py @@ -143,8 +143,8 @@ def individual_optimization(household, da_price_ts, time_step, with_bw): # EV charge is constrained to the difference of bandwidth and household load if this is positive, # and 0 otherwise def capacity_constraint(model, time, ev_i): - # TODO: here we assume that the tariff is always of the type subscription bandwidth. Make more flexible - diff = household.tariff.capacity_rule.capacity_bw - float(household.loadCurve.loc[timestamp_dict[time]]) + diff = household.tariff.get_capacity_limit(household.loadCurve, timestamp_dict[time]) - \ + float(household.loadCurve.loc[timestamp_dict[time]]) if diff > 0: return model.charge[time, ev_i] <= diff return model.charge[time, ev_i] == 0 @@ -186,20 +186,21 @@ def charge_on_arrival(household, time_step, with_bw=True): # make selection for when the EV is home and can be charged: home_time = household.loadCurve.between_time(arrival_time, departure_time) - for index, row in home_time.iteritems(): + for time_index, row in home_time.iteritems(): # clean EV load in case it has been written on previously - household.ev_load.loc[index] = 0 + household.ev_load.loc[time_index] = 0 # reset required charge every day at arrival time - if datetime.time(index) == arrival_time: + if datetime.time(time_index) == arrival_time: remaining_charge += hh_ev.daily_demand # charge at maximum possible (at bandwidth) until remaining charge is below 0 if remaining_charge > 0: if with_bw: - # remaining charge is reduced by what's possible to charge within bandwidth - ev_load_this_period = household.tariff.capacity_rule.capacity_bw - float(household.loadCurve.loc[index]) + # remaining charge is reduced by what's possible to charge within capacity limit + ev_load_this_period = household.tariff.get_capacity_limit(household.loadCurve, time_index) - \ + float(household.loadCurve.loc[time_index]) else: # remaining charge is reduced based on maximal charge power ev_load_this_period = float(household.ev.max_charge) - household.ev_load.loc[index] = ev_load_this_period + household.ev_load.loc[time_index] = ev_load_this_period remaining_charge -= ev_load_this_period * time_step/60 * hh_ev.charging_efficiency return household diff --git a/flexibleloadtariffs/tariffs.py b/flexibleloadtariffs/tariffs.py index 13a57356a6f16b4bc7a1be07f7b11e002d81c7f1..1ecfd9850da140bf55ae069e371f8e8166cd0bf9 100644 --- a/flexibleloadtariffs/tariffs.py +++ b/flexibleloadtariffs/tariffs.py @@ -110,15 +110,17 @@ class TariffRuleCapacity(TariffRule): class TariffRulePersonalPeak(TariffRule): - def __init__(self, peak_charge: float, n_peaks_month=1, peak_length=15, peak_percent_month=0.0): + def __init__(self, peak_charge: float, min_peak: float, n_peaks_month=1, peak_length=15, peak_percent_month=0.0): """ :param peak_charge: charge in Euro per kW of peak + :param min_peak: minimal peak in kW to be applied, even if the household's load is always below this :param n_peaks_month: number of peaks considered per month :param peak_length: length of considered peaks in minutes, should be multiple of 5 minutes and at most one hour :param peak_percent_month: percentage of highest peaks in a month, is an alternative specification to n_peaks """ self.peak_charge = peak_charge + self.min_peak = min_peak self.n_peaks_month = n_peaks_month self.peak_length = peak_length self.peak_percent_month = peak_percent_month @@ -160,6 +162,16 @@ class Tariff: return total_tariff_charge + def get_capacity_limit(self, hh_loadcurve: Optional[pd.Series] = None, date: Optional[pd.datetime] = None): + if self.capacity_rule is not None: + return self.capacity_rule.capacity_bw + elif self.personal_peak_rule is not None: + # in a peak tariff, we assume the maximal capacity to be given by the household's peak in the given month + # (or alternatively the minimal peak) + return max(hh_loadcurve[hh_loadcurve.index.month == date.month].max(), self.personal_peak_rule.min_peak) + else: + return float('inf') + # volumetric tariffs def power_to_volume(load_power, timestep): @@ -227,7 +239,7 @@ bw_tariff_8kW = Tariff( ) personal_peak_tariff = Tariff( - personal_peak_rule=TariffRulePersonalPeak(peak_charge=50.0, n_peaks_month=1), + personal_peak_rule=TariffRulePersonalPeak(peak_charge=50.0, min_peak=1, n_peaks_month=1), name='50 euro per kW, single personal peak' )