def test_calculation_of_lcoe_of_asset_total_flow_is_0():
    """Tests if LCOE is set to None with TOTAL_FLOW of asset is 0"""
    for group in [ENERGY_CONVERSION, ENERGY_STORAGE]:
        for asset in dict_values[group]:
            E2.lcoe_assets(dict_values[group][asset], group)
    assert dict_values[ENERGY_CONVERSION]["inverter"][LCOE_ASSET][VALUE] is 0
    assert dict_values[ENERGY_STORAGE]["battery_2"][LCOE_ASSET][VALUE] is 0
def test_calculation_of_lcoe_asset_storage_flow_not_0_provider_flow_not_0():
    """Tests whether the LCOE is correctly calculated for each asset in the different asset groups"""
    for group in [ENERGY_PRODUCTION, ENERGY_CONSUMPTION, ENERGY_STORAGE]:
        for asset in dict_values[group]:
            E2.lcoe_assets(dict_values[group][asset], group)
    assert dict_values[ENERGY_PRODUCTION]["PV"][LCOE_ASSET][
        VALUE] == exp_lcoe_pv
    assert (dict_values[ENERGY_CONSUMPTION]["demand"][LCOE_ASSET][VALUE] ==
            exp_lcoe_demand)
    assert (dict_values[ENERGY_STORAGE]["battery_1"][LCOE_ASSET][VALUE] ==
            exp_lcoe_battery_1)
    for component in [INPUT_POWER, OUTPUT_POWER, STORAGE_CAPACITY]:
        assert LCOE_ASSET in dict_values[ENERGY_STORAGE]["battery_1"][
            component]
def test_all_cost_info_parameters_added_to_dict_asset():
    """Tests whether the function get_costs is adding all the calculated costs to dict_asset."""
    E2.get_costs(dict_asset, dict_economic)

    # Note: The valid calculation of the costs is tested with test_benchmark_KPI.py, Test_Economic_KPI.test_benchmark_Economic_KPI_C2_E2()
    for k in (
            COST_DISPATCH,
            COST_OM,
            COST_TOTAL,
            COST_OPERATIONAL_TOTAL,
            ANNUITY_TOTAL,
            ANNUITY_OM,
    ):
        assert (
            k in dict_asset
        ), f"Attribute {k} is not in the asset dictionary, eventhough it should have been added."
def test_calculate_total_asset_costs_over_lifetime():
    investment_costs = 300
    om_costs = 200
    total = E2.calculate_total_asset_costs_over_lifetime(
        costs_investment=investment_costs,
        cost_operational_expenditures=om_costs)
    assert (
        total == investment_costs + om_costs
    ), f"The total costs are with {total} not equal to the sum of the investment ({investment_costs}) and OM ({om_costs}) costs."
def test_calculate_operation_and_management_expenditures():
    installed_capacity = 10
    optimized_add_capacity = 10
    specific_om_cost = 5
    operation_and_management_expenditures = E2.calculate_operation_and_management_expenditures(
        specific_om_cost=specific_om_cost,
        installed_capacity=installed_capacity,
        optimized_add_capacity=optimized_add_capacity,
    )
    assert operation_and_management_expenditures == specific_om_cost * (
        installed_capacity + optimized_add_capacity
    ), f"With {operation_and_management_expenditures}, the OM costs are not equal to the sum of the capacities ({installed_capacity+optimized_add_capacity}) times the specific costs ({specific_om_cost})."
def test_calculate_costs_replacement():
    """Tests whether replacement costs both for existing and future capacities were calculated correctly"""
    installed_capacity = 1
    specific_replacement_costs_of_installed_cap = 5
    optimized_add_capacity = 10
    specific_replacement_costs_of_optimized_cap = 10

    cost_replacement = E2.calculate_costs_replacement(
        specific_replacement_of_initial_capacity=
        specific_replacement_costs_of_installed_cap,
        specific_replacement_of_optimized_capacity=
        specific_replacement_costs_of_optimized_cap,
        initial_capacity=installed_capacity,
        optimized_capacity=optimized_add_capacity,
    )
    assert (
        cost_replacement == specific_replacement_costs_of_installed_cap *
        installed_capacity +
        specific_replacement_costs_of_optimized_cap * optimized_add_capacity
    ), f"With {cost_replacement}, the total replacement costs are not equal to the sum of the replacement costs of each pre-installed ({specific_replacement_costs_of_installed_cap * installed_capacity}) and additional capacity ({specific_replacement_costs_of_optimized_cap * optimized_add_capacity})."
def test_calculate_annual_dispatch_expenditures_pd_Series():
    dispatch_price = pd.Series([1, 2, 3])
    dispatch_expenditure = E2.calculate_dispatch_expenditures(
        dispatch_price, flow, asset)
    assert dispatch_expenditure == 6
def test_all_list_in_dict_fails_due_to_not_included_keys():
    """Tests whether looking for list items in dict_asset is plausible."""
    list_false = [AGE_INSTALLED, OPTIMIZED_ADD_CAP]
    with pytest.raises(E2.MissingParametersForEconomicEvaluation):
        boolean = E2.all_list_in_dict(dict_asset, list_false)
        assert boolean is False
def test_all_list_in_dict_passes_as_all_keys_included():
    """Tests whether looking for list items in dict_asset is plausible."""
    list_true = [ANNUAL_TOTAL_FLOW, OPTIMIZED_ADD_CAP]
    boolean = E2.all_list_in_dict(dict_asset, list_true)
    assert boolean is True
def test_calculate_annual_dispatch_expenditures_str_error():
    """Tests if a error is raised when a list with a nested list and a str value is provided as a dispatch price."""
    with pytest.raises(TypeError):
        dispatch_expenditure = E2.calculate_dispatch_expenditures(
            dispatch_price=[1, ["hi", 2]], flow=flow, asset=asset)
def test_calculate_annual_dispatch_expenditures_nested_list():
    dispatch_expenditure = E2.calculate_dispatch_expenditures(
        dispatch_price=[1, [1, 2]], flow=flow, asset=asset)
    assert (
        dispatch_expenditure == 3 + 3 + 6
    ), f"The total dispatch expenditures ({dispatch_expenditure}) are not equal to the expected value if the dispatch price is provided as a list with a nested list. "
def test_calculate_annual_dispatch_expenditures_list_pd_series():
    dispatch_expenditure = E2.calculate_dispatch_expenditures(
        dispatch_price=[1, pd.Series([1, 2, 3])], flow=flow, asset=asset)
    assert (
        dispatch_expenditure == 9
    ), f"The total dispatch expenditures ({dispatch_expenditure}) are not equal to the expected value if the dispatch price is provided as a list with a nested pd.Series. "
def test_calculate_annual_dispatch_expenditures_list_scalars():
    dispatch_expenditure = E2.calculate_dispatch_expenditures(
        dispatch_price=[1, 1], flow=flow, asset=asset)
    assert (
        dispatch_expenditure == 6
    ), f"The total dispatch expenditures ({dispatch_expenditure}) are not equal to the expected value if the dispatch price is provided as a list. "
def test_calculate_annual_dispatch_expenditures_float():
    dispatch_expenditure = E2.calculate_dispatch_expenditures(dispatch_price=1,
                                                              flow=flow,
                                                              asset=asset)
    assert dispatch_expenditure == 3
def test_calculate_total_operational_expenditures():
    total_operational_expenditures = E2.calculate_total_operational_expenditures(
        operation_and_management_expenditures=100, dispatch_expenditures=500)
    assert total_operational_expenditures == 600
def test_calculate_total_capital_costs():
    total_capital_expenditure = E2.calculate_total_capital_costs(
        upfront=300, replacement=100)
    assert total_capital_expenditure == 400
def test_calculate_costs_upfront_investment():
    costs = E2.calculate_costs_upfront_investment(specific_cost=100,
                                                  capacity=5,
                                                  development_costs=200)
    assert costs == 700
def evaluate_dict(dict_values, results_main, results_meta):
    """

    Parameters
    ----------
    dict_values: dict
        simulation parameters
    results_main: DataFrame
        oemof simulation results as output by processing.results()
    results_meta: DataFrame
        oemof simulation meta information as output by processing.meta_results()

    Returns
    -------

    """

    dict_values.update(
        {
            KPI: {
                KPI_COST_MATRIX: pd.DataFrame(columns=KPI_COST_MATRIX_ENTRIES),
                KPI_SCALAR_MATRIX: pd.DataFrame(columns=KPI_SCALAR_MATRIX_ENTRIES),
                KPI_SCALARS_DICT: {},
            }
        }
    )

    bus_data = {}
    # Store all information related to busses in bus_data
    for bus in dict_values[ENERGY_BUSSES]:
        # Read all energy flows from busses
        bus_data.update({bus: solph.views.node(results_main, bus)})

    logging.info("Evaluating optimized capacities and dispatch.")
    # Evaluate timeseries and store to a large DataFrame for each bus:
    E1.get_timeseries_per_bus(dict_values, bus_data)

    # Store all information related to storages in bus_data, as storage capacity acts as a bus
    for storage in dict_values[ENERGY_STORAGE]:
        bus_data.update(
            {
                dict_values[ENERGY_STORAGE][storage][LABEL]: solph.views.node(
                    results_main, dict_values[ENERGY_STORAGE][storage][LABEL],
                )
            }
        )
        E1.get_storage_results(
            dict_values[SIMULATION_SETTINGS],
            bus_data[dict_values[ENERGY_STORAGE][storage][LABEL]],
            dict_values[ENERGY_STORAGE][storage],
        )

        for storage_item in [STORAGE_CAPACITY, INPUT_POWER, OUTPUT_POWER]:
            E2.get_costs(
                dict_values[ENERGY_STORAGE][storage][storage_item],
                dict_values[ECONOMIC_DATA],
            )

        E2.lcoe_assets(dict_values[ENERGY_STORAGE][storage], ENERGY_STORAGE)
        for storage_item in [STORAGE_CAPACITY, INPUT_POWER, OUTPUT_POWER]:
            store_result_matrix(
                dict_values[KPI], dict_values[ENERGY_STORAGE][storage][storage_item]
            )

        if (
            dict_values[ENERGY_STORAGE][storage][INPUT_BUS_NAME]
            in dict_values[OPTIMIZED_FLOWS].keys()
        ) or (
            dict_values[ENERGY_STORAGE][storage][OUTPUT_BUS_NAME]
            in dict_values[OPTIMIZED_FLOWS].keys()
        ):
            bus_name = dict_values[ENERGY_STORAGE][storage][INPUT_BUS_NAME]
            timeseries_name = (
                dict_values[ENERGY_STORAGE][storage][LABEL]
                + " ("
                + str(
                    round(
                        dict_values[ENERGY_STORAGE][storage][STORAGE_CAPACITY][
                            OPTIMIZED_ADD_CAP
                        ][VALUE],
                        1,
                    )
                )
                + dict_values[ENERGY_STORAGE][storage][STORAGE_CAPACITY][
                    OPTIMIZED_ADD_CAP
                ][UNIT]
                + ") SOC"
            )

            dict_values[OPTIMIZED_FLOWS][bus_name][timeseries_name] = dict_values[
                ENERGY_STORAGE
            ][storage]["timeseries_soc"]

    for group in [ENERGY_CONVERSION, ENERGY_PRODUCTION, ENERGY_CONSUMPTION]:
        for asset in dict_values[group]:
            E1.get_results(
                settings=dict_values[SIMULATION_SETTINGS],
                bus_data=bus_data,
                dict_asset=dict_values[group][asset],
                asset_group=group,
            )
            E2.get_costs(dict_values[group][asset], dict_values[ECONOMIC_DATA])
            E2.lcoe_assets(dict_values[group][asset], group)
            store_result_matrix(dict_values[KPI], dict_values[group][asset])

    logging.info("Evaluating key performance indicators of the system")
    E3.all_totals(dict_values)
    E3.total_demand_and_excess_each_sector(dict_values)
    E3.add_total_feedin_electricity_equivaluent(dict_values)
    E3.add_levelized_cost_of_energy_carriers(dict_values)
    E3.add_total_renewable_and_non_renewable_energy_origin(dict_values)
    E3.add_renewable_share_of_local_generation(dict_values)
    E3.add_renewable_factor(dict_values)
    # E3.add_degree_of_sector_coupling(dict_values) feature not finished
    E3.add_onsite_energy_fraction(dict_values)
    E3.add_onsite_energy_matching(dict_values)
    E3.add_degree_of_autonomy(dict_values)

    # Tests and checks
    logging.info("Running validity checks.")
    E4.minimal_renewable_share_test(dict_values)
    E4.detect_excessive_excess_generation_in_bus(dict_values)
def test_calculate_annual_dispatch_expenditures_else():
    """Test if error is raised if the dispatch price is provided as a str."""
    with pytest.raises(TypeError):
        E2.calculate_dispatch_expenditures("str", flow, asset)