コード例 #1
0
    def schedule_run(self,
                     cur_exp_time,
                     cur_analysis_time,
                     start_of_cycle=False):
        """
        Run when first start or run at beginning of hour
        :return:
        """
        # Balance
        market = self.markets[0]  # Assume only 1 TNS market per node
        market.balance(self)
        prices = market.marginalPrices
        prices = prices[-25:]
        prices = [x.value for x in prices]
        _time = format_timestamp(Timer.get_cur_time())
        self.vip.pubsub.publish(peer='pubsub',
                                topic=self.price_topic,
                                message={
                                    'prices': prices,
                                    'current_time': _time
                                })
        self.campus.model.prep_transactive_signal(market, self)
        self.campus.model.send_transactive_signal(
            self, self.city_supply_topic, start_of_cycle=start_of_cycle)

        # Schedule to run next hour with start_of_cycle = True
        cur_exp_time = parser.parse(cur_exp_time)
        cur_analysis_time = parser.parse(cur_analysis_time)
        next_exp_time, next_analysis_time = self.get_next_exp_time(
            cur_exp_time, cur_analysis_time)
        self.core.schedule(next_exp_time,
                           self.schedule_run,
                           format_timestamp(next_exp_time),
                           format_timestamp(next_analysis_time),
                           start_of_cycle=True)
コード例 #2
0
    def new_demand_signal(self, peer, sender, bus, topic, headers, message):
        _log.debug("At {}, {} receives new demand records: {}".format(
            Timer.get_cur_time(), self.name, message))
        demand_curves = message['curves']

        # Should not do anything with start_of_cycle signal
        self.campus.model.receive_transactive_signal(
            self, demand_curves)  # atm, only one campus

        self.balance_market(1)
コード例 #3
0
    def new_supply_signal(self, peer, sender, bus, topic, headers, message):
        _log.debug("At {}, {} receives new supply records: {}".format(
            Timer.get_cur_time(), self.name, message))
        source = message['source']
        supply_curves = message['curves']
        start_of_cycle = message['start_of_cycle']
        fail_to_converged = message['fail_to_converged']

        self.city.model.receive_transactive_signal(self, supply_curves)

        if start_of_cycle:
            self.balance_market(1, start_of_cycle, fail_to_converged)
コード例 #4
0
 def new_demand_signal(self, peer, sender, bus, topic, headers, message):
     mtrs = self.campus.model.meterPoints
     if len(mtrs) > 0:
         bldg_meter = mtrs[0]
         power_unit = message[1]
         cur_power = float(message[0]["WholeBuildingPower"])
         power_unit = power_unit.get("WholeBuildingPower",
                                     {}).get("units", "kW")
         if isinstance(power_unit, str) and power_unit.lower() == "watts":
             cur_power = cur_power / 1000.0
         bldg_meter.set_meter_value(cur_power)
         if Timer.get_cur_time().minute >= 58:
             bldg_meter.update_avg()
コード例 #5
0
 def aggregate_callback(self, timestamp, market_name, buyer_seller,
                        aggregate_demand):
     if buyer_seller == BUYER and market_name in self.market_names:  # self.base_market_name in market_name:
         _log.debug("{}: at ts {} min of aggregate curve : {}".format(
             self.agent_name, timestamp, aggregate_demand.points[0]))
         _log.debug("{}: at ts {} max of aggregate curve : {}".format(
             self.agent_name, timestamp, aggregate_demand.points[-1]))
         _log.debug(
             "At {}: Report aggregate Market: {} buyer Curve: {}".format(
                 Timer.get_cur_time(), market_name, aggregate_demand))
         idx = int(market_name.split('_')[-1])
         idx += 1  # quantity has 25 values while there are 24 future markets
         self.building_demand_curves[idx] = (aggregate_demand.points[0],
                                             aggregate_demand.points[-1])
コード例 #6
0
    def new_supply_signal(self, peer, sender, bus, topic, headers, message):
        _log.debug("At {}, {} receives new supply records: {}".format(
            Timer.get_cur_time(), self.name, message))
        supply_curves = message['curves']
        start_of_cycle = message['start_of_cycle']

        self.campus.model.receive_transactive_signal(self, supply_curves)
        _log.debug("At {}, mixmarket state is {}, start_of_cycle {}".format(
            Timer.get_cur_time(), self.mix_market_running, start_of_cycle))

        db_topic = "/".join([self.db_topic, self.name, "CampusSupply"])
        message = supply_curves
        headers = {headers_mod.DATE: format_timestamp(Timer.get_cur_time())}
        self.vip.pubsub.publish("pubsub", db_topic, headers, message).get()

        if start_of_cycle:
            _log.debug("At {}, start of cycle. "
                       "Mixmarket state before overriding is {}".format(
                           Timer.get_cur_time(), self.mix_market_running))

            # if self.simulation:
            #     self.run_ep_sim(start_of_cycle)
            # else:
            self.start_mixmarket(start_of_cycle)
コード例 #7
0
    def balance_market(self, run_cnt):
        market = self.markets[0]  # Assume only 1 TNS market per node
        market.signal_new_data = True
        market.balance(self)

        if market.converged:
            # Sum all the powers as will be needed by the net supply/demand curve.
            market.assign_system_vertices(self)

            # Check to see if it is ok to send signals
            self.campus.model.check_for_convergence(market)
            if not self.campus.model.converged:
                _log.debug("NeighborModel {} sends records to campus.".format(
                    self.campus.model.name))
                self.campus.model.prep_transactive_signal(market, self)
                self.campus.model.send_transactive_signal(
                    self, self.city_supply_topic, start_of_cycle=False)
            else:
                # Schedule rerun balancing only if not in simulation mode
                if not self.simulation:
                    dt = datetime.now()
                    _log.debug(
                        "{} ({}) did not send records due to check_for_convergence()"
                        .format(self.name, dt))
                    # Schedule to rerun after 5 minutes if it is in the same hour and is the first reschedule
                    next_run_dt = dt + self.reschedule_interval
                    if dt.hour == next_run_dt.hour and run_cnt >= 1:
                        _log.debug("{} reschedule to run at {}".format(
                            self.name, next_run_dt))
                        self.core.schedule(next_run_dt, self.balance_market,
                                           run_cnt + 1)
            prices = market.marginalPrices

            # There is a case where the balancing happens at the end of the hour and continues to the next hour, which
            # creates 26 values. Get the last 25 values.
            prices = prices[-25:]
            prices = [x.value for x in prices]
            self.vip.pubsub.publish(peer='pubsub',
                                    topic=self.price_topic,
                                    message={
                                        'prices':
                                        prices,
                                        'current_time':
                                        format_timestamp(Timer.get_cur_time())
                                    })
        else:
            _log.debug("Market balancing sub-problem failed.")
コード例 #8
0
    def new_demand_signal(self, peer, sender, bus, topic, headers, message):
        _log.debug("At {}, {} receives new demand records: {}".format(
            Timer.get_cur_time(), self.name, message))
        building_name = message['source']
        demand_curves = message['curves']
        start_of_cycle = message['start_of_cycle']
        fail_to_converged = message['fail_to_converged']

        neighbors = [n for n in self.neighbors if n.name == building_name]
        if len(neighbors) == 1:
            neighbor = neighbors[0]
            neighbor.model.receive_transactive_signal(self, demand_curves)
            self.balance_market(1, start_of_cycle, fail_to_converged, neighbor)
        else:
            _log.error("{}: There are {} building(s) with name {}.".format(
                self.name, len(neighbors), building_name))
            _log.error("Neighbors are: {}".format(
                [x.name for x in self.neighbors]))
            _log.error("Message is: {}".format(message))
            _log.error(
                "Check value of 'name' key in the config file for building {}."
                .format(building_name))
コード例 #9
0
    def init_objects(self):
        # Add meter
        meter = MeterPoint()
        meter.measurementType = MeasurementType.PowerReal
        meter.name = 'CoRElectricMeter'
        meter.measurementUnit = MeasurementUnit.kWh
        self.meterPoints.append(meter)

        # Add weather forecast service
        weather_service = TemperatureForecastModel(self.config_path, self)
        self.informationServiceModels.append(weather_service)

        # Add inelastive asset
        # Source: https://www.ci.richland.wa.us/home/showdocument?id=1890
        #   Residential customers: 23,768
        #   Electricity sales in 2015:
        # Total:     100.0#   879,700,000 kWh     100,400 avg. kW)
        # Resident:   46.7    327,200,000          37,360
        # Gen. Serv.: 38.1    392,300,000          44,790
        # Industrial: 15.2    133,700,000          15,260
        # Irrigation:  2.4     21,110,000           2,410
        # Other:       0.6      5,278,000             603
        #   2015 Res. rate: $0.0616/kWh
        #   Avg. annual residential cust. use: 14,054 kWh
        #   Winter peak, 160,100 kW (1.6 x average)
        #   Summer peak, 180,400 kW (1.8 x average)
        #   Annual power supply expenses: $35.5M
        # *************************************************************************
        inelastive_load = LocalAsset()
        inelastive_load.name = 'InelasticLoad'
        inelastive_load.maximumPower = -50000  # Remember that a load is a negative power [kW]
        inelastive_load.minimumPower = -200000  # Assume twice the averag PNNL load [kW]

        # Add inelastive asset model
        inelastive_load_model = OpenLoopRichlandLoadPredictor(weather_service)
        inelastive_load_model.name = 'InelasticLoadModel'
        inelastive_load_model.defaultPower = -100420  # [kW]
        inelastive_load_model.defaultVertices = [
            Vertex(float("inf"), 0.0, -100420.0)
        ]

        # Cross-reference asset & asset model
        inelastive_load_model.object = inelastive_load
        inelastive_load.model = inelastive_load_model

        # Add inelastic as city's asset
        self.localAssets.extend([inelastive_load])

        # Add Market
        market = Market()
        market.name = 'dayAhead'
        market.commitment = False
        market.converged = False
        market.defaultPrice = 0.0428  # [$/kWh]
        market.dualityGapThreshold = self.duality_gap_threshold  # [0.02 = 2#]
        market.initialMarketState = MarketState.Inactive
        market.marketOrder = 1  # This is first and only market
        market.intervalsToClear = 1  # Only one interval at a time
        market.futureHorizon = timedelta(
            hours=24)  # Projects 24 hourly future intervals
        market.intervalDuration = timedelta(
            hours=1)  # [h] Intervals are 1 h long
        market.marketClearingInterval = timedelta(hours=1)  # [h]
        market.marketClearingTime = Timer.get_cur_time().replace(
            hour=0, minute=0, second=0,
            microsecond=0)  # Aligns with top of hour
        market.nextMarketClearingTime = market.marketClearingTime + timedelta(
            hours=1)
        self.markets.append(market)

        self.campus = self.make_campus()
        supplier = self.make_supplier()

        # Add campus as city's neighbor
        self.neighbors.extend([self.campus, supplier])
コード例 #10
0
    def init_objects(self):
        # Add meter
        meter = MeterPoint()
        meter.measurementType = MeasurementType.PowerReal
        meter.name = 'CampusElectricityMeter'
        meter.measurementUnit = MeasurementUnit.kWh
        self.meterPoints.append(meter)

        # Add weather forecast service
        weather_service = TemperatureForecastModel(self.config_path, self)
        self.informationServiceModels.append(weather_service)

        # Add inelastive asset
        inelastive_load = LocalAsset()
        inelastive_load.name = 'InelasticBuildings'  # Campus buildings that are not responsive
        inelastive_load.maximumPower = 0  # Remember that a load is a negative power [kW]
        inelastive_load.minimumPower = -2 * 8200  # Assume twice the average PNNL load [kW]

        # Add inelastive asset model
        inelastive_load_model = OpenLoopPnnlLoadPredictor(weather_service)
        inelastive_load_model.name = 'InelasticBuildingsModel'
        inelastive_load_model.engagementCost = [
            0, 0, 0
        ]  # Transition costs irrelevant
        inelastive_load_model.defaultPower = -6000  # [kW]
        inelastive_load_model.defaultVertices = [Vertex(0, 0, -6000.0, 1)]

        # Cross-reference asset & asset model
        inelastive_load_model.object = inelastive_load
        inelastive_load.model = inelastive_load_model

        # Add solar PV asset
        solar_pv = SolarPvResource()
        solar_pv.maximumPower = self.PV_max_kW  # [avg.kW]
        solar_pv.minimumPower = 0.0  # [avg.kW]
        solar_pv.name = 'SolarPv'
        solar_pv.description = '120 kW solar PV site on the campus'

        # Add solar PV asset model
        solar_pv_model = SolarPvResourceModel()
        solar_pv_model.cloudFactor = 1.0  # dimensionless
        solar_pv_model.engagementCost = [0, 0, 0]
        solar_pv_model.name = 'SolarPvModel'
        solar_pv_model.defaultPower = 0.0  # [avg.kW]
        solar_pv_model.defaultVertices = [Vertex(0, 0, 30.0, True)]
        solar_pv_model.costParameters = [0, 0, 0]
        solar_pv_model.inject(self, power_topic=self.solar_topic)

        # Cross-reference asset & asset model
        solar_pv.model = solar_pv_model
        solar_pv_model.object = solar_pv

        # Add inelastive and solar_pv as campus' assets
        self.localAssets.extend([inelastive_load, solar_pv])

        # Add Market
        market = Market()
        market.name = 'dayAhead'
        market.commitment = False
        market.converged = False
        market.defaultPrice = 0.04  # [$/kWh]
        market.dualityGapThreshold = self.duality_gap_threshold  # [0.02 = 2#]
        market.initialMarketState = MarketState.Inactive
        market.marketOrder = 1  # This is first and only market
        market.intervalsToClear = 1  # Only one interval at a time
        market.futureHorizon = timedelta(
            hours=24)  # Projects 24 hourly future intervals
        market.intervalDuration = timedelta(
            hours=1)  # [h] Intervals are 1 h long
        market.marketClearingInterval = timedelta(hours=1)  # [h]
        market.marketClearingTime = Timer.get_cur_time().replace(
            hour=0, minute=0, second=0,
            microsecond=0)  # Aligns with top of hour
        market.nextMarketClearingTime = market.marketClearingTime + timedelta(
            hours=1)
        self.markets.append(market)

        # City object
        city = Neighbor()
        city.name = 'CoR'
        city.description = 'City of Richland (COR) electricity supplier node'
        city.maximumPower = 20000  # Remember loads have negative power [avg.kW]
        city.minimumPower = 0  # [avg.kW]
        city.lossFactor = self.city_loss_factor

        # City model
        city_model = NeighborModel()
        city_model.name = 'CoR_Model'
        city_model.location = self.name
        city_model.transactive = True
        city_model.defaultPower = 10000  # [avg.kW]
        city_model.defaultVertices = [
            Vertex(0.046, 160, 0, True),
            Vertex(0.048,
                   160 + city.maximumPower * (0.046 + 0.5 * (0.048 - 0.046)),
                   city.maximumPower, True)
        ]
        city_model.costParameters = [0, 0, 0]
        city_model.demand_threshold_coef = self.demand_threshold_coef
        city_model.demandThreshold = self.monthly_peak_power
        city_model.inject(self,
                          system_loss_topic=self.system_loss_topic,
                          dc_threshold_topic=self.dc_threshold_topic)

        # Cross-reference object & model
        city_model.object = city
        city.model = city_model
        self.city = city

        # Add city as campus' neighbor
        self.neighbors.append(city)

        # Add buildings
        for bldg_name in self.building_names:
            bldg_neighbor = self.make_bldg_neighbor(bldg_name)
            self.neighbors.append(bldg_neighbor)
コード例 #11
0
    def balance_market(self,
                       run_cnt,
                       start_of_cycle=False,
                       fail_to_converged=False,
                       fail_to_converged_neighbor=None):
        market = self.markets[0]  # Assume only 1 TNS market per node
        market.signal_new_data = True
        market.balance(self)  # Assume only 1 TNS market per node

        if market.converged:
            _log.debug("TNS market {} balanced successfully.".format(
                market.name))

            # Sum all the powers as will be needed by the net supply/demand curve.
            market.assign_system_vertices(self)

            # Send only if either of the 2 conditions below occurs:
            # 1) Model balancing did not converge
            # 2) A new cycle (ie. begin of hour)
            for n in self.neighbors:
                # If the neighbor failed to converge (eg., building1 failed to converge)
                if n == fail_to_converged_neighbor and n is not None:
                    n.model.prep_transactive_signal(market, self)
                    topic = self.campus_demand_topic
                    if n != self.city:
                        topic = self.campus_supply_topic.format(n.name)
                    n.model.send_transactive_signal(self, topic,
                                                    start_of_cycle)
                    _log.debug("NeighborModel {} sent records.".format(
                        n.model.name))

                else:
                    # Always send signal downstream at the start of a new cyle
                    if start_of_cycle:
                        if n != self.city:
                            n.model.prep_transactive_signal(market, self)
                            topic = self.campus_supply_topic.format(n.name)
                            n.model.send_transactive_signal(
                                self, topic, start_of_cycle)
                            _log.debug("NeighborModel {} sent records.".format(
                                n.model.name))
                    else:
                        _log.debug(
                            "Not start of cycle. Check convergence for neighbor {}."
                            .format(n.model.name))
                        n.model.check_for_convergence(market)
                        if not n.model.converged:
                            n.model.prep_transactive_signal(market, self)
                            topic = self.campus_demand_topic
                            if n != self.city:
                                topic = self.campus_supply_topic.format(n.name)
                            n.model.send_transactive_signal(
                                self, topic, start_of_cycle)
                            _log.debug("NeighborModel {} sent records.".format(
                                n.model.name))
                        else:
                            _log.debug(
                                "{} ({}) did not send records due to check_for_convergence()."
                                .format(n.model.name, self.name))

            # Schedule rerun balancing if not in simulation mode
            if not self.simulation:
                # For start_of_cyle=True, the code above always send signal to neighbors so don't need to reschedule
                # Schedule rerun if any neighbor is not converged
                if not start_of_cycle:
                    if not all([n.model.converged for n in self.neighbors]):
                        dt = datetime.now()
                        # Schedule to rerun after 5 minutes if it is in the same hour and is the first reschedule
                        next_run_dt = dt + self.reschedule_interval
                        if dt.hour == next_run_dt.hour and run_cnt >= 1:
                            _log.debug("{} reschedule to run at {}".format(
                                self.name, next_run_dt))
                            self.core.schedule(next_run_dt,
                                               self.balance_market,
                                               run_cnt + 1)
            prices = market.marginalPrices

            # There is a case where the balancing happens at the end of the hour and continues to the next hour, which
            # creates 26 values. Get the last 25 values.
            prices = prices[-25:]
            prices = [x.value for x in prices]
            self.vip.pubsub.publish(peer='pubsub',
                                    topic=self.price_topic,
                                    message={
                                        'prices':
                                        prices,
                                        'current_time':
                                        format_timestamp(Timer.get_cur_time())
                                    })
        else:
            _log.debug("Market balancing sub-problem failed.")
            self.city.model.prep_transactive_signal(market, self)
            self.city.model.send_transactive_signal(self,
                                                    self.campus_demand_topic,
                                                    start_of_cycle)
コード例 #12
0
    def run_ep_sim(self, start_of_cycle):
        # Reset price array
        self.prices = [None for i in range(25)]

        # Save the 1st quantity as prior 2nd quantity
        cur_quantity = self.quantities[1]
        cur_curve = self.building_demand_curves[1]

        # Reset quantities and curves
        self.quantities = [None for i in range(25)]
        self.building_demand_curves = [None for i in range(25)]

        # If new cycle, set the 1st quantity to the corresponding quantity of previous hour
        if start_of_cycle:
            self.quantities[0] = cur_quantity
            self.building_demand_curves[0] = cur_curve

        # Balance market with previous known demands
        market = self.markets[0]  # Assume only 1 TNS market per node
        market.signal_new_data = True
        market.balance(self)

        # Check if now is near the end of the hour, applicable only if not in simulation mode
        now = Timer.get_cur_time()
        near_end_of_hour = False
        if not self.simulation:
            near_end_of_hour = self.near_end_of_hour(now)

        if market.converged:
            # Get new prices (expected 25 values: current hour + next 24)
            prices = market.marginalPrices

            # There is a case where the balancing happens at the end of the hour and continues to the next hour, which
            # creates 26 values. Get the last 25 values.
            prices = prices[-25:]
            self.prices = [p.value for p in prices]

            # Signal to start mix market only if the previous market is done
            if not self.mix_market_running and not near_end_of_hour:
                self.mix_market_running = True

            # Read data from e+ output file
            self.quantities = []
            self.prices = []
            self.building_demand_curves = []

            if self.cur_ep_line < len(self.ep_lines):
                for i in range(self.cur_ep_line, len(self.ep_lines)):
                    line = self.ep_lines[i]
                    if "mixmarket DEBUG: Quantities: " in line:
                        self.quantities = eval(line[line.find('['):])
                    if "mixmarket DEBUG: Prices: " in line:
                        self.prices = eval(line[line.find('['):])
                    if "mixmarket DEBUG: Curves: " in line:
                        tmp = eval(line[line.find('['):])

                        for item in tmp:
                            if item is None:
                                self.building_demand_curves.append(item)
                            else:
                                p1 = Point(item[0][0], item[0][1])
                                p2 = Point(item[1][0], item[1][1])
                                self.building_demand_curves.append((p1, p2))

                    # Stop when have enough information (ie. all data responded by a single E+ simulation)
                    if len(self.quantities) > 0 and len(
                            self.prices) > 0 and len(
                                self.building_demand_curves) > 0:
                        self.cur_ep_line = i + 1
                        break

                self.elastive_load_model.set_tcc_curves(
                    self.quantities, self.prices, self.building_demand_curves)
                self.balance_market(1)
コード例 #13
0
    def price_callback(self, timestamp, market_name, buyer_seller, price,
                       quantity):
        _log.debug("{}: cleared price ({}, {}) for {} as {} at {}".format(
            Timer.get_cur_time(), price, quantity, market_name, buyer_seller,
            timestamp))
        idx = int(market_name.split('_')[-1])
        self.prices[
            idx +
            1] = price  # price has 24 values, current hour price is excluded
        if price is None:
            raise "Market {} did not clear. Price is none.".format(market_name)
        idx += 1  # quantity has 25 values while there are 24 future markets
        if self.quantities[idx] is None:
            self.quantities[idx] = 0.
        if quantity is None:
            _log.error("Quantity is None. Set it to 0. Details below.")
            _log.debug("{}: ({}, {}) for {} as {} at {}".format(
                self.agent_name, price, quantity, market_name, buyer_seller,
                timestamp))
            quantity = 0
        self.quantities[idx] += quantity

        _log.debug("At {}, Quantity is {} and quantities are: {}".format(
            Timer.get_cur_time(), quantity, self.quantities))
        if quantity is not None and quantity < 0:
            _log.error(
                "Quantity received from mixmarket is negative!!! {}".format(
                    quantity))

        # If all markets (ie. exclude 1st value) are done then update demands, otherwise do nothing
        mix_market_done = all(
            [False if q is None else True for q in self.quantities[1:]])
        if mix_market_done:
            # Check if any quantity is greater than physical limit of the supply wire
            _log.debug("Quantity: {}".format(self.quantities))
            if not all([
                    False if q > self.max_deliver_capacity else True
                    for q in self.quantities[1:]
            ]):
                _log.error("One of quantity is greater than "
                           "physical limit {}".format(
                               self.max_deliver_capacity))

            # Check demand curves exist
            all_curves_exist = all([
                False if q is None else True
                for q in self.building_demand_curves[1:]
            ])
            if not all_curves_exist:
                _log.error("Demand curves: {}".format(
                    self.building_demand_curves))
                raise "Mix market has all quantities but not all demand curves"

            # Update demand and balance market
            self.mix_market_running = False
            #self.elastive_load_model.default_powers = [-q if q is not None else None for q in self.quantities]
            curves_arr = [(c[0].tuppleize(),
                           c[1].tuppleize()) if c is not None else None
                          for c in self.building_demand_curves]
            _log.debug("Data at time {}:".format(Timer.get_cur_time()))
            _log.debug("Market intervals: {}".format(
                [x.name for x in self.markets[0].timeIntervals]))
            _log.debug("Quantities: {}".format(self.quantities))
            _log.debug("Prices: {}".format(self.prices))
            _log.debug("Curves: {}".format(curves_arr))

            db_topic = "/".join([self.db_topic, self.name, "AggregateDemand"])
            message = {
                "Timestamp": format_timestamp(timestamp),
                "Curves": self.building_demand_curves
            }
            headers = {
                headers_mod.DATE: format_timestamp(Timer.get_cur_time())
            }
            self.vip.pubsub.publish("pubsub", db_topic, headers, message).get()

            db_topic = "/".join([self.db_topic, self.name, "Price"])
            price_message = []
            for i in range(len(self.markets[0].timeIntervals)):
                ts = self.markets[0].timeIntervals[i].name
                price = self.prices[i]
                quantity = self.quantities[i]
                price_message.append({
                    'timeInterval': ts,
                    'price': price,
                    'quantity': quantity
                })
            message = {
                "Timestamp": format_timestamp(timestamp),
                "Price": price_message
            }
            headers = {
                headers_mod.DATE: format_timestamp(Timer.get_cur_time())
            }
            self.vip.pubsub.publish("pubsub", db_topic, headers, message).get()

            self.elastive_load_model.set_tcc_curves(
                self.quantities, self.prices, self.building_demand_curves)
            self.balance_market(1)
コード例 #14
0
    def init_objects(self):
        # Add meter
        # meter = MeterPoint()
        # meter.name = 'BuildingElectricMeter'
        # meter.measurementType = MeasurementType.PowerReal
        # meter.measurementUnit = MeasurementUnit.kWh
        # self.meterPoints.append(meter)

        # Add weather forecast service
        weather_service = TemperatureForecastModel(self.config_path, self)
        self.informationServiceModels.append(weather_service)

        # # Add inelastive asset
        # inelastive_load = LocalAsset()
        # inelastive_load.name = 'InelasticBldgLoad'
        # inelastive_load.maximumPower = 0  # Remember that a load is a negative power [kW]
        # inelastive_load.minimumPower = -200
        #
        # # Add inelastive asset model
        # inelastive_load_model = LocalAssetModel()
        # inelastive_load_model.name = 'InelasticBuildingModel'
        # inelastive_load_model.defaultPower = -100  # [kW]
        # inelastive_load_model.defaultVertices = [Vertex(float("inf"), 0, -100, True)]
        #
        # # Cross-reference asset & asset model
        # inelastive_load_model.object = inelastive_load
        # inelastive_load.model = inelastive_load_model

        # Add elastive asset
        elastive_load = LocalAsset()
        elastive_load.name = 'TccLoad'
        elastive_load.maximumPower = 0  # Remember that a load is a negative power [kW]
        elastive_load.minimumPower = -self.max_deliver_capacity

        # Add inelastive asset model
        # self.elastive_load_model = LocalAssetModel()
        self.elastive_load_model = TccModel()
        self.elastive_load_model.name = 'TccModel'
        self.elastive_load_model.defaultPower = -0.5 * self.max_deliver_capacity  # [kW]
        self.elastive_load_model.defaultVertices = [
            Vertex(0.055, 0, -self.elastive_load_model.defaultPower, True),
            Vertex(0.06, 0, -self.elastive_load_model.defaultPower / 2, True)
        ]

        # Cross-reference asset & asset model
        self.elastive_load_model.object = elastive_load
        elastive_load.model = self.elastive_load_model

        # Add inelastive and elastive loads as building' assets
        self.localAssets.extend([elastive_load])

        # Add Market
        market = Market()
        market.name = 'dayAhead'
        market.commitment = False
        market.converged = False
        market.defaultPrice = 0.0428  # [$/kWh]
        market.dualityGapThreshold = self.duality_gap_threshold  # [0.02 = 2#]
        market.initialMarketState = MarketState.Inactive
        market.marketOrder = 1  # This is first and only market
        market.intervalsToClear = 1  # Only one interval at a time
        market.futureHorizon = timedelta(
            hours=24)  # Projects 24 hourly future intervals
        market.intervalDuration = timedelta(
            hours=1)  # [h] Intervals are 1 h long
        market.marketClearingInterval = timedelta(hours=1)  # [h]
        market.marketClearingTime = Timer.get_cur_time().replace(
            hour=0, minute=0, second=0,
            microsecond=0)  # Aligns with top of hour
        market.nextMarketClearingTime = market.marketClearingTime + timedelta(
            hours=1)
        self.markets.append(market)

        # Campus object
        campus = Neighbor()
        campus.name = 'PNNL_Campus'
        campus.description = 'PNNL_Campus'
        campus.maximumPower = self.max_deliver_capacity
        campus.minimumPower = 0.  # [avg.kW]
        campus.lossFactor = self.campus_loss_factor

        # Campus model
        campus_model = NeighborModel()
        campus_model.name = 'PNNL_Campus_Model'
        campus_model.location = self.name
        campus_model.defaultVertices = [
            Vertex(0.045, 25, 0, True),
            Vertex(0.048, 0, self.max_deliver_capacity, True)
        ]

        campus_model.transactive = True
        campus_model.demand_threshold_coef = self.demand_threshold_coef
        # campus_model.demandThreshold = self.demand_threshold_coef * self.monthly_peak_power
        campus_model.demandThreshold = self.monthly_peak_power
        campus_model.inject(self,
                            system_loss_topic=self.system_loss_topic,
                            dc_threshold_topic=self.dc_threshold_topic)

        # Avg building meter
        building_meter = MeterPoint()
        building_meter.name = self.name + ' ElectricMeter'
        building_meter.measurementType = MeasurementType.AverageDemandkW
        building_meter.measurementUnit = MeasurementUnit.kWh
        campus_model.meterPoints.append(building_meter)

        # Cross-reference object & model
        campus_model.object = campus
        campus.model = campus_model
        self.campus = campus

        # Add campus as building's neighbor
        self.neighbors.append(campus)
コード例 #15
0
    def start_mixmarket(self, start_of_cycle):
        # Reset price array
        self.prices = [None for i in range(25)]

        # Save the 1st quantity as prior 2nd quantity
        cur_quantity = self.quantities[1]
        cur_curve = self.building_demand_curves[1]

        # Reset quantities and curves
        self.quantities = [None for i in range(25)]
        self.building_demand_curves = [None for i in range(25)]

        # If new cycle, set the 1st quantity to the corresponding quantity of previous hour
        if start_of_cycle:
            self.quantities[0] = cur_quantity
            self.building_demand_curves[0] = cur_curve

        # Balance market with previous known demands
        market = self.markets[0]  # Assume only 1 TNS market per node
        market.signal_new_data = True
        market.balance(self)

        # Check if now is near the end of the hour, applicable only if not in simulation mode
        now = Timer.get_cur_time()
        near_end_of_hour = False
        if not self.simulation:
            near_end_of_hour = self.near_end_of_hour(now)

        if market.converged:
            # Get new prices (expected 25 values: current hour + next 24)
            prices = market.marginalPrices

            # There is a case where the balancing happens at the end of the hour and continues to the next hour, which
            # creates 26 values. Get the last 25 values.
            prices = prices[-25:]
            self.prices = [p.value for p in prices]

            # Signal to start mix market only if the previous market is done
            if not self.mix_market_running and not near_end_of_hour:
                self.mix_market_running = True
                # Update weather information
                weather_service = None
                if len(self.informationServiceModels) > 0:
                    weather_service = self.informationServiceModels[0]
                    weather_service.update_information(market)

                _log.debug("prices are {}".format(self.prices))
                if weather_service is None:
                    self.vip.pubsub.publish(peer='pubsub',
                                            topic='mixmarket/start_new_cycle',
                                            message={
                                                "prices": self.prices[-24:],
                                                "Date": format_timestamp(now)
                                            })
                else:
                    temps = [x.value for x in weather_service.predictedValues]
                    temps = temps[-24:]
                    _log.debug("temps are {}".format(temps))
                    self.vip.pubsub.publish(peer='pubsub',
                                            topic='mixmarket/start_new_cycle',
                                            message={
                                                "prices": self.prices[-24:],
                                                "temp": temps,
                                                "Date": format_timestamp(now)
                                            })