Ejemplo n.º 1
0
def test_tower_with_dispatch_model(site):
    """Testing pySSC tower model using HOPP built-in dispatch model"""
    expected_energy = 3842225.688

    interconnection_size_kw = 50000
    technologies = {
        'tower': {
            'cycle_capacity_kw': 50 * 1000,
            'solar_multiple': 2.0,
            'tes_hours': 6.0,
            'optimize_field_before_sim': False
        }
    }

    system = HybridSimulation(technologies,
                              site,
                              interconnect_kw=interconnection_size_kw,
                              dispatch_options={
                                  'is_test_start_year': True,
                                  'is_test_end_year': True
                              })

    system.tower.value('helio_width', 10.0)
    system.tower.value('helio_height', 10.0)

    system.tower.value('h_tower', 117.7)
    system.tower.value('rec_height', 11.3)
    system.tower.value('D_rec', 11.12)

    system.ppa_price = (0.12, )
    system.simulate()

    assert system.tower.annual_energy_kwh == pytest.approx(
        expected_energy, 1e-2)

    # Check dispatch targets
    disp_outputs = system.tower.outputs.dispatch
    ssc_outputs = system.tower.outputs.ssc_time_series
    for i in range(len(ssc_outputs['gen'])):
        # cycle start-up allowed
        target = 1 if (disp_outputs['is_cycle_generating'][i] +
                       disp_outputs['is_cycle_starting'][i]) > 0.01 else 0
        assert target == pytest.approx(ssc_outputs['is_pc_su_allowed'][i],
                                       1e-5)
        # receiver start-up allowed
        target = 1 if (disp_outputs['is_field_generating'][i] +
                       disp_outputs['is_field_starting'][i]) > 0.01 else 0
        assert target == pytest.approx(ssc_outputs['is_rec_su_allowed'][i],
                                       1e-5)
        # cycle thermal power
        start_power = system.tower.dispatch.allowable_cycle_startup_power if disp_outputs[
            'is_cycle_starting'][i] else 0
        target = disp_outputs['cycle_thermal_power'][i] + start_power
        assert target == pytest.approx(ssc_outputs['q_dot_pc_target_on'][i],
                                       1e-3)
        # thermal energy storage state-of-charge
        if i % system.dispatch_builder.options.n_roll_periods == 0:
            tes_estimate = disp_outputs['thermal_energy_storage'][i]
            tes_actual = ssc_outputs['e_ch_tes'][i]
            assert tes_estimate == pytest.approx(tes_actual, 0.01)
Ejemplo n.º 2
0
def test_trough_with_dispatch_model(site):
    """Testing pySSC tower model using HOPP built-in dispatch model"""
    expected_energy = 1873589.560

    interconnection_size_kw = 50000
    technologies = {
        'trough': {
            'cycle_capacity_kw': 50 * 1000,
            'solar_multiple': 2.0,
            'tes_hours': 6.0
        }
    }

    system = HybridSimulation(technologies,
                              site,
                              interconnect_kw=interconnection_size_kw,
                              dispatch_options={
                                  'is_test_start_year': True,
                                  'is_test_end_year': True
                              })
    system.ppa_price = (0.12, )
    system.simulate()

    assert system.trough.annual_energy_kwh == pytest.approx(
        expected_energy, 1e-2)
Ejemplo n.º 3
0
def test_hybrid_dispatch_financials(site):
    wind_solar_battery = {key: technologies[key] for key in ('pv', 'wind', 'battery')}
    hybrid_plant = HybridSimulation(wind_solar_battery, site, interconnect_mw * 1000,
                                    dispatch_options={'grid_charging': True})
    hybrid_plant.ppa_price = (0.06,)
    hybrid_plant.simulate(1)

    assert sum(hybrid_plant.battery.Outputs.P) < 0.0
Ejemplo n.º 4
0
def test_hybrid_dispatch_one_cycle_heuristic(site):
    dispatch_options = {'battery_dispatch': 'one_cycle_heuristic',
                        'grid_charging': False}

    wind_solar_battery = {key: technologies[key] for key in ('pv', 'wind', 'battery')}
    hybrid_plant = HybridSimulation(wind_solar_battery, site, interconnect_mw * 1000,
                                    dispatch_options=dispatch_options)
    hybrid_plant.simulate(1)

    assert sum(hybrid_plant.battery.Outputs.P) < 0.0
Ejemplo n.º 5
0
def test_hybrid_tax_incentives(site):
    wind_pv_battery = {
        key: technologies[key]
        for key in ('pv', 'wind', 'battery')
    }
    hybrid_plant = HybridSimulation(
        wind_pv_battery,
        site,
        interconnect_kw=interconnection_size_kw,
        dispatch_options={'battery_dispatch': 'one_cycle_heuristic'})
    hybrid_plant.ppa_price = (0.03, )
    hybrid_plant.pv.dc_degradation = [0] * 25
    hybrid_plant.pv._financial_model.TaxCreditIncentives.itc_fed_percent = 0.0
    hybrid_plant.wind._financial_model.TaxCreditIncentives.ptc_fed_amount = (
        1, )
    hybrid_plant.pv._financial_model.TaxCreditIncentives.ptc_fed_amount = (2, )
    hybrid_plant.battery._financial_model.TaxCreditIncentives.ptc_fed_amount = (
        3, )
    hybrid_plant.wind._financial_model.TaxCreditIncentives.ptc_fed_escal = 0
    hybrid_plant.pv._financial_model.TaxCreditIncentives.ptc_fed_escal = 0
    hybrid_plant.battery._financial_model.TaxCreditIncentives.ptc_fed_escal = 0
    hybrid_plant.simulate()

    ptc_wind = hybrid_plant.wind._financial_model.value("cf_ptc_fed")[1]
    assert ptc_wind == approx(
        hybrid_plant.wind._financial_model.value("ptc_fed_amount")[0] *
        hybrid_plant.wind.annual_energy_kwh,
        rel=1e-3)

    ptc_pv = hybrid_plant.pv._financial_model.value("cf_ptc_fed")[1]
    assert ptc_pv == approx(
        hybrid_plant.pv._financial_model.value("ptc_fed_amount")[0] *
        hybrid_plant.pv.annual_energy_kwh,
        rel=1e-3)

    ptc_batt = hybrid_plant.battery._financial_model.value("cf_ptc_fed")[1]
    assert ptc_batt == approx(
        hybrid_plant.battery._financial_model.value("ptc_fed_amount")[0] *
        hybrid_plant.battery._financial_model.LCOS.
        batt_annual_discharge_energy[1],
        rel=1e-3)

    ptc_hybrid = hybrid_plant.grid._financial_model.value("cf_ptc_fed")[1]
    ptc_fed_amount = hybrid_plant.grid._financial_model.value(
        "ptc_fed_amount")[0]
    assert ptc_fed_amount == approx(1.229, rel=1e-2)
    assert ptc_hybrid == approx(
        ptc_fed_amount *
        hybrid_plant.grid._financial_model.Outputs.cf_energy_net[1],
        rel=1e-3)
Ejemplo n.º 6
0
def test_hybrid_wind_only(site):
    wind_only = {'wind': technologies['wind']}
    hybrid_plant = HybridSimulation(wind_only,
                                    site,
                                    interconnect_kw=interconnection_size_kw)
    hybrid_plant.layout.plot()
    hybrid_plant.ppa_price = (0.01, )
    hybrid_plant.simulate(25)
    aeps = hybrid_plant.annual_energies
    npvs = hybrid_plant.net_present_values

    assert aeps.wind == approx(33615479, 1e3)
    assert aeps.hybrid == approx(33615479, 1e3)

    assert npvs.wind == approx(-13692784, 1e3)
    assert npvs.hybrid == approx(-13692784, 1e3)
Ejemplo n.º 7
0
def test_pv_wind_battery_hybrid_dispatch(site):
    expected_objective = 39460.698

    wind_solar_battery = {key: technologies[key] for key in ('pv', 'wind', 'battery')}
    hybrid_plant = HybridSimulation(wind_solar_battery, site, interconnect_mw * 1000,
                                    dispatch_options={'grid_charging': False,
                                                      'include_lifecycle_count': False})
    hybrid_plant.grid.value("federal_tax_rate", (0., ))
    hybrid_plant.grid.value("state_tax_rate", (0., ))
    hybrid_plant.ppa_price = (0.06, )
    hybrid_plant.pv.dc_degradation = [0.5] * 1

    hybrid_plant.pv.simulate(1)
    hybrid_plant.wind.simulate(1)

    hybrid_plant.dispatch_builder.dispatch.initialize_parameters()
    hybrid_plant.dispatch_builder.dispatch.update_time_series_parameters(0)
    hybrid_plant.battery.dispatch.initial_SOC = hybrid_plant.battery.dispatch.minimum_soc   # Set to min SOC

    results = HybridDispatchBuilderSolver.glpk_solve_call(hybrid_plant.dispatch_builder.pyomo_model)

    assert results.solver.termination_condition == TerminationCondition.optimal

    gross_profit_objective = pyomo.value(hybrid_plant.dispatch_builder.dispatch.objective_value)
    assert gross_profit_objective == pytest.approx(expected_objective, 1e-3)
    n_look_ahead_periods = hybrid_plant.dispatch_builder.options.n_look_ahead_periods
    available_resource = hybrid_plant.pv.generation_profile[0:n_look_ahead_periods]
    dispatch_generation = hybrid_plant.pv.dispatch.generation
    for t in hybrid_plant.dispatch_builder.pyomo_model.forecast_horizon:
        assert dispatch_generation[t] * 1e3 == pytest.approx(available_resource[t], 1e-3)

    available_resource = hybrid_plant.wind.generation_profile[0:n_look_ahead_periods]
    dispatch_generation = hybrid_plant.wind.dispatch.generation
    for t in hybrid_plant.dispatch_builder.pyomo_model.forecast_horizon:
        assert dispatch_generation[t] * 1e3 == pytest.approx(available_resource[t], 1e-3)

    assert sum(hybrid_plant.battery.dispatch.charge_power) > 0.0
    assert sum(hybrid_plant.battery.dispatch.discharge_power) > 0.0
    assert (sum(hybrid_plant.battery.dispatch.charge_power)
            * hybrid_plant.battery.dispatch.round_trip_efficiency / 100.0
            == pytest.approx(sum(hybrid_plant.battery.dispatch.discharge_power)))

    transmission_limit = hybrid_plant.grid.value('grid_interconnection_limit_kwac')
    system_generation = hybrid_plant.grid.dispatch.system_generation
    for t in hybrid_plant.dispatch_builder.pyomo_model.forecast_horizon:
        assert system_generation[t] * 1e3 <= transmission_limit + 1e-3
        assert system_generation[t] * 1e3 >= 0.0
Ejemplo n.º 8
0
def init_simulation_pv():
    """
    Create the simulation object needed to calculate the objective of the problem

    :return: The HOPP simulation as defined for this problem
    """

    # Create the site for the design evaluation
    site = 'irregular'
    location = locations[3]

    if site == 'circular':
        site_data = make_circular_site(lat=location[0], lon=location[1], elev=location[2])
    elif site == 'irregular':
        site_data = make_irregular_site(lat=location[0], lon=location[1], elev=location[2])
    else:
        raise Exception("Unknown site '" + site + "'")

    # Load in weather and price data files
    solar_file = Path(
        __file__).parent.parent / "resource_files" / "solar" / WEATHER_FILE #"Beni_Miha" / "659265_32.69_10.90_2019.csv"
    grid_file = Path(__file__).parent.parent / "resource_files" / "grid" / PRICE_FILE #"tunisia_est_grid_prices.csv"

    # Combine the data into a site definition
    site_info = SiteInfo(site_data, solar_resource_file=solar_file, grid_resource_file=grid_file)

    # set up hybrid simulation with all the required parameters
    solar_size_mw = 200
    battery_capacity_mwh = 15
    battery_capacity_mw = 100
    interconnection_size_mw = 100

    technologies = {'pv': {'system_capacity_kw': solar_size_mw * 1000,
                           'array_type': 2,
                           'dc_ac_ratio': 1.1},
                    'battery': {'system_capacity_kwh': battery_capacity_mwh * 1000,
                                'system_capacity_kw': battery_capacity_mw * 1000},
                    'grid': interconnection_size_mw * 1000}

    # Create the hybrid plant simulation
    # TODO: turn these off to run full year simulation
    dispatch_options = {'is_test_start_year': False,
                        'is_test_end_year': False,
                        'solver': 'gurobi_ampl',
                        'grid_charging': False,  
                        'pv_charging_only': True}

    # TODO: turn-on receiver and field optimization before... initial simulation
    hybrid_plant = HybridSimulation(technologies,
                                    site_info,
                                    interconnect_kw=interconnection_size_mw * 1000,
                                    dispatch_options=dispatch_options)

    # Customize the hybrid plant assumptions here...
    hybrid_plant.pv.value('inv_eff', 95.0)
    hybrid_plant.pv.value('array_type', 0)
    hybrid_plant.pv.dc_degradation = [0] * 25

    return hybrid_plant
Ejemplo n.º 9
0
def test_hybrid_om_costs_error(site):
    wind_pv_battery = {
        key: technologies[key]
        for key in ('pv', 'wind', 'battery')
    }
    hybrid_plant = HybridSimulation(
        wind_pv_battery,
        site,
        interconnect_kw=interconnection_size_kw,
        dispatch_options={'battery_dispatch': 'one_cycle_heuristic'})
    hybrid_plant.ppa_price = (0.03, )
    hybrid_plant.pv.dc_degradation = [0] * 25
    hybrid_plant.battery._financial_model.SystemCosts.om_production = (1, )
    try:
        hybrid_plant.simulate()
    except ValueError as e:
        assert e
Ejemplo n.º 10
0
def test_tower_pv_battery_hybrid(site):
    interconnection_size_kw_test = 50000
    technologies_test = {
        'tower': {
            'cycle_capacity_kw': 50 * 1000,
            'solar_multiple': 2.0,
            'tes_hours': 12.0
        },
        'pv': {
            'system_capacity_kw': 50 * 1000
        },
        'battery': {
            'system_capacity_kwh': 40 * 1000,
            'system_capacity_kw': 20 * 1000
        }
    }

    solar_hybrid = {
        key: technologies_test[key]
        for key in ('tower', 'pv', 'battery')
    }
    hybrid_plant = HybridSimulation(
        solar_hybrid,
        site,
        interconnect_kw=interconnection_size_kw_test,
        dispatch_options={
            'is_test_start_year': True,
            'is_test_end_year': True
        })
    hybrid_plant.ppa_price = (0.12, )  # $/kWh
    hybrid_plant.pv.dc_degradation = [0] * 25

    hybrid_plant.tower.value('helio_width', 10.0)
    hybrid_plant.tower.value('helio_height', 10.0)

    hybrid_plant.simulate()

    aeps = hybrid_plant.annual_energies
    npvs = hybrid_plant.net_present_values

    assert aeps.pv == approx(104053614.17, 1e-3)
    assert aeps.tower == approx(3769716.50, 5e-2)
    assert aeps.battery == approx(-9449.70, 2e-1)
    assert aeps.hybrid == approx(107882747.80, 1e-2)

    assert npvs.pv == approx(45233832.23, 1e3)
Ejemplo n.º 11
0
def test_hybrid_pv_only(site):
    solar_only = {'pv': technologies['pv']}
    hybrid_plant = HybridSimulation(solar_only,
                                    site,
                                    interconnect_kw=interconnection_size_kw)
    hybrid_plant.layout.plot()
    hybrid_plant.ppa_price = (0.01, )
    hybrid_plant.pv.dc_degradation = [0] * 25
    hybrid_plant.simulate()
    aeps = hybrid_plant.annual_energies
    npvs = hybrid_plant.net_present_values

    assert aeps.pv == approx(9884106.55, 1e-3)
    assert aeps.hybrid == approx(9884106.55, 1e-3)

    assert npvs.pv == approx(-5121293, 1e3)
    assert npvs.hybrid == approx(-5121293, 1e3)
Ejemplo n.º 12
0
def test_hybrid_dispatch_heuristic(site):
    dispatch_options = {'battery_dispatch': 'heuristic',
                        'grid_charging': False}
    wind_solar_battery = {key: technologies[key] for key in ('pv', 'wind', 'battery')}

    hybrid_plant = HybridSimulation(wind_solar_battery, site, interconnect_mw * 1000,
                                    dispatch_options=dispatch_options)
    fixed_dispatch = [0.0]*6
    fixed_dispatch.extend([-1.0]*6)
    fixed_dispatch.extend([1.0]*6)
    fixed_dispatch.extend([0.0]*6)

    hybrid_plant.battery.dispatch.user_fixed_dispatch = fixed_dispatch

    hybrid_plant.simulate(1)

    assert sum(hybrid_plant.battery.dispatch.charge_power) > 0.0
    assert sum(hybrid_plant.battery.dispatch.discharge_power) > 0.0
Ejemplo n.º 13
0
def test_tower_field_optimize_before_sim(site):
    """Testing pySSC tower model using HOPP built-in dispatch model"""
    interconnection_size_kw = 50000
    technologies = {
        'tower': {
            'cycle_capacity_kw': 50 * 1000,
            'solar_multiple': 2.0,
            'tes_hours': 6.0,
            'optimize_field_before_sim': True
        },
        'grid': 50000
    }

    system = {key: technologies[key] for key in ('tower', 'grid')}
    system = HybridSimulation(system,
                              site,
                              interconnect_kw=interconnection_size_kw,
                              dispatch_options={'is_test_start_year': True})
    system.ppa_price = (0.12, )

    system.tower.value('helio_width', 10.0)
    system.tower.value('helio_height', 10.0)

    system.tower.generate_field()

    # Get old field:
    field_parameters = [
        'N_hel', 'D_rec', 'rec_height', 'h_tower', 'land_area_base', 'A_sf_in'
    ]
    old_values = {}
    for k in field_parameters:
        old_values[k] = system.tower.value(k)

    system.simulate()

    new_values = {}
    for k in field_parameters:
        new_values[k] = system.tower.value(k)

    assert system.tower.optimize_field_before_sim

    for k in field_parameters:
        assert old_values[k] != new_values[k]
Ejemplo n.º 14
0
def test_hybrid(site):
    """
    Performance from Wind is slightly different from wind-only case because the solar presence modified the wind layout
    """
    solar_wind_hybrid = {key: technologies[key] for key in ('pv', 'wind')}
    hybrid_plant = HybridSimulation(solar_wind_hybrid,
                                    site,
                                    interconnect_kw=interconnection_size_kw)
    hybrid_plant.layout.plot()
    hybrid_plant.ppa_price = (0.01, )
    hybrid_plant.pv.dc_degradation = [0] * 25
    hybrid_plant.simulate()
    # plt.show()
    aeps = hybrid_plant.annual_energies
    npvs = hybrid_plant.net_present_values

    assert aeps.pv == approx(8703525.94, 13)
    assert aeps.wind == approx(33615479.57, 1e3)
    assert aeps.hybrid == approx(41681662.63, 1e3)

    assert npvs.pv == approx(-5121293, 1e3)
    assert npvs.wind == approx(-13909363, 1e3)
    assert npvs.hybrid == approx(-19216589, 1e3)
Ejemplo n.º 15
0
def test_hybrid_solar_battery_dispatch(site):
    expected_objective = 20819.456

    solar_battery_technologies = {k: technologies[k] for k in ('pv', 'battery')}
    hybrid_plant = HybridSimulation(solar_battery_technologies, site, interconnect_mw * 1000,
                                    dispatch_options={'grid_charging': False})
    hybrid_plant.grid.value("federal_tax_rate", (0., ))
    hybrid_plant.grid.value("state_tax_rate", (0., ))
    hybrid_plant.pv.dc_degradation = [0.5] * 1
    hybrid_plant.pv.simulate(1)

    hybrid_plant.dispatch_builder.dispatch.initialize_parameters()
    hybrid_plant.dispatch_builder.dispatch.update_time_series_parameters(0)
    hybrid_plant.battery.dispatch.initial_SOC = hybrid_plant.battery.dispatch.minimum_soc   # Set to min SOC

    n_look_ahead_periods = hybrid_plant.dispatch_builder.options.n_look_ahead_periods
    # This was done because the default peak prices coincide with solar production...
    available_resource = hybrid_plant.pv.generation_profile[0:n_look_ahead_periods]
    prices = [0.] * len(available_resource)
    for t in hybrid_plant.dispatch_builder.pyomo_model.forecast_horizon:
        if available_resource[t] > 0.0:
            prices[t] = 30.0
        else:
            prices[t] = 110.0
    hybrid_plant.grid.dispatch.electricity_sell_price = prices
    hybrid_plant.grid.dispatch.electricity_purchase_price = prices

    results = HybridDispatchBuilderSolver.glpk_solve_call(hybrid_plant.dispatch_builder.pyomo_model)

    assert results.solver.termination_condition == TerminationCondition.optimal

    gross_profit_objective = pyomo.value(hybrid_plant.dispatch_builder.dispatch.objective_value)
    assert gross_profit_objective == pytest.approx(expected_objective, 1e-3)

    available_resource = hybrid_plant.pv.generation_profile[0:n_look_ahead_periods]
    dispatch_generation = hybrid_plant.pv.dispatch.generation
    for t in hybrid_plant.dispatch_builder.pyomo_model.forecast_horizon:
        assert dispatch_generation[t] * 1e3 == pytest.approx(available_resource[t], 1e-3)

    assert sum(hybrid_plant.battery.dispatch.charge_power) > 0.0
    assert sum(hybrid_plant.battery.dispatch.discharge_power) > 0.0
    assert (sum(hybrid_plant.battery.dispatch.charge_power)
            * hybrid_plant.battery.dispatch.round_trip_efficiency / 100.0
            == pytest.approx(sum(hybrid_plant.battery.dispatch.discharge_power)))

    transmission_limit = hybrid_plant.grid.value('grid_interconnection_limit_kwac')
    system_generation = hybrid_plant.grid.dispatch.system_generation
    for t in hybrid_plant.dispatch_builder.pyomo_model.forecast_horizon:
        assert system_generation[t] * 1e3 <= transmission_limit
        assert system_generation[t] * 1e3 >= 0.0
Ejemplo n.º 16
0
def init_simulation_csp():
    """
    Create the simulation object needed to calculate the objective of the problem

    :return: The HOPP simulation as defined for this problem
    """

    # Create the site for the design evaluation
    site = 'irregular'
    location = locations[3]

    if site == 'circular':
        site_data = make_circular_site(lat=location[0], lon=location[1], elev=location[2])
    elif site == 'irregular':
        site_data = make_irregular_site(lat=location[0], lon=location[1], elev=location[2])
    else:
        raise Exception("Unknown site '" + site + "'")

    # Load in weather and price data files
    solar_file = Path(
        __file__).parent.parent / "resource_files" / "solar" / WEATHER_FILE #"Beni_Miha" / "659265_32.69_10.90_2019.csv"
    grid_file = Path(__file__).parent.parent / "resource_files" / "grid" / PRICE_FILE #"tunisia_est_grid_prices.csv"

    # Combine the data into a site definition
    site_info = SiteInfo(site_data, solar_resource_file=solar_file, grid_resource_file=grid_file)

    # set up hybrid simulation with all the required parameters
    tower_cycle_mw = 100
    interconnection_size_mw = 100

    technologies = {'tower': {'cycle_capacity_kw': tower_cycle_mw * 1000,
                              'solar_multiple': 2.0,
                              'tes_hours': 12.0,
                              'optimize_field_before_sim': True}, # TODO: turn on
                    'grid': interconnection_size_mw * 1000}

    # Create the hybrid plant simulation
    # TODO: turn these off to run full year simulation
    dispatch_options = {'is_test_start_year': False,
                        'is_test_end_year': False,
                        'solver': 'gurobi_ampl'}

    # TODO: turn-on receiver and field optimization before... initial simulation
    hybrid_plant = HybridSimulation(technologies,
                                    site_info,
                                    interconnect_kw=interconnection_size_mw * 1000,
                                    dispatch_options=dispatch_options)

    return hybrid_plant
Ejemplo n.º 17
0
def test_trough_pv_hybrid(site):
    interconnection_size_kw_test = 50000
    technologies_test = {
        'trough': {
            'cycle_capacity_kw': 50 * 1000,
            'solar_multiple': 2.0,
            'tes_hours': 12.0
        },
        'pv': {
            'system_capacity_kw': 50 * 1000
        }
    }

    solar_hybrid = {key: technologies_test[key] for key in ('trough', 'pv')}
    hybrid_plant = HybridSimulation(
        solar_hybrid,
        site,
        interconnect_kw=interconnection_size_kw_test,
        dispatch_options={
            'is_test_start_year': True,
            'is_test_end_year': True
        })

    hybrid_plant.ppa_price = (0.12, )  # $/kWh
    hybrid_plant.pv.dc_degradation = [0] * 25

    hybrid_plant.simulate()

    aeps = hybrid_plant.annual_energies
    npvs = hybrid_plant.net_present_values

    assert aeps.pv == approx(104053614.17, 1e-3)
    assert aeps.trough == approx(1871471.58, 2e-2)
    assert aeps.hybrid == approx(105926003.55, 1e-3)

    assert npvs.pv == approx(45233832.23, 1e3)
Ejemplo n.º 18
0
def init_hybrid_plant(techs_in_sim: list,
                      is_test: bool = False,
                      ud_techs: dict = {}):
    """
    Initialize hybrid simulation object using specific project inputs
    :param techs_in_sim: List of technologies to include in the simulation
    :param is_test: if True, runs dispatch for the first and last 5 days of the year
        and turns off tower and receiver optimization
    :param ud_techs: Dictionary containing technology initialization parameters required by HybridSimulation

    :return: HybridSimulation as defined for this problem
    """
    schedule_scale = 100  # MWe
    grid_interconnect_mw = 100  # MWe
    example_root = get_example_path_root()

    # Set plant location
    site_data = {
        "lat": 34.8653,
        "lon": -116.7830,
        "elev": 561,
        "tz": 1,
        "no_wind": True
    }
    solar_file = example_root + "02_weather_data/daggett_ca_34.865371_-116.783023_psmv3_60_tmy.csv"
    prices_file = example_root + "03_cost_load_price_data/constant_norm_prices.csv"
    desired_schedule_file = example_root + "03_cost_load_price_data/desired_schedule_normalized.csv"
    # Reading in desired schedule
    with open(desired_schedule_file) as f:
        csvreader = csv.reader(f)
        desired_schedule = []
        for row in csvreader:
            desired_schedule.append(float(row[0]) * schedule_scale)

    # If normalized pricing is used, then PPA price must be adjusted after HybridSimulation is initialized
    site = SiteInfo(site_data,
                    solar_resource_file=solar_file,
                    grid_resource_file=prices_file,
                    desired_schedule=desired_schedule)

    # Load in system costs
    with open(example_root +
              "03_cost_load_price_data/system_costs_SAM.json") as f:
        cost_info = json.load(f)

    # Initializing technologies
    if ud_techs:
        technologies = ud_techs
    else:
        technologies = {
            'tower': {
                'cycle_capacity_kw': 200 * 1000,  #100
                'solar_multiple': 4.0,  #2.0
                'tes_hours': 20.0,  #14
                'optimize_field_before_sim': not is_test,
                'scale_input_params': True,
            },
            'trough': {
                'cycle_capacity_kw': 200 * 1000,
                'solar_multiple': 6.0,
                'tes_hours': 28.0
            },
            'pv': {
                'system_capacity_kw': 120 * 1000
            },
            'battery': {
                'system_capacity_kwh': 200 * 1000,
                'system_capacity_kw': 100 * 1000
            },
            'grid': grid_interconnect_mw * 1000
        }

    # Create hybrid simulation class based on the technologies needed in the simulation
    sim_techs = {key: technologies[key] for key in techs_in_sim}
    sim_techs['grid'] = technologies['grid']

    hybrid_plant = HybridSimulation(sim_techs,
                                    site,
                                    interconnect_kw=technologies['grid'],
                                    dispatch_options={
                                        'is_test_start_year': is_test,
                                        'is_test_end_year': is_test,
                                        'solver': 'cbc',
                                        'grid_charging': False,
                                        'pv_charging_only': True
                                    },
                                    cost_info=cost_info['cost_info'])

    csp_dispatch_obj_costs = {
        'cost_per_field_generation': 0.5,
        'cost_per_field_start_rel': 0.0,
        'cost_per_cycle_generation': 2.0,
        'cost_per_cycle_start_rel': 0.0,
        'cost_per_change_thermal_input': 0.5
    }

    # Set CSP costs
    if hybrid_plant.tower:
        hybrid_plant.tower.ssc.set(cost_info['tower_costs'])
        hybrid_plant.tower.dispatch.objective_cost_terms = csp_dispatch_obj_costs
    if hybrid_plant.trough:
        hybrid_plant.trough.ssc.set(cost_info['trough_costs'])
        hybrid_plant.trough.dispatch.objective_cost_terms = csp_dispatch_obj_costs

    # Set O&M costs for all technologies
    for tech in ['tower', 'trough', 'pv', 'battery']:
        if not tech in techs_in_sim:
            cost_info["SystemCosts"].pop(tech)

    hybrid_plant.assign(cost_info["SystemCosts"])

    # Set financial parameters for singleowner model
    with open(example_root +
              '03_cost_load_price_data/financial_parameters_SAM.json') as f:
        fin_info = json.load(f)

    hybrid_plant.assign(fin_info["FinancialParameters"])
    hybrid_plant.assign(fin_info["TaxCreditIncentives"])
    hybrid_plant.assign(fin_info["Revenue"])
    hybrid_plant.assign(fin_info["Depreciation"])
    hybrid_plant.assign(fin_info["PaymentIncentives"])

    # Set specific technology assumptions here
    if hybrid_plant.pv:
        hybrid_plant.pv.dc_degradation = [0.5] * 25
        hybrid_plant.pv.value('array_type', 2)  # 1-axis tracking
        hybrid_plant.pv.value('tilt', 0)  # Tilt for 1-axis

    # This is required if normalized prices are provided
    hybrid_plant.ppa_price = (0.10, )  # $/kWh

    return hybrid_plant
Ejemplo n.º 19
0
def test_wind_pv_with_storage_dispatch(site):
    wind_pv_battery = {
        key: technologies[key]
        for key in ('pv', 'wind', 'battery')
    }
    hybrid_plant = HybridSimulation(wind_pv_battery,
                                    site,
                                    interconnect_kw=interconnection_size_kw)
    hybrid_plant.battery.dispatch.lifecycle_cost_per_kWh_cycle = 0.01
    hybrid_plant.ppa_price = (0.03, )
    hybrid_plant.pv.dc_degradation = [0] * 25
    hybrid_plant.simulate()
    aeps = hybrid_plant.annual_energies
    npvs = hybrid_plant.net_present_values
    taxes = hybrid_plant.federal_taxes
    apv = hybrid_plant.energy_purchases_values
    debt = hybrid_plant.debt_payment
    esv = hybrid_plant.energy_sales_values
    depr = hybrid_plant.federal_depreciation_totals
    insr = hybrid_plant.insurance_expenses
    om = hybrid_plant.om_total_expenses
    rev = hybrid_plant.total_revenues
    tc = hybrid_plant.tax_incentives

    assert aeps.pv == approx(9882421, rel=0.05)
    assert aeps.wind == approx(33637983, rel=0.05)
    assert aeps.battery == approx(-31287, rel=0.05)
    assert aeps.hybrid == approx(43489117, rel=0.05)

    assert npvs.pv == approx(-853226, rel=5e-2)
    assert npvs.wind == approx(-4380277, rel=5e-2)
    assert npvs.battery == approx(-6889961, rel=5e-2)
    assert npvs.hybrid == approx(-11861790, rel=5e-2)

    assert taxes.pv[1] == approx(94661, rel=5e-2)
    assert taxes.wind[1] == approx(413068, rel=5e-2)
    assert taxes.battery[1] == approx(297174, rel=5e-2)
    assert taxes.hybrid[1] == approx(804904, rel=5e-2)

    assert apv.pv[1] == approx(0, rel=5e-2)
    assert apv.wind[1] == approx(0, rel=5e-2)
    assert apv.battery[1] == approx(40158, rel=5e-2)
    assert apv.hybrid[1] == approx(3050, rel=5e-2)

    assert debt.pv[1] == approx(0, rel=5e-2)
    assert debt.wind[1] == approx(0, rel=5e-2)
    assert debt.battery[1] == approx(0, rel=5e-2)
    assert debt.hybrid[1] == approx(0, rel=5e-2)

    assert esv.pv[1] == approx(353105, rel=5e-2)
    assert esv.wind[1] == approx(956067, rel=5e-2)
    assert esv.battery[1] == approx(80449, rel=5e-2)
    assert esv.hybrid[1] == approx(1352445, rel=5e-2)

    assert depr.pv[1] == approx(762811, rel=5e-2)
    assert depr.wind[1] == approx(2651114, rel=5e-2)
    assert depr.battery[1] == approx(1486921, rel=5e-2)
    assert depr.hybrid[1] == approx(4900847, rel=5e-2)

    assert insr.pv[0] == approx(0, rel=5e-2)
    assert insr.wind[0] == approx(0, rel=5e-2)
    assert insr.battery[0] == approx(0, rel=5e-2)
    assert insr.hybrid[0] == approx(0, rel=5e-2)

    assert om.pv[1] == approx(74993, rel=5e-2)
    assert om.wind[1] == approx(420000, rel=5e-2)
    assert om.battery[1] == approx(75000, rel=5e-2)
    assert om.hybrid[1] == approx(569993, rel=5e-2)

    assert rev.pv[1] == approx(353105, rel=5e-2)
    assert rev.wind[1] == approx(956067, rel=5e-2)
    assert rev.battery[1] == approx(80449, rel=5e-2)
    assert rev.hybrid[1] == approx(1352445, rel=5e-2)

    assert tc.pv[1] == approx(1123104, rel=5e-2)
    assert tc.wind[1] == approx(504569, rel=5e-2)
    assert tc.battery[1] == approx(0, rel=5e-2)
    assert tc.hybrid[1] == approx(1646170, rel=5e-2)
Ejemplo n.º 20
0
        'layout_mode':
        'boundarygrid',
        'layout_params':
        WindBoundaryGridParameters(border_spacing=2,
                                   border_offset=0.5,
                                   grid_angle=0.5,
                                   grid_aspect_power=0.5,
                                   row_phase_offset=0.5)
    }
}

# Get resource

# Create model
hybrid_plant = HybridSimulation(technologies,
                                site_info,
                                interconnect_kw=interconnection_size_mw * 1000)
# hybrid_plant.plot_layout()
# plt.show()
hybrid_plant.simulate(1)

# Setup Optimization Candidate


class HybridLayoutProblem(OptimizationProblem):
    """
    Optimize the layout of the wind and solar plant
    """
    def __init__(self, simulation: HybridSimulation) -> None:
        """
        Optimize layout with fixed number of turbines and solar capacity
Ejemplo n.º 21
0
def init_hybrid_plant():
    """
    Initialize hybrid simulation object using specific project inputs
    :return: HybridSimulation as defined for this problem
    """
    is_test = False  # Turns off full year dispatch and optimize tower and receiver
    
    techs_in_sim = ['tower',
                    'pv',
                    'battery',
                    'grid']

    site_data = {
        "lat": 34.85,
        "lon": -116.9,
        "elev": 641,
        "year": 2012,
        "tz": -8,
        "no_wind": True
        }

    root = "C:/Users/WHamilt2/Documents/Projects/HOPP/CSP_PV_battery_dispatch_plots/"
    solar_file = root + "34.865371_-116.783023_psmv3_60_tmy.csv"
    prices_file = root + "constant_nom_prices.csv"
    schedule_scale = 100  # MWe
    desired_schedule_file = root + "sample_load_profile_normalized.csv"
    # Reading in desired schedule
    with open(desired_schedule_file) as f:
        csvreader = csv.reader(f)
        desired_schedule = []
        for row in csvreader:
            desired_schedule.append(float(row[0])*schedule_scale)

    # If normalized pricing is used, then PPA price must be adjusted after HybridSimulation is initialized
    site = SiteInfo(site_data,
                    solar_resource_file=solar_file,
                    grid_resource_file=prices_file,
                    desired_schedule=desired_schedule
                    )

    technologies = {'tower': {
                        'cycle_capacity_kw':  100 * 1000, #100 * 1000,
                        'solar_multiple': 3.0, #2.0,
                        'tes_hours': 16.0, #16.0,
                        'optimize_field_before_sim': not is_test,
                        'scale_input_params': True,
                        },
                    'trough': {
                        'cycle_capacity_kw': 100 * 1000,
                        'solar_multiple': 4.0,
                        'tes_hours': 20.0
                    },
                    'pv': {
                        'system_capacity_kw': 50 * 1000
                        },
                    'battery': {
                        'system_capacity_kwh': 300 * 1000,
                        'system_capacity_kw': 100 * 1000
                        },
                    'grid': 150 * 1000}

    # Create model
    hybrid_plant = HybridSimulation({key: technologies[key] for key in techs_in_sim}, 
                                    site,
                                    interconnect_kw=technologies['grid'],
                                    dispatch_options={
                                        'is_test_start_year': is_test,
                                        'is_test_end_year': is_test,
                                        'solver': 'xpress',
                                        'grid_charging': False,
                                        'pv_charging_only': True,
                                        },
                                    simulation_options={
                                        'storage_capacity_credit': False,
                                    }
                                    )

    # Defaults:
    # {'cost_per_field_generation': 0.5,
    #  'cost_per_field_start_rel': 1.5,
    #  'cost_per_cycle_generation': 2.0,
    #  'cost_per_cycle_start_rel': 40.0,
    #  'cost_per_change_thermal_input': 0.5}

    csp_dispatch_obj_costs = dict()
    csp_dispatch_obj_costs = {
                              'cost_per_field_generation': 0.0, #0.5,
    #                           'cost_per_field_start_rel': 0.0,
    #                           'cost_per_cycle_generation': 2.0,
                              'cost_per_cycle_start_rel': 0.0,
                              'cost_per_change_thermal_input': 0.5}

    # Set CSP costs
    if hybrid_plant.tower:
        hybrid_plant.tower.dispatch.objective_cost_terms.update(csp_dispatch_obj_costs)
        hybrid_plant.tower.value('cycle_max_frac', 1.0)
    if hybrid_plant.trough:
        hybrid_plant.trough.dispatch.objective_cost_terms.update(csp_dispatch_obj_costs)
        hybrid_plant.trough.value('cycle_max_frac', 1.0)

    # if hybrid_plant.battery:
    #     hybrid_plant.battery.dispatch.lifecycle_cost_per_kWh_cycle = 0.0265 / 100
    #     # hybrid_plant.battery.dispatch.lifecycle_cost_per_kWh_cycle = 1e-6

    if hybrid_plant.pv:
        hybrid_plant.pv.dc_degradation = [0.5] * 25
        hybrid_plant.pv.value('array_type', 2)  # 1-axis tracking
        hybrid_plant.pv.value('tilt', 0)        # Tilt for 1-axis

    # This is required if normalized prices are provided
    hybrid_plant.ppa_price = (0.12,)  # $/kWh

    return hybrid_plant
Ejemplo n.º 22
0
technologies = {'pv': {
                    'system_capacity_kw': solar_size_mw * 1000
                },
                'wind': {
                    'num_turbines': 10,
                    'turbine_rating_kw': 2000
                }}

# Get resource
lat = flatirons_site['lat']
lon = flatirons_site['lon']
prices_file = examples_dir.parent / "resource_files" / "grid" / "pricing-data-2015-IronMtn-002_factors.csv"
site = SiteInfo(flatirons_site, grid_resource_file=prices_file)

# Create model
hybrid_plant = HybridSimulation(technologies, site, interconnect_kw=interconnection_size_mw * 1000)

hybrid_plant.pv.system_capacity_kw = solar_size_mw * 1000
hybrid_plant.wind.system_capacity_by_num_turbines(wind_size_mw * 1000)
hybrid_plant.ppa_price = 0.1
hybrid_plant.pv.dc_degradation = [0] * 25
hybrid_plant.simulate(25)

# Save the outputs
annual_energies = hybrid_plant.annual_energies
wind_plus_solar_npv = hybrid_plant.net_present_values.wind + hybrid_plant.net_present_values.pv
npvs = hybrid_plant.net_present_values

wind_installed_cost = hybrid_plant.wind.total_installed_cost
solar_installed_cost = hybrid_plant.pv.total_installed_cost
hybrid_installed_cost = hybrid_plant.grid.total_installed_cost
Ejemplo n.º 23
0
def run_hopp_calc(Site, scenario_description, bos_details,
                  total_hybrid_plant_capacity_mw, solar_size_mw, wind_size_mw,
                  nameplate_mw, interconnection_size_mw,
                  load_resource_from_file, ppa_price, results_dir):
    """ run_hopp_calc Establishes sizing models, creates a wind or solar farm based on the desired sizes,
     and runs SAM model calculations for the specified inputs.
     save_outputs contains a dictionary of all results for the hopp calculation.

    :param scenario_description: Project scenario - 'greenfield' or 'solar addition'.
    :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE).
    :param total_hybrid_plant_capacity_mw: capacity in MW of hybrid plant.
    :param solar_size_mw: capacity in MW of solar component of plant.
    :param wind_size_mw: capacity in MW of wind component of plant.
    :param nameplate_mw: nameplate capacity of total plant.
    :param interconnection_size_mw: interconnection size in MW.
    :param load_resource_from_file: flag determining whether resource is loaded directly from file or through
     interpolation routine.
    :param ppa_price: PPA price in USD($)
    :return: collection of outputs from SAM and hybrid-specific calculations (includes e.g. AEP, IRR, LCOE),
     plus wind and solar filenames used
    (save_outputs)
    """
    # Get resource data
    if load_resource_from_file:
        pass
    else:
        Site[
            'resource_filename_solar'] = ""  # Unsetting resource filename to force API download of wind resource
        Site[
            'resource_filename_wind'] = ""  # Unsetting resource filename to force API download of solar resource

    site = SiteInfo(Site,
                    solar_resource_file=sample_site['resource_filename_solar'],
                    wind_resource_file=sample_site['resource_filename_wind'])

    #TODO: Incorporate this in SiteInfo
    # if 'roll_tz' in Site.keys():
    #     site.solar_resource.roll_timezone(Site['roll_tz'], Site['roll_tz'])

    # Set up technology and cost model info
    technologies = {
        'solar': solar_size_mw,  # mw system capacity
        'wind': wind_size_mw,  # mw system capacity
        'grid': interconnection_size_mw
    }  # mw interconnect

    # Create model
    hybrid_plant = HybridSimulation(technologies,
                                    site,
                                    interconnect_kw=interconnection_size_mw *
                                    1000)

    hybrid_plant.setup_cost_calculator(
        create_cost_calculator(interconnection_size_mw,
                               bos_details['BOSSource'], scenario_description))

    hybrid_plant.ppa_price = ppa_price
    hybrid_plant.discount_rate = 6.4
    hybrid_plant.solar.system_capacity_kw = solar_size_mw * 1000
    hybrid_plant.wind.system_capacity_by_num_turbines(wind_size_mw * 1000)
    actual_solar_pct = hybrid_plant.solar.system_capacity_kw / \
                       (hybrid_plant.solar.system_capacity_kw + hybrid_plant.wind.system_capacity_kw)

    logger.info("Run with solar percent {}".format(actual_solar_pct))
    hybrid_plant.simulate()
    outputs = hybrid_plant.hybrid_outputs()
    for k, v in outputs.items():
        outputs[k] = [v]

    return outputs, site.wind_resource.filename, site.solar_resource.filename
Ejemplo n.º 24
0
def setup_power_calcs(scenario, solar_size_mw, storage_size_mwh,
                      storage_size_mw, interconnection_size_mw):
    """
    A function to facilitate plant setup for POWER calculations, assuming one wind turbine.
    
    INPUT VARIABLES
    scenario: dict, the H2 scenario of interest
    solar_size_mw: float, the amount of solar capacity in MW
    storage_size_mwh: float, the amount of battery storate capacity in MWh
    storage_size_mw: float, the amount of battery storate capacity in MW
    interconnection_size_mw: float, the interconnection size in MW

    OUTPUTS
    hybrid_plant: the hybrid plant object from HOPP for power calculations
    """

    # Set API key
    load_dotenv()
    NREL_API_KEY = os.getenv("NREL_API_KEY")
    set_developer_nrel_gov_key(
        NREL_API_KEY
    )  # Set this key manually here if you are not setting it using the .env

    # Step 1: Establish output structure and special inputs
    year = 2013
    sample_site['year'] = year
    useful_life = 30
    custom_powercurve = True
    electrolyzer_size = 50000

    sample_site['lat'] = scenario['Lat']
    sample_site['lon'] = scenario['Long']
    tower_height = scenario['Tower Height']

    scenario['Useful Life'] = useful_life

    site = SiteInfo(sample_site, hub_height=tower_height)

    technologies = {
        'pv': {
            'system_capacity_kw': solar_size_mw * 1000
        },
        'wind': {
            'num_turbines': 1,
            'turbine_rating_kw': scenario['Turbine Rating'] * 1000,
            'hub_height': scenario['Tower Height'],
            'rotor_diameter': scenario['Rotor Diameter']
        },
        'grid': electrolyzer_size,
        'battery': {
            'system_capacity_kwh': storage_size_mwh * 1000,
            'system_capacity_kw': storage_size_mw * 1000
        }
    }
    dispatch_options = {'battery_dispatch': 'heuristic'}
    hybrid_plant = HybridSimulation(technologies,
                                    site,
                                    interconnect_kw=electrolyzer_size,
                                    dispatch_options=dispatch_options)

    hybrid_plant.wind._system_model.Turbine.wind_resource_shear = 0.33

    if custom_powercurve:
        powercurve_file = open(scenario['Powercurve File'])
        powercurve_data = json.load(powercurve_file)
        powercurve_file.close()
        hybrid_plant.wind._system_model.Turbine.wind_turbine_powercurve_windspeeds = \
            powercurve_data['turbine_powercurve_specification']['wind_speed_ms']
        hybrid_plant.wind._system_model.Turbine.wind_turbine_powercurve_powerout = \
            powercurve_data['turbine_powercurve_specification']['turbine_power_output']

    hybrid_plant.pv.system_capacity_kw = solar_size_mw * 1000

    return hybrid_plant
Ejemplo n.º 25
0
def run_hopp_calc(Site, scenario_description, bos_details, total_hybrid_plant_capacity_mw, solar_size_mw, wind_size_mw,
                    nameplate_mw, interconnection_size_mw, load_resource_from_file,
                    ppa_price, results_dir):
    """ run_hopp_calc Establishes sizing models, creates a wind or solar farm based on the desired sizes,
     and runs SAM model calculations for the specified inputs.
     save_outputs contains a dictionary of all results for the hopp calculation.

    :param scenario_description: Project scenario - 'greenfield' or 'solar addition'.
    :param bos_details: contains bos details including type of analysis to conduct (cost/mw, json lookup, HybridBOSSE).
    :param total_hybrid_plant_capacity_mw: capacity in MW of hybrid plant.
    :param solar_size_mw: capacity in MW of solar component of plant.
    :param wind_size_mw: capacity in MW of wind component of plant.
    :param nameplate_mw: nameplate capacity of total plant.
    :param interconnection_size_mw: interconnection size in MW.
    :param load_resource_from_file: flag determining whether resource is loaded directly from file or through
     interpolation routine.
    :param ppa_price: PPA price in USD($)
    :return: collection of outputs from SAM and hybrid-specific calculations (includes e.g. AEP, IRR, LCOE),
     plus wind and solar filenames used
    (save_outputs)
    """
    # Get resource data
    # sample_site['lat'] = Site['Lat']
    # sample_site['lon'] = Site['Lon']
    # # site = SiteInfo(sample_site, solar_resource_file=Site['resource_filename_solar'],
    # #                 wind_resource_file=Site['resource_filename_wind'])
    if load_resource_from_file:
        pass
    else:
        Site['resource_filename_solar'] = ""  # Unsetting resource filename to force API download of wind resource
        Site['resource_filename_wind'] = ""  # Unsetting resource filename to force API download of solar resource

    site = SiteInfo(Site)

    if 'roll_tz' in Site.keys():
        site.solar_resource.roll_timezone(Site['roll_tz'], Site['roll_tz'])

    # Set up technology and cost model info
    technologies = {'solar': solar_size_mw,          # mw system capacity
                    'wind': wind_size_mw            # mw system capacity
                    }

    # Create model
    hybrid_plant = HybridSimulation(technologies, site, interconnect_kw=interconnection_size_mw * 1000)

    # hybrid_plant.setup_cost_calculator(create_cost_calculator(bos_cost_source='boslookup', interconnection_mw=interconnection_size_mw))
    hybrid_plant.setup_cost_calculator(create_cost_calculator(bos_cost_source=bos_details['BOSSource'],
                                                                    interconnection_mw=interconnection_size_mw,
                                                              modify_costs=bos_details['Modify Costs'],
                                                              cost_reductions=bos_details,
                                                              wind_installed_cost_mw=1696000,
                                                              solar_installed_cost_mw=1088600,
                                                              storage_installed_cost_mw=0,
                                                              storage_installed_cost_mwh=0,
                                                              ))

    hybrid_plant.ppa_price = ppa_price
    hybrid_plant.discount_rate = 6.4
    hybrid_plant.solar.system_capacity_kw = solar_size_mw * 1000
    hybrid_plant.wind.rotor_diameter = 100
    # Modify Wind Turbine Coordinates
    Nx = 8
    Ny = 5
    spacing = hybrid_plant.wind.row_spacing
    turbine_x = np.linspace(0, (Nx * spacing) - spacing, Nx)
    turbine_y = np.linspace(0, (Ny * spacing) - spacing, Ny)
    turbX = np.zeros(Nx * Ny)
    turbY = np.zeros(Nx * Ny)
    count = 0
    for i in range(Nx):
        for j in range(Ny):
            turbX[count] = turbine_x[i]
            turbY[count] = turbine_y[j]
            count = count + 1
    hybrid_plant.wind.modify_coordinates(list(turbX), list(turbY))
    hybrid_plant.wind.system_capacity_by_num_turbines(wind_size_mw * 1000)
    actual_solar_pct = hybrid_plant.solar.system_capacity_kw / \
                       (hybrid_plant.solar.system_capacity_kw + hybrid_plant.wind.system_capacity_kw)

    logger.info("Run with solar percent {}".format(actual_solar_pct))
    hybrid_plant.simulate()
    outputs = hybrid_plant.hybrid_outputs()
    for k, v in outputs.items():
        outputs[k] = [v]

    return outputs, site.wind_resource.filename, site.solar_resource.filename
Ejemplo n.º 26
0
# Set wind, solar, and interconnection capacities (in MW)
solar_size_mw = 20
wind_size_mw = 20
interconnection_size_mw = 20

technologies = {'solar': solar_size_mw,  # mw system capacity
                'wind': wind_size_mw,  # mw system capacity
                'grid': interconnection_size_mw}

# Get resource
lat = flatirons_site['lat']
lon = flatirons_site['lon']
site = SiteInfo(flatirons_site)

# Create model
hybrid_plant = HybridSimulation(technologies, site, interconnect_kw=interconnection_size_mw * 1000)

# Setup cost model
hybrid_plant.setup_cost_calculator(create_cost_calculator(interconnection_size_mw))
hybrid_plant.solar.system_capacity_kw = solar_size_mw * 1000
hybrid_plant.wind.system_capacity_by_num_turbines(wind_size_mw * 1000)
hybrid_plant.ppa_price = 0.1
hybrid_plant.simulate(25)

# Save the outputs
annual_energies = hybrid_plant.annual_energies
wind_plus_solar_npv = hybrid_plant.net_present_values.wind + hybrid_plant.net_present_values.solar
npvs = hybrid_plant.net_present_values

wind_installed_cost = hybrid_plant.wind.financial_model.SystemCosts.total_installed_cost
solar_installed_cost = hybrid_plant.solar.financial_model.SystemCosts.total_installed_cost
Ejemplo n.º 27
0
def test_hybrid_om_costs(site):
    wind_pv_battery = {
        key: technologies[key]
        for key in ('pv', 'wind', 'battery')
    }
    hybrid_plant = HybridSimulation(
        wind_pv_battery,
        site,
        interconnect_kw=interconnection_size_kw,
        dispatch_options={'battery_dispatch': 'one_cycle_heuristic'})
    hybrid_plant.ppa_price = (0.03, )
    hybrid_plant.pv.dc_degradation = [0] * 25

    # set all O&M costs to 0 to start
    hybrid_plant.wind.om_fixed = 0
    hybrid_plant.wind.om_capacity = 0
    hybrid_plant.wind.om_variable = 0
    hybrid_plant.pv.om_fixed = 0
    hybrid_plant.pv.om_capacity = 0
    hybrid_plant.pv.om_variable = 0
    hybrid_plant.battery.om_fixed = 0
    hybrid_plant.battery.om_capacity = 0
    hybrid_plant.battery.om_variable = 0

    # test variable costs
    hybrid_plant.wind.om_variable = 5
    hybrid_plant.pv.om_variable = 2
    hybrid_plant.battery.om_variable = 3
    hybrid_plant.simulate()
    var_om_costs = hybrid_plant.om_variable_expenses
    total_om_costs = hybrid_plant.om_total_expenses
    for i in range(len(var_om_costs.hybrid)):
        assert var_om_costs.pv[i] + var_om_costs.wind[
            i] + var_om_costs.battery[i] == approx(var_om_costs.hybrid[i],
                                                   rel=1e-1)
        assert total_om_costs.pv[i] == approx(var_om_costs.pv[i])
        assert total_om_costs.wind[i] == approx(var_om_costs.wind[i])
        assert total_om_costs.battery[i] == approx(var_om_costs.battery[i])
        assert total_om_costs.hybrid[i] == approx(var_om_costs.hybrid[i])
    hybrid_plant.wind.om_variable = 0
    hybrid_plant.pv.om_variable = 0
    hybrid_plant.battery.om_variable = 0

    # test fixed costs
    hybrid_plant.wind.om_fixed = 5
    hybrid_plant.pv.om_fixed = 2
    hybrid_plant.battery.om_fixed = 3
    hybrid_plant.simulate()
    fixed_om_costs = hybrid_plant.om_fixed_expenses
    total_om_costs = hybrid_plant.om_total_expenses
    for i in range(len(fixed_om_costs.hybrid)):
        assert fixed_om_costs.pv[i] + fixed_om_costs.wind[i] + fixed_om_costs.battery[i] \
               == approx(fixed_om_costs.hybrid[i])
        assert total_om_costs.pv[i] == approx(fixed_om_costs.pv[i])
        assert total_om_costs.wind[i] == approx(fixed_om_costs.wind[i])
        assert total_om_costs.battery[i] == approx(fixed_om_costs.battery[i])
        assert total_om_costs.hybrid[i] == approx(fixed_om_costs.hybrid[i])
    hybrid_plant.wind.om_fixed = 0
    hybrid_plant.pv.om_fixed = 0
    hybrid_plant.battery.om_fixed = 0

    # test capacity costs
    hybrid_plant.wind.om_capacity = 5
    hybrid_plant.pv.om_capacity = 2
    hybrid_plant.battery.om_capacity = 3
    hybrid_plant.simulate()
    cap_om_costs = hybrid_plant.om_capacity_expenses
    total_om_costs = hybrid_plant.om_total_expenses
    for i in range(len(cap_om_costs.hybrid)):
        assert cap_om_costs.pv[i] + cap_om_costs.wind[i] + cap_om_costs.battery[i] \
               == approx(cap_om_costs.hybrid[i])
        assert total_om_costs.pv[i] == approx(cap_om_costs.pv[i])
        assert total_om_costs.wind[i] == approx(cap_om_costs.wind[i])
        assert total_om_costs.battery[i] == approx(cap_om_costs.battery[i])
        assert total_om_costs.hybrid[i] == approx(cap_om_costs.hybrid[i])
    hybrid_plant.wind.om_capacity = 0
    hybrid_plant.pv.om_capacity = 0
    hybrid_plant.battery.om_capacity = 0
Ejemplo n.º 28
0
def test_capacity_credit(site):
    site = SiteInfo(data=flatirons_site,
                    solar_resource_file=solar_resource_file,
                    wind_resource_file=wind_resource_file,
                    capacity_hours=capacity_credit_hours)
    wind_pv_battery = {
        key: technologies[key]
        for key in ('pv', 'wind', 'battery')
    }
    hybrid_plant = HybridSimulation(wind_pv_battery,
                                    site,
                                    interconnect_kw=interconnection_size_kw)
    hybrid_plant.battery.dispatch.lifecycle_cost_per_kWh_cycle = 0.01
    hybrid_plant.ppa_price = (0.03, )
    hybrid_plant.pv.dc_degradation = [0] * 25

    # Backup values for resetting before tests
    gen_max_feasible_orig = hybrid_plant.battery.gen_max_feasible
    capacity_hours_orig = hybrid_plant.site.capacity_hours
    interconnect_kw_orig = hybrid_plant.interconnect_kw

    def reinstate_orig_values():
        hybrid_plant.battery.gen_max_feasible = gen_max_feasible_orig
        hybrid_plant.site.capacity_hours = capacity_hours_orig
        hybrid_plant.interconnect_kw = interconnect_kw_orig

    # Test when 0 gen_max_feasible
    reinstate_orig_values()
    hybrid_plant.battery.gen_max_feasible = [0] * 8760
    capacity_credit_battery = hybrid_plant.battery.calc_capacity_credit_percent(
        hybrid_plant.interconnect_kw)
    assert capacity_credit_battery == approx(0, rel=0.05)
    # Test when representative gen_max_feasible
    reinstate_orig_values()
    hybrid_plant.battery.gen_max_feasible = [2500] * 8760
    capacity_credit_battery = hybrid_plant.battery.calc_capacity_credit_percent(
        hybrid_plant.interconnect_kw)
    assert capacity_credit_battery == approx(50, rel=0.05)
    # Test when no capacity hours
    reinstate_orig_values()
    hybrid_plant.battery.gen_max_feasible = [2500] * 8760
    hybrid_plant.site.capacity_hours = [False] * 8760
    capacity_credit_battery = hybrid_plant.battery.calc_capacity_credit_percent(
        hybrid_plant.interconnect_kw)
    assert capacity_credit_battery == approx(0, rel=0.05)
    # Test when no interconnect capacity
    reinstate_orig_values()
    hybrid_plant.battery.gen_max_feasible = [2500] * 8760
    hybrid_plant.interconnect_kw = 0
    capacity_credit_battery = hybrid_plant.battery.calc_capacity_credit_percent(
        hybrid_plant.interconnect_kw)
    assert capacity_credit_battery == approx(0, rel=0.05)

    # Test integration with system simulation
    reinstate_orig_values()
    cap_payment_mw = 100000
    hybrid_plant.assign({"cp_capacity_payment_amount": [cap_payment_mw]})

    hybrid_plant.simulate()

    total_gen_max_feasible = np.array(hybrid_plant.pv.gen_max_feasible) \
                           + np.array(hybrid_plant.wind.gen_max_feasible) \
                           + np.array(hybrid_plant.battery.gen_max_feasible)
    assert sum(hybrid_plant.grid.gen_max_feasible) == approx(sum(np.minimum(hybrid_plant.grid.interconnect_kw * hybrid_plant.site.interval / 60, \
                                                                            total_gen_max_feasible)), rel=0.01)

    total_nominal_capacity = hybrid_plant.pv.calc_nominal_capacity(hybrid_plant.interconnect_kw) \
                           + hybrid_plant.wind.calc_nominal_capacity(hybrid_plant.interconnect_kw) \
                           + hybrid_plant.battery.calc_nominal_capacity(hybrid_plant.interconnect_kw)
    assert total_nominal_capacity == approx(18845.8, rel=0.01)
    assert total_nominal_capacity == approx(
        hybrid_plant.grid.hybrid_nominal_capacity, rel=0.01)

    capcred = hybrid_plant.capacity_credit_percent
    assert capcred['pv'] == approx(8.03, rel=0.05)
    assert capcred['wind'] == approx(33.25, rel=0.10)
    assert capcred['battery'] == approx(58.95, rel=0.05)
    assert capcred['hybrid'] == approx(43.88, rel=0.05)

    cp_pay = hybrid_plant.capacity_payments
    np_cap = hybrid_plant.system_nameplate_mw  # This is not the same as nominal capacity...
    assert cp_pay['pv'][1] / (np_cap['pv']) / (capcred['pv'] / 100) == approx(
        cap_payment_mw, 0.05)
    assert cp_pay['wind'][1] / (np_cap['wind']) / (capcred['wind'] /
                                                   100) == approx(
                                                       cap_payment_mw, 0.05)
    assert cp_pay['battery'][1] / (np_cap['battery']) / (capcred['battery'] /
                                                         100) == approx(
                                                             cap_payment_mw,
                                                             0.05)
    assert cp_pay['hybrid'][1] / (np_cap['hybrid']) / (capcred['hybrid'] /
                                                       100) == approx(
                                                           cap_payment_mw,
                                                           0.05)

    aeps = hybrid_plant.annual_energies
    assert aeps.pv == approx(9882421, rel=0.05)
    assert aeps.wind == approx(33637983, rel=0.05)
    assert aeps.battery == approx(-31287, rel=0.05)
    assert aeps.hybrid == approx(43489117, rel=0.05)

    npvs = hybrid_plant.net_present_values
    assert npvs.pv == approx(-565098, rel=5e-2)
    assert npvs.wind == approx(-1992106, rel=5e-2)
    assert npvs.battery == approx(-4773045, rel=5e-2)
    assert npvs.hybrid == approx(-5849767, rel=5e-2)

    taxes = hybrid_plant.federal_taxes
    assert taxes.pv[1] == approx(86826, rel=5e-2)
    assert taxes.wind[1] == approx(348124, rel=5e-2)
    assert taxes.battery[1] == approx(239607, rel=5e-2)
    assert taxes.hybrid[1] == approx(633523, rel=5e-2)

    apv = hybrid_plant.energy_purchases_values
    assert apv.pv[1] == approx(0, rel=5e-2)
    assert apv.wind[1] == approx(0, rel=5e-2)
    assert apv.battery[1] == approx(40158, rel=5e-2)
    assert apv.hybrid[1] == approx(2980, rel=5e-2)

    debt = hybrid_plant.debt_payment
    assert debt.pv[1] == approx(0, rel=5e-2)
    assert debt.wind[1] == approx(0, rel=5e-2)
    assert debt.battery[1] == approx(0, rel=5e-2)
    assert debt.hybrid[1] == approx(0, rel=5e-2)

    esv = hybrid_plant.energy_sales_values
    assert esv.pv[1] == approx(353105, rel=5e-2)
    assert esv.wind[1] == approx(956067, rel=5e-2)
    assert esv.battery[1] == approx(80449, rel=5e-2)
    assert esv.hybrid[1] == approx(1352445, rel=5e-2)

    depr = hybrid_plant.federal_depreciation_totals
    assert depr.pv[1] == approx(762811, rel=5e-2)
    assert depr.wind[1] == approx(2651114, rel=5e-2)
    assert depr.battery[1] == approx(1486921, rel=5e-2)
    assert depr.hybrid[1] == approx(4900847, rel=5e-2)

    insr = hybrid_plant.insurance_expenses
    assert insr.pv[0] == approx(0, rel=5e-2)
    assert insr.wind[0] == approx(0, rel=5e-2)
    assert insr.battery[0] == approx(0, rel=5e-2)
    assert insr.hybrid[0] == approx(0, rel=5e-2)

    om = hybrid_plant.om_total_expenses
    assert om.pv[1] == approx(74993, rel=5e-2)
    assert om.wind[1] == approx(420000, rel=5e-2)
    assert om.battery[1] == approx(75000, rel=5e-2)
    assert om.hybrid[1] == approx(569993, rel=5e-2)

    rev = hybrid_plant.total_revenues
    assert rev.pv[1] == approx(393226, rel=5e-2)
    assert rev.wind[1] == approx(1288603, rel=5e-2)
    assert rev.battery[1] == approx(375215, rel=5e-2)
    assert rev.hybrid[1] == approx(2229976, rel=5e-2)

    tc = hybrid_plant.tax_incentives
    assert tc.pv[1] == approx(1123104, rel=5e-2)
    assert tc.wind[1] == approx(504569, rel=5e-2)
    assert tc.battery[1] == approx(0, rel=5e-2)
    assert tc.hybrid[1] == approx(1646170, rel=5e-2)
Ejemplo n.º 29
0
def test_desired_schedule_dispatch():

    # Creating a contrived schedule
    daily_schedule = [interconnect_mw]*10
    daily_schedule.extend([20] * 8)
    daily_schedule.append(interconnect_mw + 5)
    daily_schedule.extend([0] * 5)
    desired_schedule = daily_schedule*365

    desired_schedule_site = SiteInfo(flatirons_site,
                                     desired_schedule=desired_schedule)
    tower_pv_battery = {key: technologies[key] for key in ('pv', 'tower', 'battery')}

    # Default case doesn't leave enough head room for battery operations
    tower_pv_battery['tower'] = {'cycle_capacity_kw': 35 * 1000,
                                 'solar_multiple': 2.0,
                                 'tes_hours': 10.0}

    tower_pv_battery['pv'] = {'system_capacity_kw': 80 * 1000}

    hybrid_plant = HybridSimulation(tower_pv_battery, desired_schedule_site, interconnect_mw * 1000,
                                    dispatch_options={'is_test_start_year': True,
                                                      'is_test_end_year': False,
                                                      'grid_charging': False,
                                                      'pv_charging_only': True,
                                                      'include_lifecycle_count': False
                                                      })
    hybrid_plant.ppa_price = (0.06, )

    # Constant price
    # hybrid_plant.site.elec_prices = [100] * hybrid_plant.site.n_timesteps
    hybrid_plant.simulate(1)

    system_generation = hybrid_plant.dispatch_builder.dispatch.system_generation
    system_load = hybrid_plant.dispatch_builder.dispatch.system_load
    electricity_sold = hybrid_plant.grid.dispatch.electricity_sold
    electricity_purchased = hybrid_plant.grid.dispatch.electricity_purchased
    gen_limit = hybrid_plant.grid.dispatch.generation_transmission_limit
    transmission_limit = hybrid_plant.grid.value('grid_interconnection_limit_kwac')

    schedule = daily_schedule*2
    # System generation does not exceed schedule limits
    for t in hybrid_plant.dispatch_builder.pyomo_model.forecast_horizon:
        assert gen_limit[t] * 1e3 <= transmission_limit
        assert system_generation[t] - system_load[t] <= schedule[t] + 1e-3
        if system_generation[t] > system_load[t]:
            assert electricity_sold[t] == pytest.approx(system_generation[t] - system_load[t], 1e-3)
            assert electricity_purchased[t] == pytest.approx(0.0, 1e-3)
        else:
            assert electricity_purchased[t] == pytest.approx(system_load[t] - system_generation[t], 1e-3)
            assert electricity_sold[t] == pytest.approx(0.0, 1e-3)

    # Battery charges and discharges
    assert sum(hybrid_plant.battery.dispatch.charge_power) > 0.0
    assert sum(hybrid_plant.battery.dispatch.discharge_power) > 0.0

    # PV can be curtailed
    assert sum(hybrid_plant.pv.dispatch.generation) <= sum(hybrid_plant.pv.dispatch.available_generation)

    # CSP can run
    assert sum(hybrid_plant.tower.dispatch.cycle_generation) > 0.0
    assert sum(hybrid_plant.tower.dispatch.receiver_thermal_power) > 0.0
Ejemplo n.º 30
0
    },
    'battery': {
        'system_capacity_kwh': battery_capacity_mw * 1000,
        'system_capacity_kw': battery_capacity_mw * 4 * 1000
    }
}

# Get resource
lat = flatirons_site['lat']
lon = flatirons_site['lon']
prices_file = examples_dir.parent / "resource_files" / "grid" / "pricing-data-2015-IronMtn-002_factors.csv"

site = SiteInfo(flatirons_site,
                grid_resource_file=prices_file)
# Create base model
hybrid_plant = HybridSimulation(technologies, site, interconnect_kw=interconnection_size_mw * 1000)

hybrid_plant.pv.dc_degradation = (0,)             # year over year degradation
hybrid_plant.wind.wake_model = 3                # constant wake loss, layout-independent
hybrid_plant.wind.value("wake_int_loss", 1)     # percent wake loss

hybrid_plant.pv.system_capacity_kw = solar_size_mw * 1000
hybrid_plant.wind.system_capacity_by_num_turbines(wind_size_mw * 1000)

# prices_file are unitless dispatch factors, so add $/kwh here
hybrid_plant.ppa_price = 0.04

# use single year for now, multiple years with battery not implemented yet
hybrid_plant.simulate(project_life=20)

print("output after losses over gross output",