# Add Market market = Market() market.name = 'dayAhead' market.commitment = False market.converged = False market.defaultPrice = 0.0428 # [$/kWh] market.dualityGapThreshold = 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) city_market.markets.append(market) # Add Campus campus_model = Neighbor() campus_model.name = 'PNNL_Campus_Model' campus_model.defaultPower = -10000 # [avg.kW] campus_model.defaultVertices = [Vertex(0.045, 0.0, -10000.0)] campus_model.transactive = True campus_model.maximumPower = 0.0 # Remember loads have negative power [avg.kW] campus_model.minimumPower = -20000 # [avg.kW] # Add Supplier supplierModel = BulkSupplier_dc()
def test_get_extended_prices(): print("Running test_get_extended_prices()") """ This base method uses the following prioritization to populate the price horizon needed by this local asset: 1. Actual marginal prices offered by the market. 2. Actual marginal prices in prior sequential markets that are similar to the market. 3. Actual marginal prices in prior markets that are being corrected by the market. 4. Modeled prices using the market's price model 5. The market's default price value. 6. Nothing """ # ****************************************************************************************************************** print(" Case 1. Actual marginal prices offered by the market." ) # ***************************************** # The test setup is such that the local asset should use Methods 1 to find an existing marginal price in its market. now = datetime.now() # test_asset = LocalAsset() test_asset_model = LocalAsset() # test_asset = test_asset_model # test_asset_model.object = test_asset test_asset_model.schedulingHorizon = timedelta(hours=0.5) test_market = Market() test_interval = TimeInterval(now, timedelta(hours=1), test_market, now, now) price = 3.14159 test_price = IntervalValue(None, test_interval, test_market, 'test', price) test_market.timeIntervals = [test_interval] test_market.marginalPrices = [test_price] test_mtn = TransactiveNode() test_mtn.markets = [test_market] test_mtn.localAssets = [test_asset_model] assert len(test_market.marginalPrices ) == 1, 'The market was supposed to have a marginal price' assert datetime.now() + test_asset_model.schedulingHorizon \ < test_market.timeIntervals[0].startTime + test_market.intervalDuration, \ 'For this test, the existing marginal price intervals should not extend beyond the scheduling horizon.' try: price_set = test_asset_model.get_extended_prices(test_market) print(" The case ran without errors.") except RuntimeWarning as cause: print(" The case encountered errors.", cause) price_set = [] assert len(price_set) == 1, 'An unexpected number of prices was found' assert price_set[0].value == price, 'The price was no correct' # ****************************************************************************************************************** print( " Case 2. Actual marginal prices in prior sequential market that is similar to the market." ) # **** # The test setup is such that the local asset should sequentially use Methods 1, & 2 to find two marginal prices. now = datetime.now() test_asset_model = LocalAsset() test_asset_model.schedulingHorizon = timedelta( hours=1.5) # Should cause asset to use prior market test_market = Market() test_interval0 = TimeInterval(now, timedelta(hours=1), test_market, now, now) price0 = 3.14159 test_price0 = IntervalValue(None, test_interval0, test_market, 'test', price0) test_market.timeIntervals = [test_interval0] test_market.marginalPrices = [test_price0] test_market.marketSeriesName = "Test Market" test_market.marketClearingTime = now prior_market = Market() test_interval1 = TimeInterval(now, timedelta(hours=1), prior_market, now, now) test_interval2 = TimeInterval(now, timedelta(hours=1), prior_market, now, now + timedelta(hours=1)) price1 = 10 test_price1 = IntervalValue(None, test_interval1, prior_market, 'test', price1) test_price2 = IntervalValue(None, test_interval2, prior_market, 'test', price1) prior_market.timeIntervals = [test_interval1, test_interval2] prior_market.marginalPrices = [test_price1, test_price2] prior_market.marketSeriesName = test_market.marketSeriesName prior_market.marketClearingTime = test_market.marketClearingTime - timedelta( hours=1) test_market.priorMarketInSeries = prior_market # Important pointer to preceding market interval in market series. test_mtn = TransactiveNode() test_mtn.markets = [prior_market, test_market] test_mtn.localAssets = [test_asset_model] assert len(test_market.marginalPrices ) == 1, 'The market was supposed to have a marginal price' assert len(prior_market.marginalPrices ) == 2, "The prior market should have had two prices" assert test_market.marketSeriesName == prior_market.marketSeriesName, 'The market names must be the same' assert test_market.priorMarketInSeries == prior_market, "The market must point to its predecessor in market series" try: price_set = test_asset_model.get_extended_prices(test_market) print(" The case ran without errors.") except RuntimeWarning as result: print(" The case encountered errors.", result) assert len(price_set) == 2, 'An unexpected number of prices was found' assert price_set[0].value == price0, 'The first price was not correct' assert price_set[1].value == price1, 'The second price was not correct' # ****************************************************************************************************************** print( " Case 3. Actual marginal prices in prior markets that are being corrected by the market." ) # ******* # The test setup is such that the local asset should sequentially use Methods 1, 2, & 3 to find three marginal # prices. now = datetime.now() # test_asset = LocalAsset() test_asset_model = LocalAsset() # test_asset.model = test_asset_model # test_asset_model.object = test_asset test_asset_model.schedulingHorizon = timedelta( hours=2.5) # Should cause asset to use prior market test_market = Market() test_interval0 = TimeInterval(now, timedelta(hours=1), test_market, now, now) price0 = 3.14159 test_price0 = IntervalValue(None, test_interval0, test_market, 'test', price0) test_market.timeIntervals = [test_interval0] test_market.marginalPrices = [test_price0] test_market.marketSeriesName = "Test Market" test_market.marketClearingTime = now prior_market = Market() test_interval1 = TimeInterval(now, timedelta(hours=1), prior_market, now, now) test_interval2 = TimeInterval(now, timedelta(hours=1), prior_market, now, now + timedelta(hours=1)) price1 = 10 test_price1 = IntervalValue(None, test_interval1, prior_market, 'test', price1) test_price2 = IntervalValue(None, test_interval2, prior_market, 'test', price1) prior_market.timeIntervals = [test_interval1, test_interval2] prior_market.marginalPrices = [test_price1, test_price2] prior_market.marketSeriesName = test_market.marketSeriesName prior_market.marketClearingTime = test_market.marketClearingTime - timedelta( hours=1) test_market.priorMarketInSeries = prior_market corrected_market = Market() price2 = 20 test_interval3 = TimeInterval(now, timedelta(hours=1), corrected_market, now, now + timedelta(hours=2)) test_price3 = IntervalValue(None, test_interval1, corrected_market, 'test', price2) test_price4 = IntervalValue(None, test_interval2, corrected_market, 'test', price2) test_price5 = IntervalValue(None, test_interval3, corrected_market, 'test', price2) corrected_market.timeIntervals = [ test_interval1, test_interval2, test_interval3 ] corrected_market.marginalPrices = [test_price3, test_price4, test_price5] corrected_market.marketSeriesName = "Corrected Market" corrected_market.marketClearingTime = test_market.marketClearingTime - timedelta( hours=2) corrected_market.intervalDuration = timedelta(hours=1) test_market.priorRefinedMarket = corrected_market test_mtn = TransactiveNode() test_mtn.markets = [corrected_market, prior_market, test_market] test_mtn.localAssets = [test_asset_model] assert len(test_market.marginalPrices ) == 1, 'The market was supposed to have a marginal price' assert len(prior_market.marginalPrices ) == 2, "The prior market should have had two prices" assert len(corrected_market.marginalPrices ) == 3, 'The corrected market should have three prices' assert test_market.marketSeriesName == prior_market.marketSeriesName, 'The market names must be the same' try: price_set = test_asset_model.get_extended_prices(test_market) print(" The case ran without errors.") except RuntimeWarning as result: print(" The case encountered errors.", result) price_set = [] assert len(price_set) == 3, 'An unexpected number of prices was found' assert price_set[0].value == price0, 'The first price was not correct' assert price_set[1].value == price1, 'The second price was not correct' assert price_set[2].value == price2, 'The third price was not correct' # ****************************************************************************************************************** print(" Case 4. Modeled prices using the market's price model." ) # *********************************************** # The test setup is such that the local asset should use Methods 1 & 4 to find four marginal prices. now = datetime.now() test_asset_model = LocalAsset() test_asset_model.schedulingHorizon = timedelta( hours=3.5) # Should cause asset to use prior market test_market = Market() test_interval0 = TimeInterval(now, timedelta(hours=1), test_market, now, now) price0 = 3.14159 test_price0 = IntervalValue(None, test_interval0, test_market, 'test', price0) test_market.timeIntervals = [test_interval0] test_market.marginalPrices = [test_price0] test_market.marketSeriesName = "Test Market" test_market.marketClearingTime = now test_market.priorMarketInSeries = None test_market.priorRefinedMarket = None avg_price = 30 std_price = 0.1 test_market.priceModel = [avg_price, std_price ] * 24 # Critical to this test test_mtn = TransactiveNode() test_mtn.markets = [test_market] test_mtn.localAssets = [test_asset_model] assert len(test_market.marginalPrices ) == 1, 'The market was supposed to have a marginal price' assert len(test_market.priceModel ) == 48, 'A price model must exist for all 2 * 24 hours' try: price_set = test_asset_model.get_extended_prices(test_market) print(" The case ran without errors.") except RuntimeWarning as result: print(" The case encountered errors.", result) price_set = [] # 200207DJH: The assignment of modeled prices now completes the prior successful method to the top of the next hour. # Thereafter, modeled prices are assigned through the top of the hour that exceeds the scheduling # horizon. Therefore, there is some variability in the count of assert len(price_set) == 4 or len(price_set) == 5, \ ('An unexpected number', len(price_set), ' of prices was found') assert price_set[0].value == price0, 'The first price was not correct' assert all([price_set[x].value == avg_price for x in range(1, len(price_set))]), \ 'Prices 1 - 4 were not correct' # ****************************************************************************************************************** print(" Case 5. The market's default price value." ) # ************************************************************ test_asset_model = LocalAsset() test_asset_model.schedulingHorizon = timedelta(hours=4.5) test_market = Market() default_price = 1.2345 test_market.defaultPrice = default_price test_market.priceModel = None test_market.intervalsToClear = 24 test_market.intervalDuration = timedelta(hours=1) test_market.activationLeadTime = timedelta(days=2) test_market.priorRefinedMarket = None test_mtn = TransactiveNode() test_mtn.markets = [test_market] assert type(test_market.defaultPrice ) == float, 'A valid default price must be defined' try: price_set = test_asset_model.get_extended_prices(test_market) print(" The case ran without errors.") except RuntimeWarning: print(" The case encountered errors.") assert len(price_set) == 5, 'The number of horizon prices was unexpected' assert all([price_set[x].value == default_price for x in range(1, len(price_set))]), \ 'The default prices were not used' print("Method test_get_extended_prices() ran to completion.\n")