Exemple #1
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)
Exemple #2
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