Пример #1
0
  def testSimpleStorage(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 = GridStorage(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([4.0, 0, 0, 2.0]))

    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, 1, 1]))

    npt.assert_almost_equal(storage.source.get_solution_values(),
                            np.array([0, 0, 0, 1]))

    npt.assert_almost_equal(storage.sink.get_solution_values(),
                            np.array([1, 0, 0, 0]))
Пример #2
0
  def testCheaperDispatchableOnly(self):
    """Two Dispatchable Sources. Cheaper one should fill demand."""

    lp = self.lp
    ng1 = self.ng
    ng2 = GridSource(NG2, 2e6, 2e6)
    lp.add_dispatchable_sources(ng1, ng2)
    self.assertTrue(lp.solve())

    npt.assert_almost_equal(ng1.get_solution_values(), self.demand_profile)
    npt.assert_almost_equal(ng2.get_solution_values(), np.zeros(4))

    self.assertAlmostEqual(ng1.get_nameplate_solution_value(),
                           max(self.demand_profile))

    self.assertAlmostEqual(ng2.get_nameplate_solution_value(), 0.0)
Пример #3
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]))
Пример #4
0
  def testCostConstraintCreation(self):
    """Verify cost constraint gets created upon initialization."""
    lp = self.lp

    ng = GridSource(NG, 1e6, 1e6)
    lp.add_dispatchable_sources(ng)
    self.assertIsNone(lp.minimize_costs_objective)
    lp._initialize_solver()
    self.assertIsNotNone(lp.minimize_costs_objective)
Пример #5
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]))
Пример #6
0
  def testPostProcessing(self):
    lp = self.lp
    wind = GridSource(WIND, 2.0e6, 0, is_rps_source=True)
    ng = GridSource(NG, 1.0e6, 1.0e6)
    storage = GridStorage(STORAGE, 1, 1, 1)

    lp.add_nondispatchable_sources(wind)
    lp.add_dispatchable_sources(ng)
    lp.add_storage(storage)

    lp.rps_percent = 20
    self.assertTrue(lp.solve())

    wind_solution = MockPostProcessingGridSourceSolver(wind)
    storage_sink_solution = MockPostProcessingGridSourceSolver(storage.sink)

    wind_solution.solution_values -= 0.1

    with self.assertRaises(DemandNotSatisfiedError):
      lp._post_process()

    # After reset it shouldn't error out.
    wind_solution.reset()
    try:
      lp._post_process()
    except RuntimeError:
      self.fail()

    storage_sink_solution.solution_values += 20

    with self.assertRaises(DemandNotSatisfiedError):
      lp._post_process()

    # After reset it shouldn't error out.
    storage_sink_solution.reset()
    try:
      lp._post_process()
    except RuntimeError:
      self.fail()

    lp.rps_demand *= 100
    with self.assertRaises(RpsPercentNotMetError):
      lp._post_process()
Пример #7
0
  def testCombinedSolarWindNgRps(self):
    """Sweep RPS."""

    solar = GridSource(SOLAR, 2.0e6, 0, is_rps_source=True)
    wind = GridSource(WIND, 4.0e6, 0, is_rps_source=True)
    ng = GridSource(NG, 0, 1.0e6)

    lp = self.lp
    lp.add_dispatchable_sources(ng)
    lp.add_nondispatchable_sources(solar, wind)

    # As rps is swept, it will fill RPS requirement with cheaper solar
    # first then wind.  NG is cheapest but not in RPS so it will fill
    # in the blanks.

    # Wind is really expensive so check and make sure the LP doesn't
    # cheat by requesting more cheaper solar than it can actually use
    # in order to satisfy rps.  Instead, after it's maxed out on
    # solar, it has to use the expensive wind.

    for rps in np.arange(0, 1.2, 0.1):
      lp.rps_percent = rps * 100.0
      if lp.solve():
        self.assertTrue(rps <= 1.0)

        solar_nameplate = rps * 2 if rps <= 0.5 else 1.0
        wind_nameplate = (rps - 0.5) * 2 if rps > 0.5 else 0.0

        solar_golden_profile = self.profiles[SOLAR] * solar_nameplate
        wind_golden_profile = self.profiles[WIND] * wind_nameplate

        ng_golden_profile = (self.profiles[DEMAND] -
                             solar_golden_profile -
                             wind_golden_profile)

        npt.assert_almost_equal(solar.get_solution_values(),
                                solar_golden_profile)

        npt.assert_almost_equal(wind.get_solution_values(),
                                wind_golden_profile)

        npt.assert_almost_equal(ng.get_solution_values(),
                                ng_golden_profile)

      else:
        # Ensure lp doesn't solve if rps > 1.0
        self.assertTrue(rps > 1.0)
Пример #8
0
  def setUp(self):
    self.demand_profile = np.array([3.0, 0.0, 0.0, 3.0])

    rng = pd.date_range('1/1/2011', periods=len(self.demand_profile), freq='H')

    df = pd.DataFrame.from_dict(
        {DEMAND: self.demand_profile,
         SOLAR: np.array([2.0, 0.0, 0.0, 1.0]),
         WIND: np.array([1.0, 0.0, 0.0, 0.0]),
         TIME: rng}
    )

    self.profiles = df.set_index(TIME,
                                 verify_integrity=True)

    self.lp = LinearProgramContainer(self.profiles)
    self.lp.add_demands(GridDemand(DEMAND))

    self.solar = GridSource(SOLAR, 1e6, 1e6)
    self.ng = GridSource(NG, 1e6, 1e6)
Пример #9
0
  def testVariableCreation(self):
    """Check GridSource creates nameplate / timeslice variables."""
    lp = self.lp
    ng = GridSource(NG, 1e6, 1e6)
    self.assertIsNone(ng.timeslice_variables)
    self.assertIsNone(ng.nameplate_variable)

    lp.add_dispatchable_sources(ng)

    lp._initialize_solver()
    self.assertIsNotNone(ng.nameplate_variable)
    self.assertEqual(len(ng.timeslice_variables), lp.number_of_timeslices)
Пример #10
0
  def testFreeStorageMeansCheapestSource(self):
    """Verify that free storage selects the cheapest energy supply."""
    solar = GridSource(SOLAR, 2.0e6, 0)
    wind = GridSource(WIND, 2.2e6, 0)
    storage = GridStorage(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.source.get_solution_values(),
                            np.array([1.0, 0.0]))

    npt.assert_almost_equal(storage.sink.get_solution_values(),
                            np.array([0.0, 1.0]))
Пример #11
0
  def testSolutionValuesCalledBeforeSolve(self):
    lp = LinearProgramContainer(self.dummy_profile)
    ng = GridSource(NG, 1e6, 1e6)
    lp.add_dispatchable_sources(ng)
    with self.assertRaises(RuntimeError):
      ng.get_solution_values()

    with self.assertRaises(RuntimeError):
      ng.get_nameplate_solution_value()
Пример #12
0
  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)
Пример #13
0
  def testMaxPowerCheaperDispatchable(self):
    """Two Dispatchable Sources. Cheaper one fills up to max_power."""

    lp = self.lp
    max_power = 1
    ng1 = GridSource(NG, 1e6, 1e6, max_power=max_power)
    ng2 = GridSource(NG2, 2e6, 2e6)
    lp.add_dispatchable_sources(ng1, ng2)
    self.assertTrue(lp.solve())

    max_power_profile = np.array([max_power, 0, 0, max_power])
    remaining = self.demand_profile - max_power_profile
    npt.assert_almost_equal(ng1.get_solution_values(), max_power_profile)
    npt.assert_almost_equal(ng2.get_solution_values(), remaining)

    self.assertAlmostEqual(ng1.get_nameplate_solution_value(),
                           max(max_power_profile))

    self.assertAlmostEqual(ng2.get_nameplate_solution_value(),
                           max(remaining))
Пример #14
0
  def testMaxEnergyCheaperDispatchable(self):
    """Two Dispatchable Sources. Cheaper one fills up to max_energy."""

    lp = self.lp
    max_energy = 1.0
    ng1 = GridSource(NG, 1e6, 1e6, max_energy=max_energy)
    ng2 = GridSource(NG2, 2e6, 2e6)
    lp.add_dispatchable_sources(ng1, ng2)
    self.assertTrue(lp.solve())

    demand_profiles = self.demand_profile
    demand_energy = sum(demand_profiles)
    max_energy_profile = (max_energy / demand_energy) * demand_profiles
    remaining = demand_profiles - max_energy_profile

    npt.assert_almost_equal(ng1.get_solution_values(), max_energy_profile)
    npt.assert_almost_equal(ng2.get_solution_values(), remaining)

    self.assertAlmostEqual(ng1.get_nameplate_solution_value(),
                           max(max_energy_profile))

    self.assertAlmostEqual(ng2.get_nameplate_solution_value(),
                           max(remaining))
Пример #15
0
  def setUp(self):
    self.demand_profile = np.array(
        [0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0])

    impulse_profile = np.zeros(len(self.demand_profile))
    impulse_profile[0] = 1.0
    self.impulse = impulse_profile

    rng = pd.date_range('1/1/2011', periods=len(self.demand_profile), freq='H')

    df = pd.DataFrame.from_dict(
        {DEMAND: self.demand_profile,
         SOLAR: impulse_profile,
         TIME: rng}
    )

    self.profiles = df.set_index(TIME,
                                 verify_integrity=True)

    self.lp = LinearProgramContainer(self.profiles)
    self.lp.add_demands(GridDemand(DEMAND))

    self.solar = GridSource(SOLAR, 1e6, 1e6)
Пример #16
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)
Пример #17
0
  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]))
Пример #18
0
  def testAddNonDispatchableSourceWithoutProfile(self):
    """Ensure NonDispatchable Source without profile gets error."""

    with self.assertRaises(KeyError):
      lp = LinearProgramContainer(self.dummy_profile)
      lp.add_nondispatchable_sources(GridSource(NG, 1e6, 1e6))
Пример #19
0
  def testAddDispatchableSourceWithProfile(self):
    """Ensure Dispatchable Source with profile gets error."""

    with self.assertRaises(KeyError):
      lp = LinearProgramContainer(pd.DataFrame({NG: np.ones(4)}))
      lp.add_dispatchable_sources(GridSource(NG, 1e6, 1e6))