def testSimpleStorageWithStorageEfficiency(self): """Free Storage should backup Solar.""" solar = GridSource(SOLAR, 2.0e6, 0) wind = GridSource(WIND, 5.0e6, 0) ng = GridSource(NG, 1.0e10, 0) se = math.pow(0.5, 1.0 / 3) storage = GridRecStorage(STORAGE, 0, storage_efficiency=se) lp = self.lp lp.add_nondispatchable_sources(solar, wind) lp.add_dispatchable_sources(ng) lp.add_storage(storage) self.assertTrue(lp.solve()) npt.assert_almost_equal(solar.get_solution_values(), np.array([4.5, 0, 0, 2.25])) npt.assert_almost_equal(wind.get_solution_values(), np.zeros(4)) npt.assert_almost_equal(ng.get_solution_values(), np.zeros(4)) npt.assert_almost_equal(storage.get_solution_values(), np.array([0, 1.5, 1.5 * se, 1.5 * se * se])) npt.assert_almost_equal(storage.get_source_solution_values(), np.array([-1.5, 0, 0, 0.75]))
def testSimpleStorageWithSourceLimit(self): """Tests Solar, Wind, Storage. Solar limited so wind makes up the rest.""" solar = GridSource(SOLAR, 2.0e6, 0, max_energy=3) wind = GridSource(WIND, 5.0e6, 0) ng = GridSource(NG, 1.0e10, 0) storage = GridRecStorage(STORAGE, 0) lp = self.lp lp.add_nondispatchable_sources(solar, wind) lp.add_dispatchable_sources(ng) lp.add_storage(storage) self.assertTrue(lp.solve()) npt.assert_almost_equal(solar.get_solution_values(), np.array([2.0, 0, 0, 1.0])) npt.assert_almost_equal(wind.get_solution_values(), np.array([3.0, 0, 0, 0.0])) npt.assert_almost_equal(ng.get_solution_values(), np.zeros(4)) npt.assert_almost_equal(storage.get_solution_values(), np.array([0, 2.0, 2.0, 2.0])) npt.assert_almost_equal(storage.get_source_solution_values(), np.array([-2.0, 0, 0, 2.0]))
def testSimpleStorageWithStorageLimit(self): """Free Storage should backup Solar.""" solar = GridSource(SOLAR, 2.0e6, 0) wind = GridSource(WIND, 5.0e6, 0) ng = GridSource(NG, 1.0e10, 0) storage = GridRecStorage(STORAGE, 0, max_storage=0.5) lp = self.lp lp.add_nondispatchable_sources(solar, wind) lp.add_dispatchable_sources(ng) lp.add_storage(storage) self.assertTrue(lp.solve()) npt.assert_almost_equal(solar.get_solution_values(), np.array([5.0, 0, 0, 2.5])) npt.assert_almost_equal(wind.get_solution_values(), np.zeros(4)) npt.assert_almost_equal(ng.get_solution_values(), np.zeros(4)) npt.assert_almost_equal(storage.get_solution_values(), np.array([0, 0.5, 0.5, 0.5])) npt.assert_almost_equal(storage.get_source_solution_values(), np.array([-0.5, 0, 0, 0.5]))
def testRandomSawToothRecStorage(self): lp = self.lp solar = self.solar lp.add_nondispatchable_sources(solar) storage = GridRecStorage(STORAGE, 0) lp.add_storage(storage) for storage_efficiency in np.linspace(0.1, 1.0, 4): storage.storage_efficiency = storage_efficiency self.assertTrue(lp.solve()) # build up storage profile demand_profile = self.demand_profile golden_storage_profile = [] last_storage_value = 0.0 for d in reversed(demand_profile): next_storage_value = (last_storage_value + d) / storage_efficiency golden_storage_profile.append(next_storage_value) last_storage_value = next_storage_value golden_storage_profile.reverse() # First generation comes from solar, so set golden_storage[0] = 0. golden_storage_profile[0] = 0 golden_solar_profile = self.impulse * golden_storage_profile[1] npt.assert_allclose(solar.get_solution_values(), golden_solar_profile) npt.assert_allclose(storage.get_solution_values(), golden_storage_profile, atol=1e-7)
def testRpsStorage(self): """Storage credits rps if timeslice exceeds demand.""" lp = self.lp wind = GridSource(WIND, 2.0e6, 0, is_rps_source=True) ng = GridSource(NG, 0, 1.0e6) storage = GridRecStorage(STORAGE, 1, 1, 1) lp.add_nondispatchable_sources(wind) lp.add_dispatchable_sources(ng) lp.add_storage(storage) demand_at_0 = self.profiles[DEMAND][0] demand_at_1 = self.profiles[DEMAND][1] total = sum(self.profiles[DEMAND]) for rps in range(0, 120, 10): lp.rps_percent = rps rps_total = total * rps / 100.0 # Wind is only on for one time-slice. wind_at_0 = rps_total wind_nameplate = wind_at_0 golden_wind = wind_nameplate * self.profiles[WIND] # Either we charge at 0, or ng fills remaining. if wind_at_0 >= demand_at_0: storage_at_0 = wind_at_0 - demand_at_0 ng_at_0 = 0 else: storage_at_0 = 0 ng_at_0 = demand_at_0 - wind_at_0 # Discharge everything at 1. storage_discharge_power = storage_at_0 ng_at_1 = demand_at_1 - storage_discharge_power if lp.solve(): self.assertTrue(rps <= 100) npt.assert_almost_equal(wind.get_solution_values(), golden_wind) npt.assert_almost_equal(ng.get_solution_values(), np.array([ng_at_0, ng_at_1])) # Storage at t=1 shows what charged at t=0. npt.assert_almost_equal(storage.get_solution_values(), np.array([0.0, storage_at_0])) else: # Verify no convergence because we asked for a ridiculous rps number. self.assertTrue(rps > 100)
def testStorageNameplateCost(self): """Keep increasing storage costs until ng finally wins out.""" wind = GridSource(WIND, 1.0e6, 0) storage = GridRecStorage(STORAGE, 0) ng = GridSource(NG, 4.6e6, 0) lp = self.lp lp.add_nondispatchable_sources(wind) lp.add_dispatchable_sources(ng) lp.add_storage(storage) self.assertTrue(lp.solve()) npt.assert_almost_equal(wind.get_solution_values(), np.array([2.0, 0.0])) npt.assert_almost_equal(ng.get_solution_values(), np.zeros(2)) # Change costs. Total wind + storage cost is now (2 + 1)E6. # Still less than ng costs. storage.charge_nameplate_cost = 1.0e6 self.assertTrue(lp.solve()) npt.assert_almost_equal(wind.get_solution_values(), np.array([2.0, 0.0])) npt.assert_almost_equal(ng.get_solution_values(), np.zeros(2)) # Change Costs. Total wind + storage cost is now (2 + 1 + 1)E6. # Still less than ng costs. storage.storage_nameplate_cost = 1.0e6 self.assertTrue(lp.solve()) npt.assert_almost_equal(wind.get_solution_values(), np.array([2.0, 0.0])) npt.assert_almost_equal(ng.get_solution_values(), np.zeros(2)) # Change costs. Total wind + storage cost is now # (2 + 1 + 1 + 1)E6. Now more than ng costs. storage.discharge_nameplate_cost = 1.0e6 self.assertTrue(lp.solve()) npt.assert_almost_equal(wind.get_solution_values(), np.zeros(2)) npt.assert_almost_equal(ng.get_solution_values(), np.array([1.0, 1.0]))
def testCircularRecStorageFirstHourSource(self): """Verify that storage from first hour affects last hour.""" wind = GridSource(WIND, 2.0e6, 0) storage = GridRecStorage(STORAGE, 0) lp = self.lp lp.add_nondispatchable_sources(wind) lp.add_storage(storage) self.assertTrue(lp.solve()) npt.assert_almost_equal(wind.get_solution_values(), np.array([2.0, 0.0])) npt.assert_almost_equal(storage.get_solution_values(), np.array([0.0, 1.0])) npt.assert_almost_equal(storage.get_source_solution_values(), np.array([-1.0, 1.0]))
def testCircularRecStorageLastHourSource(self): """Verify that storage from last hour affects first hour.""" solar = GridSource(SOLAR, 2.0e6, 0) storage = GridRecStorage(STORAGE, 0) lp = self.lp lp.add_nondispatchable_sources(solar) lp.add_storage(storage) self.assertTrue(lp.solve()) npt.assert_almost_equal(solar.get_solution_values(), np.array([0.0, 2.0])) npt.assert_almost_equal(storage.get_solution_values(), np.array([1.0, 0.0])) npt.assert_almost_equal(storage.get_source_solution_values(), np.array([1.0, -1.0]))
def testFreeRecStorageMeansCheapestSource(self): """Verify that free storage selects the cheapest energy supply.""" solar = GridSource(SOLAR, 2.0e6, 0) wind = GridSource(WIND, 2.2e6, 0) storage = GridRecStorage(STORAGE, 0) lp = self.lp lp.add_nondispatchable_sources(solar, wind) lp.add_storage(storage) self.assertTrue(lp.solve()) npt.assert_almost_equal(wind.get_solution_values(), np.zeros(2)) npt.assert_almost_equal(solar.get_solution_values(), np.array([0.0, 2.0])) npt.assert_almost_equal(storage.get_solution_values(), np.array([1.0, 0.0])) npt.assert_almost_equal(storage.get_source_solution_values(), np.array([1.0, -1.0]))
def testCircularRecAccounting(self): """Verify that RECs get stored and accounted for properly.""" lp = self.lp solar = GridSource(SOLAR, 2e6, 2e6, is_rps_source=True) wind = GridSource(WIND, 1e6, 1e6) storage = GridRecStorage(STORAGE, 1, 1, 1, discharge_efficiency=0.5) lp.add_nondispatchable_sources(solar, wind) lp.add_storage(storage) for rps in np.arange(0, 110, 10): lp.rps_percent = rps self.assertTrue(lp.solve()) npt.assert_almost_equal(solar.get_solution_values(), self.profiles[SOLAR].values * rps / storage.discharge_efficiency) npt.assert_almost_equal(wind.get_solution_values(), self.profiles[WIND] * (100 - rps) / storage.discharge_efficiency) rps_credit = np.array([v.solution_value() for v in lp.rps_credit_variables[0]]) self.assertAlmostEqual(sum(rps_credit), rps) rec_storage = storage.rec_storage no_rec_storage = storage.no_rec_storage npt.assert_almost_equal(rps_credit, rec_storage.source.get_solution_values() * storage.discharge_efficiency) npt.assert_almost_equal(self.profiles[DEMAND] - rps_credit, no_rec_storage.source.get_solution_values() * storage.discharge_efficiency)