def update_information(ism, mkt):
        #   Gather active time intervals ti
        ti = mkt.timeIntervals

        #   index through active time intervals ti
        for i in range(len(ti)):  # for i = 1:length(ti)
            #       Get the start time for the indexed time interval
            st = ti(i).startTime

            #       Extract the starting time hour
            hr = st.hour

            #       Look up the value in a table. NOTE: tables may be used during
            #       development until active information services are developed.
            # Is the purpose of this one to read MODERATE weather temperature? YES
            T = readtable(ism.file)
            value = T(hr + 1, 1)

            #       Check whether the information exists in the indexed time interval
            # Question: what is ism? InformationServiceModel doesn't have 'values' as well as 'iv' properties.
            #   Suggestion: use long name as much as possible
            #   Need an example on what this one does. Really need a unit test here?
            #iv = findobj(ism.values, 'timeInterval', ti(i))
            iv = [x for x in ism.values if x.timeInterval.startTime == ti[i].startTime]  #
            iv = iv[0] if len(iv)>0 else None

            if iv is None:  # isempty(iv):
                # The value does not exist in the indexed time interval. Create it and store it.
                #iv = IntervalValue(ism, ti(i), mkt, 'Temperature', value)
                iv = IntervalValue(ism, ti[i], mkt, MeasurementType.Temperature, value)
                ism.values = [ism.values, iv]

            else:
                # The value exists in the indexed time interval. Simply reassign it
                iv.value = value
示例#2
0
    def update_dual_costs(self, mkt):
        # Update the dual cost for all active time intervals
        # (NOTE: Choosing not to separate this def from the base class because
        # cost might need to be handled differently and redefined in subclasses.)

        # Gather the active time intervals ti
        time_intervals = mkt.timeIntervals
        time_interval_values = [t.startTime for t in time_intervals]
        self.dualCosts = [
            x for x in self.dualCosts
            if x.timeInterval.startTime in time_interval_values
        ]

        # Index through the time intervals ti
        for i in range(1, len(time_intervals)):
            # Find the marginal price mp for the indexed time interval ti(i) in
            # the given market mkt
            mp = find_obj_by_ti(mkt.marginalPrices, time_intervals[i])
            mp = mp.value  # a marginal price [$/kWh]

            # Find the scheduled power sp for the asset in the indexed time interval ti(i)
            sp = find_obj_by_ti(self.scheduledPowers, time_intervals[i])
            sp = sp.value  # schedule power [avg.kW]

            # Find the production cost in the indexed time interval
            pc = find_obj_by_ti(self.productionCosts, time_intervals[i])
            pc = pc.value  # production cost [$]

            # Dual cost in the time interval is calculated as production cost,
            # minus the product of marginal price, scheduled power, and the
            # duration of the time interval.
            dur = time_intervals[i].duration.seconds // 3600
            dc = pc - (mp * sp * dur)  # a dual cost [$]

            # Check whether a dual cost exists in the indexed time interval
            iv = find_obj_by_ti(self.dualCosts, time_intervals[i])

            if iv is None:
                # No dual cost was found in the indexed time interval. Create an
                # interval value and assign it the calculated value.
                iv = IntervalValue(self, time_intervals[i], mkt,
                                   MeasurementType.DualCost, dc)

                # Append the new interval value to the list of active interval values
                self.dualCosts.append(iv)

            else:
                # The dual cost value was found to already exist in the indexed
                # time interval. Simply reassign it the new calculated value.
                iv.value = dc  # a dual cost [$]

        # Ensure that only active time intervals are in the list of dual costs adc
        #self.dualCosts = [x for x in self.dualCosts if x.timeInterval in ti]

        # Sum the total dual cost and save the value
        self.totalDualCost = sum([x.value for x in self.dualCosts])

        dc = [(x.timeInterval.name, x.value) for x in self.dualCosts]
        _log.debug("{} asset model dual costs are: {}".format(self.name, dc))
示例#3
0
    def update_vertices(self, mkt):
        # Create vertices to represent the asset's flexibility
        #
        # For the base local asset model, a single, inelastic power is needed.
        # There is no flexibility. The constant power may be represented by a
        # single (price, power) point (See struct Vertex).

        # Gather active time intervals
        ti = mkt.timeIntervals  # active TimeIntervals
        time_interval_values = [t.startTime for t in ti]
        self.activeVertices = [
            x for x in self.activeVertices
            if x.timeInterval.startTime in time_interval_values
        ]

        # Index through active time intervals ti
        for i in range(len(ti)):
            # Find the scheduled power for the indexed time interval
            # Extract the scheduled power value
            sp = find_obj_by_ti(self.scheduledPowers, ti[i])
            sp = sp.value  # avg. kW]

            # Create the vertex that can represent this (lack of) flexibility
            value = Vertex(float("inf"), 0.0, sp, True)

            # Check to see if the active vertex already exists for this indexed time interval.
            iv = find_obj_by_ti(self.activeVertices, ti[i])

            # If the active vertex does not exist, a new interval value must be
            # created and stored.
            if iv is None:
                # Create the interval value and place the active vertex in it
                iv = IntervalValue(self, ti[i], mkt,
                                   MeasurementType.ActiveVertex, value)

                # Append the interval value to the list of active vertices
                self.activeVertices.append(iv)

            else:
                # Otherwise, simply reassign the active vertex value to the
                # existing listed interval value. (NOTE that this base local
                # asset model unnecessarily reassigns constant values, but the
                # reassignment is allowed because it teaches how a more dynamic
                # assignment may be maintained.
                iv.value = value

        av = [(x.timeInterval.name, x.value.marginalPrice, x.value.power)
              for x in self.activeVertices]
        _log.debug("{} asset model active vertices are: {}".format(
            self.name, av))
示例#4
0
    def schedule_engagement(self, mkt):
        # To assign engagement, or commitment, which
        # is relevant to some local assets (supports future capabilities).
        # NOTE: The assignment of engagement schedule, if used, may be assigned
        # during the scheduling of power, not separately as demonstrated here.
        # Commitment and engagement are closely aligned with the optimal
        # production costs of schedulable generators and utility def of
        # engagements (e.g., demand responses).

        # NOTE: Because this is a future capability, Implementers might choose to
        # simply return from the call until LocalAsset behaviors are found to need
        # commitment or engagement.

        # Gather the active time intervals ti
        time_intervals = mkt.timeIntervals  # active TimeIntervals
        time_interval_values = [t.startTime for t in time_intervals]
        self.engagementSchedule = [
            x for x in self.engagementSchedule
            if x.timeInterval.startTime in time_interval_values
        ]

        # Index through the active time intervals ti
        for i in range(len(time_intervals)):
            # Check whether an engagement schedule exists in the indexed time interval
            iv = find_obj_by_ti(self.engagementSchedule, time_intervals[i])

            # NOTE: this template currently assigns engagement value as true (i.e., engaged).
            val = True  # Asset is committed or engaged

            if iv is None:
                # No engagement schedule was found in the indexed time interval.
                # Create an interval value and assign its value.
                iv = IntervalValue(self, time_intervals[i], mkt,
                                   MeasurementType.EngagementValue,
                                   val)  # an IntervalValue

                # Append the interval value to the list of active interval values
                self.engagementSchedule.append(iv)

            else:
                # An engagement schedule was found in the indexed time interval.
                # Simpy reassign its value.
                iv.value = val  # [$]
示例#5
0
    def update_production_costs(self, mkt):
        # Calculate the costs of generated energies.
        # (NOTE: Choosing not to separate this def from the base class because
        # cost might need to be handled differently and redefined in subclasses.)

        # Gather active time intervals ti
        time_intervals = mkt.timeIntervals
        time_interval_values = [t.startTime for t in time_intervals]
        self.productionCosts = [
            x for x in self.productionCosts
            if x.timeInterval.startTime in time_interval_values
        ]

        # Index through the active time interval ti
        for i in range(1, len(time_intervals)):
            # Get the scheduled power sp in the indexed time interval
            sp = find_obj_by_ti(self.scheduledPowers, time_intervals[i])
            sp = sp.value  # schedule power [avg.kW]

            # Call on def that calculates production cost pc based on the
            # vertices of the supply or demand curve
            # NOTE that this def is now stand-alone because it might be
            # generally useful for a number of models.
            pc = prod_cost_from_vertices(self, time_intervals[i],
                                         sp)  # interval production cost [$]

            # Check for a transition cost in the indexed time interval.
            # (NOTE: this differs from neighbor models, which do not posses the
            # concept of commitment and engagement. This is a good reason to keep
            # this method within its base class to allow for subtle differences.)
            tc = find_obj_by_ti(self.transitionCosts, time_intervals[i])

            if tc is None:
                tc = 0.0  # [$]
            else:
                tc = tc.value  # [$]

            # Add the transition cost to the production cost
            pc = pc + tc

            # Check to see if the production cost value has been defined for the
            # indexed time interval
            iv = find_obj_by_ti(self.productionCosts, time_intervals[i])

            if iv is None:
                # The production cost value has not been defined in the indexed
                # time interval. Create it and assign its value pc.
                iv = IntervalValue(self, time_intervals[i], mkt,
                                   MeasurementType.ProductionCost, pc)

                # Append the production cost to the list of active production
                # cost values
                self.productionCosts.append(iv)  # IntervalValues

            else:
                # The production cost value already exists in the indexed time
                # interval. Simply reassign its value.
                iv.value = pc  # interval production cost [$]

        # Ensure that only active time intervals are in the list of active
        # production costs apc
        #self.productionCosts = [x for x in self.productionCosts if x.timeInterval in time_intervals]

        # Sum the total production cost
        self.totalProductionCost = sum([x.value for x in self.productionCosts
                                        ])  # total production cost [$]

        pc = [(x.timeInterval.name, x.value) for x in self.productionCosts]
        _log.debug("{} asset model production costs are: {}".format(
            self.name, pc))
示例#6
0
    def assign_transition_costs(self, mkt):
        # Assign the cost of changeing
        # engagement state from the prior to the current time interval
        #
        # PRESUMPTIONS:
        # - Time intervals exist and have been updated
        # - The engagement schedule exists and has been updated. Contents are
        #   logical [true/false].
        # - Engagement costs have been accurately assigned for [disengagement,
        #   unchanged, engagement]
        #
        # INPUTS:
        # mkt - Market object
        #
        # USES:
        # - self.engagementCost - three costs that correspond to
        #   [disengagement, unchanged, engagement) transitions
        # - self.engagement_cost() - assigns appropriate cost from
        #   self.engagementCost property
        # - self.engagementSchedule - engagement states (true/false) for the asset
        #   in active time intervals
        #
        # OUTPUTS:
        # Assigns values to self.transition_costs

        # Gather active time intervals
        time_intervals = mkt.timeIntervals
        time_interval_values = [t.startTime for t in time_intervals]
        self.transitionCosts = [
            x for x in self.transitionCosts
            if x.timeInterval.startTime in time_interval_values
        ]

        # Ensure that ti is ordered by time interval start times
        time_intervals.sort(key=lambda x: x.startTime)

        # Index through all but the first time interval ti
        for i in range(len(time_intervals)):
            # Find the current engagement schedule ces in the current indexed
            # time interval ti(i)
            ces = [
                x for x in self.engagementSchedule
                if x.timeInterval.startTime == time_intervals[i].startTime
            ]

            # Extract its engagement state
            ces = ces[0].value  # logical (true/false)

            # Find the engagement schedule pes in the prior indexed time interval ti(i-1)
            pes = [
                x for x in self.engagementSchedule
                if x.timeInterval.startTime == time_intervals[i - 1].startTime
            ]

            # And extract its value
            pes = pes[0].value  # logical (true/false)

            # Calculate the state transition
            # - -1:Disengaging
            # -  0:Unchaged
            # -  1:Engaging
            dif = ces - pes

            # Assign the corresponding transition cost
            val = self.engagement_cost(dif)

            # Check whether a transition cost exists in the indexed time interval
            iv = find_obj_by_ti(self.transitionCosts, time_intervals[i])

            if iv is None:
                # No transition cost was found in the indexed time interval.
                # Create an interval value and assign its value.
                iv = IntervalValue(self, time_intervals[i], mkt,
                                   MeasurementType.TransitionCost, val)

                # Append the interval value to the list of active interval values
                self.transitionCosts.append(iv)

            else:
                # A transition cost was found in the indexed time interval.
                # Simpy reassign its value.
                iv.value = val  # [$]
示例#7
0
    def calculate_reserve_margin(self, mkt):
        # Estimate available (spinning) reserve margin for this asset.
        #
        # NOTES:
        #   This method works with the simplest base classes that have constant
        #   power and therefore provide no spinning reserve. This method may be
        #   redefined by subclasses of the local asset model to add new features
        #   or capabilities.
        #   This calculation will be more meaningful and useful after resource
        #   commitments and uncertainty estimates become implemented. Until then,
        #   reserve margins may be tracked, even if they are not used.
        #
        # PRESUMPTIONS:
        # - Active time intervals exist and have been updated
        # - The asset's maximum power is a meaningful and accurate estimate of
        #   the maximum power level that can be achieved on short notice, i.e.,
        #   spinning reserve.
        #
        # INPUTS:
        # mkt - market object
        #
        # OUTPUTS:
        # Modifies self.reserveMargins - an array of estimated (spinning) reserve
        # margins in active time intervals

        # Gather the active time intervals ti
        time_intervals = mkt.timeIntervals  # active TimeIntervals
        time_interval_values = [t.startTime for t in time_intervals]
        self.reserveMargins = [
            x for x in self.reserveMargins
            if x.timeInterval.startTime in time_interval_values
        ]

        # Index through active time intervals ti
        for i in range(len(time_intervals)):
            # Calculate the reserve margin for the indexed interval. This is the
            # non-negative difference between the maximum asset power and the
            # scheduled power. In principle, generation may be increased or
            # demand decreased by this quantity to act as spinning reserve.

            # Find the scheduled power in the indexed time interval
            iv = find_obj_by_ti(self.scheduledPowers, time_intervals[i])

            # Calculate the reserve margin rm in the indexed time interval. The
            # reserve margin is the differnce between the maximum operational
            # power value in the interval and the scheduled power. The
            # operational maximum should be less than the object's hard physical
            # power constraint, so a check is in order.
            # start with the hard physical constraint.
            hard_const = self.object.maximumPower  # [avg.kW]

            # Calculate the operational maximum constraint, which is the highest
            # point on the supply/demand curve (i.e., the vertex) that represents
            # the residual flexibility of the asset in the time interval.
            op_const = find_objs_by_ti(self.activeVertices, time_intervals[i])

            if len(op_const) == 0:
                op_const = hard_const
            else:
                op_const = [x.value for x in op_const]  # active vertices
                op_const = max([x.power for x in op_const
                                ])  # operational max. power[avg.kW]

            # Check that the upper operational power constraint is less than or
            # equal to the object's hard physical constraint.
            soft_maximum = min(hard_const, op_const)  # [avg.kW]

            # And finally calculate the reserve margin.
            rm = max(0, soft_maximum - iv.value)  # reserve margin [avg. kW]

            # Check whether a reserve margin already exists for the indexed time interval
            iv = find_obj_by_ti(self.reserveMargins,
                                time_intervals[i])  # an IntervalValue

            if iv is None:
                # A reserve margin does not exist for the indexed time interval.
                # create it. (See IntervalValue class.)
                iv = IntervalValue(self, time_intervals[i], mkt,
                                   MeasurementType.ReserveMargin,
                                   rm)  # an IntervalValue

                # Append the new reserve margin interval value to the list of
                # reserve margins for the active time intervals
                self.reserveMargins.append(iv)

            else:
                # The reserve margin already exists for the indexed time
                # interval. Simply reassign its value.
                iv.value = rm  # reserve margin [avg.kW]
示例#8
0
    def schedule_power(self, mkt):
        # Determine powers of an asset in active time
        # intervals. NOTE that this method may be redefined by subclasses if more
        # features are needed. NOTE that this method name is common for all asset
        # and neighbor models to facilitate its redefinition.
        #
        # PRESUMPTIONS:
        # - Active time intervals exist and have been updated
        # - Marginal prices exist and have been updated. NOTE: Marginal prices
        #   are not used for inelastic assets.
        # - Transition costs, if relevant, are applied during the scheduling
        #   of assets.
        # - An engagement schedule, if used, is applied during an asset's power
        #   scheduling.
        # - Scheduled power and engagement schedule must be self consistent at
        # the end of this method. That is, power should not be scheduled while
        # the asset is disengaged (uncommitted).
        #
        # INPUTS:
        # mkt - market object
        #
        # OUTPUTS:
        # - Updates self.scheduledPowers - the schedule of power consumed
        # - Updates self.engagementSchedule - an array that states whether the
        #   asset is engaged (committed) (true) or not (false) in the time interval

        # Gather the active time intervals ti
        time_intervals = mkt.timeIntervals
        time_interval_values = [t.startTime for t in time_intervals]
        self.scheduledPowers = [
            x for x in self.scheduledPowers
            if x.timeInterval.startTime in time_interval_values
        ]

        time_intervals.sort(key=lambda x: x.startTime)

        len_powers = len(self.default_powers)
        default_value = self.defaultPower

        # Index through the active time intervals ti
        for i in range(len(time_intervals)):
            # Check whether a scheduled power already exists for the indexed time interval
            iv = find_obj_by_ti(self.scheduledPowers, time_intervals[i])

            # Reassign default value if there is power value for this time interval
            if len_powers > i:
                default_value = self.default_powers[i] if self.default_powers[
                    i] is not None else self.defaultPower

            if iv is None:  # A scheduled power does not exist for the indexed time interval
                # Create an interval value and assign the default value
                iv = IntervalValue(self, time_intervals[i], mkt,
                                   MeasurementType.ScheduledPower,
                                   default_value)

                # Append the new scheduled power to the list of scheduled
                # powers for the active time intervals
                self.scheduledPowers.append(iv)

            else:
                # The scheduled power already exists for the indexed time
                # interval. Simply reassign its value
                iv.value = default_value  # [avg.kW]

        sp = [(x.timeInterval.name, x.value) for x in self.scheduledPowers]
        _log.debug("{} asset model scheduledPowers are: {}".format(
            self.name, sp))
    def schedule_power(self, mkt):
        # Estimate stochastic generation from a solar
        # PV array as a function of time-of-day and a cloud-cover factor.
        # INPUTS:
        # obj - SolarPvResourceModel class object
        # tod - time of day
        # OUTPUTS:
        # p - calcalated maximum power production at this time of day
        # LOCAL:
        # h - hour (presumes 24-hour clock, local time)
        # *************************************************************************

        # Gather active time intervals
        tis = mkt.timeIntervals

        # Index through the active time intervals ti
        for ti in tis:
            # Production will be estimated from the time-of-day at the center of
            # the time interval.
            tod = ti.startTime + ti.duration / 2  # a datetime

            # extract a fractional representation of the hour-of-day
            h = tod.hour
            m = tod.minute
            h = h + m / 60  # TOD stated as fractional hours

            # Estimate solar generation as a sinusoidal function of daylight hours.
            if h < 5.5 or h > 17.5:
                # The time is outside the time of solar production. Set power to zero.
                p = 0.0  # [avg.kW]

            else:
                # A sinusoidal function is used to forecast solar generation
                # during the normally sunny part of a day.
                p = 0.5 * (1 + math.cos((h - 12) * 2.0 * math.pi / 12))
                p = self.object.maximumPower * p
                p = self.cloudFactor * p  # [avg.kW]

            # Check whether a scheduled power exists in the indexed time interval.
            iv = find_obj_by_ti(self.scheduledPowers, ti)
            if iv is None:
                # No scheduled power value is found in the indexed time interval.
                # Create and store one.
                iv = IntervalValue(self, ti, mkt,
                                   MeasurementType.ScheduledPower, p)
                # Append the scheduled power to the list of scheduled powers.
                self.scheduledPowers.append(iv)

            else:
                # A scheduled power already exists in the indexed time interval.
                # Simply reassign its value.
                iv.value = p  # [avg.kW]

            # Assign engagement schedule in the indexed time interval
            # NOTE: The assignment of engagement schedule, if used, will often be
            # assigned during the scheduling of power, not separately as
            # demonstrated here.

            # Check whether an engagement schedule exists in the indexed time interval
            iv = find_obj_by_ti(self.engagementSchedule, ti)

            # NOTE: this template assigns engagement value as true (i.e., engaged).
            val = True  # Asset is committed or engaged

            if iv is None:
                # No engagement schedule was found in the indexed time interval.
                # Create an interval value and assign its value.
                iv = IntervalValue(self, ti, mkt,
                                   MeasurementType.EngagementSchedule,
                                   val)  # an IntervalValue

                # Append the interval value to the list of active interval values
                self.engagementSchedule.append(iv)

            else:
                # An engagement schedule was found in the indexed time interval.
                # Simpy reassign its value.
                iv.value = val  # [$]

        # Remove any extra scheduled powers
        self.scheduledPowers = [
            x for x in self.scheduledPowers if x.timeInterval in tis
        ]

        # Remove any extra engagement schedule values
        self.engagementSchedule = [
            x for x in self.engagementSchedule if x.timeInterval in tis
        ]
示例#10
0
    def update_supply_demand(self, mtn):
        # For each time interval, sum the power that is generated, imported,
        # consumed, or exported for all modeled local resources, neighbors, and
        # local load.

        # Extract active time intervals
        time_intervals = self.timeIntervals  # active TimeIntervals

        time_interval_values = [t.startTime for t in time_intervals]
        # Delete netPowers not in active time intervals
        self.netPowers = [x for x in self.netPowers if x.timeInterval.startTime in time_interval_values]

        # Index through the active time intervals ti
        for i in range(1, len(time_intervals)):
            # Initialize total generation tg
            tg = 0.0  # [avg.kW]

            # Initialize total demand td
            td = 0.0  # [avg.kW]

            # Index through local asset models m.
            m = mtn.localAssets

            for k in range(len(m)):
                mo = find_obj_by_ti(m[k].model.scheduledPowers, time_intervals[i])

                # Extract and include the resource's scheduled power
                p = mo.value  # [avg.kW]

                if p > 0:  # Generation
                    # Add positive powers to total generation tg
                    tg = tg + p  # [avg.kW]

                else:  # Demand
                    # Add negative powers to total demand td
                    td = td + p  # [avg.kW]

            # Index through neighbors m
            m = mtn.neighbors

            for k in range(len(m)):
                # Find scheduled power for this neighbor in the indexed time interval
                mo = find_obj_by_ti(m[k].model.scheduledPowers, time_intervals[i])

                # Extract and include the neighbor's scheduled power
                p = mo.value  # [avg.kW]

                if p > 0:  # Generation
                    # Add positive power to total generation tg
                    tg = tg + p  # [avg.kW]

                else:  # Demand
                    # Add negative power to total demand td
                    td = td + p  # [avg.kW]

            # At this point, total generation and importation tg, and total
            # demand and exportation td have been calculated for the indexed
            # time interval ti[i]

            # Save the total generation in the indexed time interval

            # Check whether total generation exists for the indexed time interval
            iv = find_obj_by_ti(self.totalGeneration, time_intervals[i])

            if iv is None:
                # No total generation was found in the indexed time interval.
                # Create an interval value.
                iv = IntervalValue(self, time_intervals[i], self, MeasurementType.TotalGeneration, tg)  # an IntervalValue

                # Append the total generation to the list of total generations
                self.totalGeneration.append(iv)

            else:
                # Total generation exists in the indexed time interval. Simply
                # reassign its value.
                iv.value = tg

            # Calculate and save total demand for this time interval.
            # NOTE that this formulation includes both consumption and
            # exportation among total load.

            # Check whether total demand exists for the indexed time interval

            iv = find_obj_by_ti(self.totalDemand, time_intervals[i])
            if iv is None:
                # No total demand was found in the indexed time interval. Create
                # an interval value.
                iv = IntervalValue(self, time_intervals[i], self, MeasurementType.TotalDemand, td)  # an IntervalValue

                # Append the total demand to the list of total demands
                self.totalDemand.append(iv)

            else:
                # Total demand was found in the indexed time interval. Simply reassign it.
                iv.value = td

            # Update net power for the interval
            # Net power is the sum of total generation and total load.
            # By convention generation power is positive and consumption
            # is negative.

            # Check whether net power exists for the indexed time interval
            iv = find_obj_by_ti(self.netPowers, time_intervals[i])

            if iv is None:
                # Net power is not found in the indexed time interval. Create an interval value.
                iv = IntervalValue(self, time_intervals[i], self, MeasurementType.NetPower, tg + td)

                # Append the net power to the list of net powers
                self.netPowers.append(iv)
            else:
                # A net power was found in the indexed time interval. Simply reassign its value.
                iv.value = tg + td

        np = [(x.timeInterval.name, x.value) for x in self.netPowers]
        _log.debug("{} market netPowers are: {}".format(self.name, np))
示例#11
0
    def update_costs(self, mtn):
        # Sum the production and dual costs from all modeled local resources, local
        # loads, and neighbors, and then sum them for the entire duration of the
        # time horizon being calculated.
        #
        # PRESUMPTIONS:
        # - Dual costs have been created and updated for all active time
        # intervals for all neighbor objects
        # - Production costs have been created and updated for all active time
        # intervals for all asset objects
        #
        # INTPUTS:
        # mtn - my Transactive Node object
        #
        # OUTPUTS:
        # - Updates Market.productionCosts - an array of total production cost in
        # each active time interval
        # - Updates Market.totalProductionCost - the sum of production costs for
        # the entire future time horizon of active time intervals
        # - Updates Market.dualCosts - an array of dual cost for each active time
        # interval
        # - Updates Market.totalDualCost - the sum of all the dual costs for the
        # entire future time horizon of active time intervals

        # Call each LocalAssetModel to update its costs
        for la in mtn.localAssets:
            la.model.update_costs(self)

        # Call each NeighborModel to update its costs
        for n in mtn.neighbors:
            n.model.update_costs(self)

        for i in range (1, len(self.timeIntervals)):
            ti = self.timeIntervals[i]
            # Initialize the sum dual cost sdc in this time interval
            sdc = 0.0  # [$]

            # Initialize the sum production cost spc in this time interval
            spc = 0.0  # [$]

            for la in mtn.localAssets:
                iv = find_obj_by_ti(la.model.dualCosts, ti)
                sdc = sdc + iv.value  # sum dual cost [$]

                iv = find_obj_by_ti(la.model.productionCosts, ti)
                spc = spc + iv.value  # sum production cost [$]

            for n in mtn.neighbors:
                iv = find_obj_by_ti(n.model.dualCosts, ti)
                sdc = sdc + iv.value  # sum dual cost [$]

                iv = find_obj_by_ti(n.model.productionCosts, ti)
                spc = spc + iv.value  # sum production cost [$]

            # Check to see if a sum dual cost exists in the indexed time interval
            iv = find_obj_by_ti(self.dualCosts, ti)

            if iv is None:
                # No dual cost was found for the indexed time interval. Create
                # an IntervalValue and assign it the sum dual cost for the
                # indexed time interval
                iv = IntervalValue(self, ti, self, MeasurementType.DualCost, sdc)  # an IntervalValue

                # Append the dual cost to the list of interval dual costs
                self.dualCosts.append(iv)  # = [mkt.dualCosts, iv]  # IntervalValues

            else:
                # A sum dual cost value exists in the indexed time interval.
                # Simply reassign its value
                iv.value = sdc  # sum dual cost [$]

            # Check to see if a sum production cost exists in the indexed time interval
            iv = find_obj_by_ti(self.productionCosts, ti)

            if iv is None:
                # No sum production cost was found for the indexed time
                # interval. Create an IntervalValue and assign it the sum
                # prodution cost for the indexed time interval
                iv = IntervalValue(self, ti, self, MeasurementType.ProductionCost, spc)

                # Append the production cost to the list of interval production costs
                self.productionCosts.append(iv)

            else:
                # A sum production cost value exists in the indexed time
                # interval. Simply reassign its value
                iv.value = spc  # sum production cost [$]

        # Sum total dual cost for the entire time horizon
        self.totalDualCost = sum([x.value for x in self.dualCosts])  # [$]

        # Sum total primal cost for the entire time horizon
        self.totalProductionCost = sum([x.value for x in self.productionCosts])  # [$]
示例#12
0
    def schedule_power(self, mkt):
        """
        Predict municipal load.
        This is a model of non-price-responsive load using an open-loop regression model.
        :param mkt:
        :return:
        """

        # Get the active time intervals.
        time_intervals = mkt.timeIntervals  # TimeInterval objects

        TEMP = None
        # Index through the active time intervals.
        for time_interval in time_intervals:
            # Extract the start time from the indexed time interval.
            interval_start_time = time_interval.startTime

            if self.temperature_forecaster is None:  #if isempty(temperature_forecaster)
                # No appropriate information service was found, must use a
                # default temperature value.
                TEMP = 56.6  # [deg.F]
            else:
                # An appropriate information service was found. Get the
                # temperature that corresponds to the indexed time interval.
                interval_value = find_obj_by_ti(
                    self.temperature_forecaster.predictedValues, time_interval)

                if interval_value is None:  #if isempty(interval_value)
                    # No stored temperature was found. Assign a default value.
                    TEMP = 56.6  # [def.F]
                else:
                    # A stored temperature value was found. Use it.
                    TEMP = interval_value.value  # [def.F]

                if TEMP is None:
                    # The temperature value is not a number. Use a default value.
                    TEMP = 56.6  # [def.F]

            # Determine the DOW_Intercept.
            # The DOW_Intercept is a function of categorical day-of-week number
            # DOWN. Calculate the weekday number DOWN.
            DOWN = interval_start_time.weekday()  #weekday(interval_start_time)

            # Look up the DOW_intercept from the short table that is among the
            # class's constant properties.
            DOW_Intercept = self.dowIntercept[DOWN]

            # Determine categorical HOUR of the indexed time interval. This will
            # be needed to mine the HOUR_SEASON_REGIME_Intercept lookup table.
            # The hour is incremented by 1 because the lookup table uses hours
            # [1,24], not [0,23].
            HOUR = interval_start_time.hour  # + 1

            # Determine the categorical SEASON of the indexed time interval.
            # SEASON is a function of MONTH, so start by determining the MONTH of
            # the indexed time interval.
            MONTH = interval_start_time.month  #MONTH = month(interval_start_time)

            # Property season provides an index for use with the
            # HOUR_SEASON_REGIME_Intercept lookup table.
            SEASON = self.season[MONTH - 1]  #obj.season(MONTH);

            # Determine categorical REGIME, which is also an index for use with
            # the HOUR_SEASON_REGIME_Intercept lookup table.
            REGIME = 0  # The default assignment
            if (
                    SEASON == 1 or SEASON == 4
            ) and TEMP <= 56.6:  # (Spring season index OR Fall season index) # AND Heating regime
                REGIME = 1

            # Calcualte the table row. Add final 1 because of header row.
            row = 6 * HOUR + SEASON + REGIME  #6 * (HOUR - 1) + SEASON + REGIME

            # Matlab is 1-based vs. python 0-based.
            row = row - 1

            # Assign the Intercept and Factor values that were found.
            HOUR_SEASON_REGIME_Intercept = self.values[row][0]
            HOUR_SEASON_REGIME_Factor = self.values[row][1]

            # Finally, predict the city load.
            LOAD = DOW_Intercept + HOUR_SEASON_REGIME_Intercept + HOUR_SEASON_REGIME_Factor * TEMP  # [avg.kW]

            # The table defined electric load as a positive value. The network
            # model defines load as a negative value.
            LOAD = -LOAD  # [avg.kW]

            # Look for the scheduled power in the indexed time interval.
            interval_value = find_obj_by_ti(self.scheduledPowers,
                                            time_interval)

            if interval_value is None:
                # No scheduled power was found in the indexed time interval.
                # Create one and store it.
                interval_value = IntervalValue(self, time_interval, mkt,
                                               MeasurementType.ScheduledPower,
                                               LOAD)
                self.scheduledPowers.append(interval_value)
            else:
                # The interval value already exist. Simply reassign its value.
                interval_value.value = LOAD