def test_order_vertices(): try: from vertex import Vertex except (SystemError, ImportError): from code.vertex import Vertex p = [-100, 0, 100, 0] # power vector c = [0.4, 0.3, 0.3, 0.2] # marginal price vector uv = [] for i in range(len(p)): uv.append(Vertex(c[i], 0, p[i])) ov = order_vertices(uv) print (uv) print (ov)
def test_prod_cost_from_vertices(): from code.local_asset_model import LocalAsset from code.market import Market # TEST_PROD_COST_FROM_VERTICES - tests function prod_cost_from_vertices() print('Running test_prod_cost_from_vertices()') pf = 'pass' # Create a test object test_object = LocalAsset # Create a test market test_market = Market() # Create several active vertices av av = [Vertex(0.02, 5, 0), Vertex(0.02, 7, 100), Vertex(0.025, 9.25, 200)] # Create a time interval dt = datetime.now() at = dt # NOTE: Function Hours() corrects behavior of Matlab function hours(). dur = timedelta(hours=1) mkt = test_market mct = dt st = dt ti = TimeInterval(at, dur, mkt, mct, st) # Create and store the activeVertices, which are IntervalValues test_object.activeVertices = [IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[0]), IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[1]), IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[2])] # CASE: Various signed powers when there is more than one vertex test_powers = [-50, 0, 50, 150, 250] pc = [] for p in test_powers: pc.append(prod_cost_from_vertices(test_object, ti, p)) # pc(1) = 0: value is always 0 for power < 0 # pc(2) = 5.0: assign cost from first vertex # pc(3) = 6.0: interpolate between vertices # pc(4) = 8.125: interpolate between vertices # pc(5) = 9.25: use last vertex cost if power > last vertex power # if ~all(pc == [0, 5.0, 6.0, 8.125, 9.25]) expected = [0, 5.0, 6.0, 8.125, 9.25] if not all([pc[i] == expected[i] for i in range(len(pc))]): pf = 'fail' raise Exception('- the production cost was incorrectly calculated') else: print('- the production cost was correctly calculated') # CASE: One vertex (inelastic case, a constant) test_object.activeVertices = [ IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[0])] # pc[i] = prod_cost_from_vertices(test_object, ti, test_powers[i]) pc = [] for p in test_powers: pc.append(prod_cost_from_vertices(test_object, ti, p)) expected = [0.0, 5.0, 5.0, 5.0, 5.0] # if ~all(pc == [0.0, 5.0, 5.0, 5.0, 5.0]) if not all([pc[i] == expected[i] for i in range(len(pc))]): pf = 'fail' raise Exception('- made an incorrect assignment when there is one vertex') else: print('- made a correct assignment when there is one vertex') # CASE: No active vertices (error case): test_object.activeVertices = [] # print('off', 'all') try: pc = prod_cost_from_vertices(test_object, ti, test_powers[4]) pf = 'fail' # print('on', 'all') raise Exception('- the function should have warned and continued when there were no active vertices') except: print('- the function returned gracefully when there were no active vertices') # print('on', 'all') # Success print('- the test function ran to completion') print('Result: #s\n\n', pf)
def test_production(): from code.local_asset_model import LocalAsset from code.market import Market print('Running test_production()') pf = 'pass' # Create a test object test_object = LocalAsset() # Create a test market test_market = Market() # Create several active vertices av av = [Vertex(0.0200, 5.00, 0.0), Vertex(0.0200, 7.00, 100.0), Vertex(0.0250, 9.25, 200.0)] # Create a time interval ti dt = datetime.now() at = dt # NOTE: Function Hours() corrects the behavior of Matlab hours(). dur = timedelta(hours=1) mkt = test_market mct = dt st = dt ti = TimeInterval(at, dur, mkt, mct, st) # Assign activeVertices, which are IntervalValues test_object.activeVertices = [ IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[0]), IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[1]), IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[2])] # CASE: Various marginal prices when there is more than one vertex test_prices = [-0.010, 0.000, 0.020, 0.0225, 0.030] p = [0] * len(test_prices) # zeros(1, length(test_prices)) for i in range(len(test_prices)): # for i = 1:length(test_prices) p[i] = production(test_object, test_prices[i], ti) print('- the function ran without errors') # p(1) = 0: below first vertex # p(2) = 0: below first vertex # p(3) = 100: at first vertex, which has identical marginal price as second # p(4) = 150: interpolate between vertices # p(5) = 200: exceeds last vertex # if ~all(abs(p - [0, 0, 100, 150, 200]) < 0.001): expected = [0, 0, 100, 150, 200] if not all([p[i] - expected[i] < 0.001 for i in range(len(p))]): pf = 'fail' raise Exception('- the production cost was incorrectly calculated') else: print('- the production cost was correctly calculated') # CASE: One vertex (inelastic case, a constant) test_object.activeVertices = [IntervalValue(test_object, ti, test_market, MeasurementType.ActiveVertex, av[2])] for i in range(5): p[i] = production(test_object, test_prices[i], ti) # if ~all(p == 200 * ones(1, length(p))): if not all(x == 200 for x in p): pf = 'fail' raise Exception('the vertex power should be assigned when there is one vertex') else: print('- the correct power was assigned when there is one vertex') # CASE: No active vertices (error case): test_object.activeVertices = [] try: p = production(test_object, test_prices[4], ti) pf = 'fail' raise Exception('- an error should have occurred with no active vertices') except: print('- with no vertices, system returned with warnings, as expected') # Success print('- the test function ran to completion') print('Result: #s\n\n', pf)
city_market.meterPoints.append(meter) # Add weather forecast service config = {'weather_file': city_config['weather_forecast']['weather_file']} weather_service = TemperatureForecastModel(config) city_market.informationServiceModels.append(weather_service) # Add uncontrollable model 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 average PNNL load [kW] 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)] inelastive_load_model.object = inelastive_load inelastive_load.model = inelastive_load_model city_market.localAssets.extend([inelastive_load]) # 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(
def test_update_costs(): print('Running AbstractModel.test_update_costs()') test_mtn = TransactiveNode() # Create a test market test_mkt test_mkt = Market() # Create a sample time interval ti dt = datetime.now() at = dt # NOTE: Function Hours() corrects behavior of Matlab hours(). dur = timedelta(hours=1) mkt = test_mkt mct = dt st = datetime.combine(date.today(), time()) + timedelta(hours=20) ti = TimeInterval(at, dur, mkt, mct, st) # Save the time interval test_mkt.timeIntervals = [ti] # Assign a marginal price in the time interval test_mkt.check_marginal_prices(test_mtn) # Create a Neighbor test object and give it a default maximum power value # test_obj = Neighbor() # test_obj.maximumPower = 100 # Create a corresponding Neighbor. test_mdl = Neighbor() # Make sure that the model and object cross-reference one another # test_obj.model = test_mdl # test_mdl.object = test_obj test_mdl.scheduledPowers = [ IntervalValue(test_mdl, ti, test_mkt, MeasurementType.ScheduledPower, 100) ] test_mdl.activeVertices = [ IntervalValue(test_mdl, ti, test_mkt, MeasurementType.ActiveVertex, Vertex(0.05, 0, 100)) ] # Run a test with a Neighbor object print('- running test with a Neighbor:') try: test_mdl.update_costs(test_mkt) print(' - the method encountered no errors') except RuntimeWarning: print(' - ERRORS ENCOUNTERED') assert len(test_mdl.productionCosts ) == 1, ' - the method did not store a production cost' assert len( test_mdl.dualCosts) == 1, ' - the method did not store a dual cost' assert test_mdl.totalProductionCost == sum([x.value for x in test_mdl.productionCosts]), \ ' - the method did not store a total production cost' assert test_mdl.totalDualCost == sum([x.value for x in test_mdl.dualCosts]), \ ' - the method did not store a total dual cost' # Run a test again with a LocalAsset. # test_obj = LocalAsset() test_mdl = LocalAsset() # test_obj.model = test_mdl # test_mdl.object = test_obj test_mdl.maximumPower = 100 test_mdl.scheduledPowers = [ IntervalValue(test_mdl, ti, test_mkt, MeasurementType.ScheduledPower, 100) ] test_mdl.activeVertices = [ IntervalValue(test_mdl, ti, test_mkt, MeasurementType.ActiveVertex, Vertex(0.05, 0, 100)) ] print('- running test with a LocalAsset:') try: test_mdl.update_costs(test_mkt) print(' - the method encountered no errors') except RuntimeWarning: print(' - ERRORS ENCOUNTERED') assert len(test_mdl.productionCosts ) == 1, ' - the method did not store a production cost' assert len( test_mdl.dualCosts) == 1, ' - the method did not store a dual cost' assert test_mdl.totalProductionCost == sum([x.value for x in test_mdl.productionCosts]), \ ' - the method did not store a total production cost' assert test_mdl.totalDualCost == sum([x.value for x in test_mdl.dualCosts]), \ ' - the method did not store a total dual cost' # Success print('test_update_costs() ran to completion.\n')
def test_calculate_reserve_margin(): # TEST_LAM_CALCULATE_RESERVE_MARGIN() - a LocalAsset ("LAM") class # method NOTE: Reserve margins are introduced but not fully integrated into # code in early template versions. # CASES: # 1. uses hard maximum if no active vertices exist # 2. vertices exist # 2.1 uses maximum vertex power if it is less than hard power constraint # 2.2 uses hard constraint if it is less than maximum vertex power # 2.3 upper flex power is greater than scheduled power assigns correct # positive reserve margin # 2.4 upperflex power less than scheduled power assigns zero value to # reserve margin. print('Running LocalAsset.test_calculate_reserve_margin()') # Establish test market test_mkt = Market() # Establish test market with an active time interval # Note: modified 1/29/18 due to new TimeInterval constructor dt = datetime.now() at = dt # NOTE: def Hours() corrects behavior of Matlab hours(). dur = timedelta(hours=1) mkt = test_mkt mct = dt # st = datetime(date) st = datetime.combine(date.today(), time()) ti = TimeInterval(at, dur, mkt, mct, st) # Store time interval test_mkt.timeIntervals = [ti] # Establish test object that is a LocalAsset. test_model = LocalAsset() test_model.scheduledPowers = [ IntervalValue(test_model, ti, test_mkt, MeasurementType.ScheduledPower, 0.0) ] test_model.maximumPower = 100 # Run the first test case. print(" Case 1:") try: test_model.calculate_reserve_margin(test_mkt) print(' The test ran without errors') except RuntimeWarning as cause: print(' The test encountered errors', cause) print(test_model.reserveMargins[0].value) assert len(test_model.reserveMargins ) == 1, 'An unexpected number of results were stored' assert test_model.reserveMargins[0].value == test_model.maximumPower, \ 'The method did not use the available maximum power' # create some vertices and store them iv = [ IntervalValue(test_model, ti, test_mkt, MeasurementType.Vertex, Vertex(0, 0, -10)), IntervalValue(test_model, ti, test_mkt, MeasurementType.Vertex, Vertex(0, 0, 10)) ] test_model.activeVertices = iv print(" Case 2: test with maximum power greater than maximum vertex") test_model.maximumPower = 100 try: test_model.calculate_reserve_margin(test_mkt) print(' The test ran without errors') except RuntimeWarning as cause: print(' The test encountered errors', cause) assert test_model.reserveMargins[ 0].value == 10, 'The method should have used vertex for comparison' print(" Case 3: test with maximum power less than maximum vertex") test_model.maximumPower = 5 try: test_model.calculate_reserve_margin(test_mkt) print(' The test ran without errors') except RuntimeWarning as cause: print(' The test encountered errors', cause) assert test_model.reserveMargins[ 0].value == 5, 'The method should have used maximum power for comparison' print(" Case 4: test with scheduled power greater than maximum vertex") test_model.scheduledPowers[0].value = 20 test_model.maximumPower = 500 try: test_model.calculate_reserve_margin(test_mkt) print(' The test ran without errors') except RuntimeWarning as cause: print(' The test encountered errors', cause) print(test_model.reserveMargins[0].value) assert test_model.reserveMargins[ 0].value == 0, 'The method should have assigned zero for a neg. result' # Success. print('Method test_calculate_reserve_margin() ran to completion.\n')
def test_update_production_costs(): # TEST_UPDATE_PRODUCTION_COSTS() - test method update_production_costs() that calculates production costs from # active vertices and scheduled powers. # NOTE: This test is virtually identical to the Neighbor test of the same name. print('Running LocalAsset.test_update_production_costs()') # Create a test Market. test_market = Market() # Create and store a TimeInterval. dt = datetime.now( ) # datetime that may be used for most datetime arguments time_interval = TimeInterval(dt, timedelta(hours=1), test_market, dt, dt) test_market.timeIntervals = [time_interval] # Create a test LocalAsset. test_model = LocalAsset() # Create and store a scheduled power IntervalValue in the active time interval. test_model.scheduledPowers = [ IntervalValue(test_model, time_interval, test_market, MeasurementType.ScheduledPower, 50) ] # Create and store some active vertices IntervalValues in the active time interval. vertices = [Vertex(0.1, 1000, 0), Vertex(0.2, 1015, 100)] interval_values = [ IntervalValue(test_model, time_interval, test_market, MeasurementType.ActiveVertex, vertices[0]), IntervalValue(test_model, time_interval, test_market, MeasurementType.ActiveVertex, vertices[1]) ] test_model.activeVertices = interval_values # TEST 1 print('- Test 1: First calculation of a production cost') try: test_model.update_production_costs(test_market) print(' - the method ran without errors') except RuntimeWarning as cause: print(' - the method encountered errors', cause) assert len(test_model.productionCosts ) == 1, 'The wrong number of production costs was created' production_cost = test_model.productionCosts[0].value assert production_cost == 1007.5, 'An unexpected production cost value was found' # TEST 2 print('- Test 2: Reassignment of an existing production cost') # Configure the test by modifying the scheduled power value. test_model.scheduledPowers[0].value = 150 try: test_model.update_production_costs(test_market) print(' - the method ran without errors') except RuntimeWarning as cause: print(' - the method encountered errors', cause) assert len(test_model.productionCosts ) == 1, 'The wrong number of productions was created' production_cost = test_model.productionCosts[0].value assert production_cost == 1015, 'An unexpected dual cost value was found' # Success. print('Method test_update_production_costs() ran to completion.\n')