def _validate_rates(initial_rate, final_rate, energy_rate_change_per_update, fit_to_limit): # all parameters have to be validated for each time slot here for time_slot in initial_rate.keys(): rate_change = None if fit_to_limit else \ find_object_of_same_weekday_and_time(energy_rate_change_per_update, time_slot) PVValidator.validate_rate( initial_selling_rate=initial_rate[time_slot], final_selling_rate=find_object_of_same_weekday_and_time( final_rate, time_slot), energy_rate_decrease_per_update=rate_change, fit_to_limit=fit_to_limit)
def _populate_profiles(self, area): for market in area.all_markets: time_slot = market.time_slot if self.fit_to_limit is False: self.energy_rate_change_per_update[time_slot] = \ find_object_of_same_weekday_and_time( self.energy_rate_change_per_update_profile_buffer, time_slot) self.initial_rate[time_slot] = \ find_object_of_same_weekday_and_time(self.initial_rate_profile_buffer, time_slot) self.final_rate[time_slot] = \ find_object_of_same_weekday_and_time(self.final_rate_profile_buffer, time_slot) self._set_or_update_energy_rate_change_per_update(market.time_slot) write_default_to_dict(self.update_counter, market.time_slot, 0)
def _fill_gaps_in_profile(input_profile: Dict = None, out_profile: Dict = None) -> Dict: """ Fills time steps, where no value is provided, with the value value of the last available time step. :param input_profile: Dict[Datetime: float, int, tuple] :param out_profile: dict with the same format as the input_profile that can be used to provide a default zero-value profile dict with the expected timestamps that need to be populated in the profile :return: continuous profile Dict[Datetime: float, int, tuple] """ if isinstance(list(input_profile.values())[0], tuple): current_val = (0, 0) else: current_val = 0 for time in out_profile.keys(): if GlobalConfig.IS_CANARY_NETWORK: temp_val = find_object_of_same_weekday_and_time( input_profile, time, ignore_not_found=True) if temp_val is not None: current_val = temp_val else: if time in input_profile: current_val = input_profile[time] out_profile[time] = current_val return out_profile
def get_market_maker_rate_from_config(next_market, default_value=None): if next_market is None: return default_value if isinstance(GlobalConfig.market_maker_rate, dict): return find_object_of_same_weekday_and_time( GlobalConfig.market_maker_rate, next_market.time_slot) else: return GlobalConfig.market_maker_rate
def test_global_market_maker_rate_set_at_instantiation(area_test1): strategy = InfiniteBusStrategy(energy_sell_rate=35) assert strategy.energy_rate == GlobalConfig.market_maker_rate strategy = InfiniteBusStrategy(energy_rate_profile={"01:15": 40}) timestamp_key = pendulum.today("utc").set(hour=1, minute=15) rate = find_object_of_same_weekday_and_time(GlobalConfig.market_maker_rate, timestamp_key) assert rate == 40
def event_market_cycle(self): power_from_profile = \ find_object_of_same_weekday_and_time(self.max_available_power_kW, self.area.next_market.time_slot) self.energy_per_slot_kWh = convert_kW_to_kWh( power_from_profile, self.area.config.slot_length) if self.energy_per_slot_kWh <= 0.0: return super().event_market_cycle()
def check_load_profile_csv(context, single_or_multi): house1 = next(filter(lambda x: x.name == "House 1", context.simulation.area.children)) load = next(filter(lambda x: x.name == "H1 DefinedLoad", house1.children)) if single_or_multi == "single": path = user_profile_load_csv.profile_path else: path = user_profile_load_csv_multiday.profile_path input_profile = read_arbitrary_profile(InputProfileTypes.POWER, path) for timepoint, energy in load.strategy.state._desired_energy_Wh.items(): assert energy == find_object_of_same_weekday_and_time(input_profile, timepoint) * 1000
def _set_or_update_energy_rate_change_per_update(self, time_slot): energy_rate_change_per_update = {} if self.fit_to_limit: energy_rate_change_per_update[time_slot] = \ (find_object_of_same_weekday_and_time( self.initial_rate_profile_buffer, time_slot) - find_object_of_same_weekday_and_time( self.final_rate_profile_buffer, time_slot)) / \ self.number_of_available_updates else: if self.rate_limit_object is min: energy_rate_change_per_update[time_slot] = \ -1 * find_object_of_same_weekday_and_time( self.energy_rate_change_per_update_profile_buffer, time_slot) elif self.rate_limit_object is max: energy_rate_change_per_update[time_slot] = \ find_object_of_same_weekday_and_time( self.energy_rate_change_per_update_profile_buffer, time_slot) self.energy_rate_change_per_update.update( energy_rate_change_per_update)
def _validate_rates(initial_selling_rate, final_selling_rate, initial_buying_rate, final_buying_rate, energy_rate_increase_per_update, energy_rate_decrease_per_update, bid_fit_to_limit, offer_fit_to_limit): for time_slot in initial_selling_rate.keys(): bid_rate_change = None if bid_fit_to_limit else \ find_object_of_same_weekday_and_time(energy_rate_increase_per_update, time_slot) offer_rate_change = None if offer_fit_to_limit else \ find_object_of_same_weekday_and_time(energy_rate_decrease_per_update, time_slot) StorageValidator.validate( initial_selling_rate=initial_selling_rate[time_slot], final_selling_rate=find_object_of_same_weekday_and_time( final_selling_rate, time_slot), initial_buying_rate=find_object_of_same_weekday_and_time( initial_buying_rate, time_slot), final_buying_rate=find_object_of_same_weekday_and_time( final_buying_rate, time_slot), energy_rate_increase_per_update=bid_rate_change, energy_rate_decrease_per_update=offer_rate_change)
def event_market_cycle(self): super().event_market_cycle() if ConstSettings.IAASettings.MARKET_TYPE == 2: for market in self.area.all_markets: try: buy_rate = find_object_of_same_weekday_and_time(self.energy_buy_rate, market.time_slot) self.post_bid(market, buy_rate * INF_ENERGY, INF_ENERGY) except MarketException: pass
def buy_energy(self, market): for offer in market.sorted_offers: if offer.seller == self.owner.name: # Don't buy our own offer continue if offer.energy_rate <= find_object_of_same_weekday_and_time(self.energy_buy_rate, market.time_slot): try: self.accept_offer(market, offer, buyer_origin=self.owner.name, buyer_origin_id=self.owner.uuid, buyer_id=self.owner.uuid) except MarketException: # Offer already gone etc., try next one. continue
def set_produced_energy_forecast_kWh_future_markets( self, reconfigure=True): self._power_profile_index = self.cloud_coverage \ if self.cloud_coverage is not None else self.area.config.cloud_coverage if reconfigure: self._read_predefined_profile_for_pv() for market in self.area.all_markets: slot_time = market.time_slot if not self.power_profile: raise D3AException( f"PV {self.owner.name} tries to set its available energy forecast without a " f"power profile.") available_energy_kWh = find_object_of_same_weekday_and_time( self.power_profile, slot_time) * self.panel_count self.state.set_available_energy(available_energy_kWh, slot_time, reconfigure)
def _update_energy_requirement_future_markets(self): """ Update required energy values for each market slot. :return: None """ for market in self.area.all_markets: slot_time = market.time_slot if not self.load_profile: raise D3AException( f"Load {self.owner.name} tries to set its energy forecasted requirement " f"without a profile.") load_energy_kWh = \ find_object_of_same_weekday_and_time(self.load_profile, slot_time) self.state.set_desired_energy(load_energy_kWh * 1000, slot_time, overwrite=False) self.state.update_total_demanded_energy(slot_time)
def offer_energy(self, market): energy_rate = find_object_of_same_weekday_and_time( self.energy_rate, market.time_slot) try: offer = market.offer( self.energy_per_slot_kWh * energy_rate, self.energy_per_slot_kWh, self.owner.name, original_offer_price=self.energy_per_slot_kWh * energy_rate, seller_origin=self.owner.name, seller_origin_id=self.owner.uuid, seller_id=self.owner.uuid) self.offers.post(offer, market.id) except MarketException: logging.error( f"Offer posted with negative energy rate {energy_rate}." f"Posting offer with zero energy rate instead.")
def __init__( self, initial_soc: float = StorageSettings.MIN_ALLOWED_SOC, min_allowed_soc=StorageSettings.MIN_ALLOWED_SOC, battery_capacity_kWh: float = StorageSettings.CAPACITY, max_abs_battery_power_kW: float = StorageSettings.MAX_ABS_POWER, cap_price_strategy: bool = False, initial_selling_rate: Union[ float, dict] = StorageSettings.SELLING_RATE_RANGE.initial, final_selling_rate: Union[ float, dict] = StorageSettings.SELLING_RATE_RANGE.final, initial_buying_rate: Union[ float, dict] = StorageSettings.BUYING_RATE_RANGE.initial, final_buying_rate: Union[ float, dict] = StorageSettings.BUYING_RATE_RANGE.final, loss_per_hour=StorageSettings.LOSS_PER_HOUR, loss_function=StorageSettings.LOSS_FUNCTION, fit_to_limit=True, energy_rate_increase_per_update=None, energy_rate_decrease_per_update=None, update_interval=None, initial_energy_origin: Enum = ESSEnergyOrigin.EXTERNAL, balancing_energy_ratio: tuple = ( BalancingSettings.OFFER_DEMAND_RATIO, BalancingSettings.OFFER_SUPPLY_RATIO)): if update_interval is None: update_interval = \ duration(minutes=ConstSettings.GeneralSettings.DEFAULT_UPDATE_INTERVAL) if min_allowed_soc is None: min_allowed_soc = StorageSettings.MIN_ALLOWED_SOC self.initial_soc = initial_soc StorageValidator.validate( initial_soc=initial_soc, min_allowed_soc=min_allowed_soc, battery_capacity_kWh=battery_capacity_kWh, max_abs_battery_power_kW=max_abs_battery_power_kW, loss_per_hour=loss_per_hour, loss_function=loss_function, fit_to_limit=fit_to_limit, energy_rate_increase_per_update=energy_rate_increase_per_update, energy_rate_decrease_per_update=energy_rate_decrease_per_update) if isinstance(update_interval, int): update_interval = duration(minutes=update_interval) BidEnabledStrategy.__init__(self) self.offer_update = \ TemplateStrategyOfferUpdater( initial_rate=initial_selling_rate, final_rate=final_selling_rate, fit_to_limit=fit_to_limit, energy_rate_change_per_update=energy_rate_decrease_per_update, update_interval=update_interval) for time_slot in self.offer_update.initial_rate_profile_buffer.keys(): StorageValidator.validate( initial_selling_rate=self.offer_update. initial_rate_profile_buffer[time_slot], final_selling_rate=find_object_of_same_weekday_and_time( self.offer_update.final_rate_profile_buffer, time_slot)) self.bid_update = \ TemplateStrategyBidUpdater( initial_rate=initial_buying_rate, final_rate=final_buying_rate, fit_to_limit=fit_to_limit, energy_rate_change_per_update=energy_rate_increase_per_update, update_interval=update_interval, rate_limit_object=min ) for time_slot in self.bid_update.initial_rate_profile_buffer.keys(): StorageValidator.validate( initial_buying_rate=self.bid_update. initial_rate_profile_buffer[time_slot], final_buying_rate=find_object_of_same_weekday_and_time( self.bid_update.final_rate_profile_buffer, time_slot)) self.state = \ StorageState(initial_soc=initial_soc, initial_energy_origin=initial_energy_origin, capacity=battery_capacity_kWh, max_abs_battery_power_kW=max_abs_battery_power_kW, loss_per_hour=loss_per_hour, loss_function=loss_function, min_allowed_soc=min_allowed_soc) self.cap_price_strategy = cap_price_strategy self.balancing_energy_ratio = BalancingRatio(*balancing_energy_ratio)