import copy
import logging
import os
import shutil

from copy import deepcopy
from zipfile import ZipFile

import numpy as np
import pandas as pd
import pytest

from matplotlib import pyplot as plt
from pandas.testing import assert_frame_equal, assert_series_equal
from shapely.geometry import Point

from edisgo import EDisGo
from edisgo.edisgo import import_edisgo_from_files
from edisgo.flex_opt.reinforce_grid import enhanced_reinforce_grid
from edisgo.network.results import Results


class TestEDisGo:
    @pytest.fixture(autouse=True)
    def setup_fixture(self):
        """
        Fixture to set up new EDisGo object before each test function.

        """
        self.setup_edisgo_object()

    def setup_edisgo_object(self):
        self.edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_path)

    def setup_worst_case_time_series(self):
        self.edisgo.set_time_series_worst_case_analysis()

    def test_config_setter(self):
        save_dir = os.path.join(os.getcwd(), "config_dir")

        # test default
        config_orig = copy.deepcopy(self.edisgo.config)
        self.edisgo.config = {}
        assert config_orig._data == self.edisgo.config._data

        # test specifying different directory
        self.edisgo.config = {"config_path": save_dir}
        assert len(os.listdir(save_dir)) == 5
        shutil.rmtree(save_dir)

        # test json and config_path=None
        # save changed config to json
        self.edisgo.config["geo"]["srid"] = 2
        config_json = copy.deepcopy(self.edisgo.config)
        self.edisgo.save(
            save_dir,
            save_topology=False,
            save_timeseries=False,
            save_results=False,
            save_electromobility=False,
        )
        # overwrite config with config_path=None and check
        self.edisgo.config = {"config_path": save_dir}
        assert config_orig._data == self.edisgo.config._data
        # overwrite config from json and check
        self.edisgo.config = {"from_json": True, "config_path": save_dir}
        assert config_json._data == self.edisgo.config._data

        # delete directory
        shutil.rmtree(save_dir)

    def test_set_time_series_manual(self, caplog):
        timeindex = pd.date_range("1/1/2018", periods=3, freq="H")
        gens_ts = pd.DataFrame(
            data={
                "GeneratorFluctuating_15": [2.0, 5.0, 6.0],
                "GeneratorFluctuating_24": [4.0, 7.0, 8.0],
            },
            index=timeindex,
        )
        loads_ts = pd.DataFrame(
            data={
                "Load_residential_LVGrid_5_3": [2.0, 5.0, 6.0],
            },
            index=timeindex,
        )
        storage_units_ts = pd.DataFrame(
            data={
                "Storage_1": [4.0, 7.0, 8.0],
            },
            index=timeindex,
        )

        # test setting some time series and with no time index being previously set
        with caplog.at_level(logging.WARNING):
            self.edisgo.set_time_series_manual(
                generators_p=gens_ts,
                generators_q=gens_ts,
                loads_p=loads_ts,
                storage_units_q=storage_units_ts,
            )
        assert (
            "When setting time series manually a time index is not automatically "
            "set" in caplog.text
        )
        assert self.edisgo.timeseries.generators_active_power.shape == (0, 2)
        self.edisgo.set_timeindex(timeindex)
        assert_frame_equal(gens_ts, self.edisgo.timeseries.generators_active_power)
        assert_frame_equal(gens_ts, self.edisgo.timeseries.generators_reactive_power)
        assert_frame_equal(loads_ts, self.edisgo.timeseries.loads_active_power)
        assert self.edisgo.timeseries.loads_reactive_power.empty
        assert self.edisgo.timeseries.storage_units_active_power.empty
        assert_frame_equal(
            storage_units_ts, self.edisgo.timeseries.storage_units_reactive_power
        )

        # test overwriting time series and with some components that do not exist
        timeindex2 = pd.date_range("1/1/2018", periods=4, freq="H")
        gens_ts2 = pd.DataFrame(
            data={
                "GeneratorFluctuating_15": [1.0, 2.0, 5.0, 6.0],
                "GeneratorFluctuating_14": [5.0, 2.0, 5.0, 6.0],
                "GeneratorFluctuating_x": [8.0, 4.0, 7.0, 8.0],
            },
            index=timeindex2,
        )
        loads_ts2 = pd.DataFrame(
            data={
                "Load_residential_LVGrid_5_3": [2.0, 5.0, 6.0],
                "Load_residential_LVGrid_x": [2.0, 5.0, 6.0],
            },
            index=timeindex,
        )
        self.edisgo.set_time_series_manual(
            generators_p=gens_ts2, loads_p=loads_ts2, storage_units_p=storage_units_ts
        )
        assert self.edisgo.timeseries.generators_active_power.shape == (3, 3)
        assert_frame_equal(
            gens_ts2.loc[
                timeindex, ["GeneratorFluctuating_15", "GeneratorFluctuating_14"]
            ],
            self.edisgo.timeseries.generators_active_power.loc[
                :, ["GeneratorFluctuating_15", "GeneratorFluctuating_14"]
            ],
        )
        assert_frame_equal(
            gens_ts.loc[:, ["GeneratorFluctuating_24"]],
            self.edisgo.timeseries.generators_active_power.loc[
                :, ["GeneratorFluctuating_24"]
            ],
        )
        assert_frame_equal(gens_ts, self.edisgo.timeseries.generators_reactive_power)
        assert_frame_equal(
            loads_ts2.loc[:, ["Load_residential_LVGrid_5_3"]],
            self.edisgo.timeseries.loads_active_power.loc[
                :, ["Load_residential_LVGrid_5_3"]
            ],
        )
        assert self.edisgo.timeseries.loads_reactive_power.empty
        assert_frame_equal(
            storage_units_ts, self.edisgo.timeseries.storage_units_active_power
        )
        assert_frame_equal(
            storage_units_ts, self.edisgo.timeseries.storage_units_reactive_power
        )

    def test_set_time_series_worst_case_analysis(self):
        self.edisgo.set_time_series_worst_case_analysis(
            cases="load_case", generators_names=["Generator_1"], loads_names=[]
        )
        assert self.edisgo.timeseries.generators_active_power.shape == (2, 1)
        assert self.edisgo.timeseries.generators_reactive_power.shape == (2, 1)
        assert self.edisgo.timeseries.loads_active_power.shape == (2, 0)
        assert self.edisgo.timeseries.loads_reactive_power.shape == (2, 0)
        assert self.edisgo.timeseries.storage_units_active_power.shape == (2, 1)
        assert self.edisgo.timeseries.storage_units_reactive_power.shape == (2, 1)

        self.edisgo.set_time_series_worst_case_analysis()
        assert self.edisgo.timeseries.generators_active_power.shape == (
            4,
            len(self.edisgo.topology.generators_df),
        )
        assert self.edisgo.timeseries.generators_reactive_power.shape == (
            4,
            len(self.edisgo.topology.generators_df),
        )
        assert self.edisgo.timeseries.loads_active_power.shape == (
            4,
            len(self.edisgo.topology.loads_df),
        )
        assert self.edisgo.timeseries.loads_reactive_power.shape == (
            4,
            len(self.edisgo.topology.loads_df),
        )
        assert self.edisgo.timeseries.storage_units_active_power.shape == (
            4,
            len(self.edisgo.topology.storage_units_df),
        )
        assert self.edisgo.timeseries.storage_units_reactive_power.shape == (
            4,
            len(self.edisgo.topology.storage_units_df),
        )

    def test_set_time_series_active_power_predefined(self, caplog):
        # options where database connection is needed are tested in separate function

        # check warning
        self.edisgo.set_time_series_active_power_predefined()
        assert (
            "When setting time series using predefined profiles it is better"
            in caplog.text
        )

        # check if right functions are called
        timeindex = pd.date_range("1/1/2011 12:00", periods=2, freq="H")
        self.edisgo.timeseries.timeindex = timeindex
        ts_fluc = pd.DataFrame(
            data={
                "wind": [5, 6],
            },
            index=timeindex,
        )
        ts_disp = pd.DataFrame(
            data={
                "other": [5, 6],
            },
            index=timeindex,
        )
        ts_cp = pd.DataFrame(
            data={
                "hpc": [5, 6],
            },
            index=timeindex,
        )
        self.edisgo.topology._loads_df.loc[
            "Load_residential_LVGrid_1_4", ["type", "sector"]
        ] = ("charging_point", "hpc")

        self.edisgo.set_time_series_active_power_predefined(
            fluctuating_generators_ts=ts_fluc,
            fluctuating_generators_names=["GeneratorFluctuating_8"],
            dispatchable_generators_ts=ts_disp,
            dispatchable_generators_names=["Generator_1"],
            conventional_loads_ts="demandlib",
            conventional_loads_names=[
                "Load_residential_LVGrid_3_2",
                "Load_residential_LVGrid_3_3",
            ],
            charging_points_ts=ts_cp,
            charging_points_names=None,
        )

        assert self.edisgo.timeseries.generators_active_power.shape == (2, 2)
        assert self.edisgo.timeseries.generators_reactive_power.shape == (2, 0)
        assert self.edisgo.timeseries.loads_active_power.shape == (2, 3)
        assert self.edisgo.timeseries.loads_reactive_power.shape == (2, 0)
        assert self.edisgo.timeseries.storage_units_active_power.shape == (2, 0)
        assert self.edisgo.timeseries.storage_units_reactive_power.shape == (2, 0)

    def test_set_time_series_active_power_predefined_oedb(self):
        # test conventional_loads_ts="oedb" for all loads in grid
        edisgo_object = EDisGo(
            ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False
        )
        edisgo_object.set_timeindex(pd.date_range("1/1/2011", periods=8760, freq="H"))
        edisgo_object.set_time_series_active_power_predefined(
            conventional_loads_ts="oedb",
            fluctuating_generators_ts="oedb",
            scenario="eGon2035",
            engine=pytest.engine,
            timeindex=pd.date_range("1/1/2011 12:00", periods=2, freq="H"),
            conventional_loads_names=[
                "Load_mvgd_33535_lvgd_1164210000_244_residential"
            ],
        )

        assert edisgo_object.timeseries.loads_active_power.dropna().shape == (
            2,
            1,
        )
        fluctuating_gens = edisgo_object.topology.generators_df[
            edisgo_object.topology.generators_df.type.isin(["wind", "solar"])
        ]
        assert edisgo_object.timeseries.generators_active_power.dropna().shape == (
            2,
            len(fluctuating_gens),
        )

    def test_set_time_series_reactive_power_control(self):
        # set active power time series for fixed cosphi
        timeindex = pd.date_range("1/1/1970", periods=3, freq="H")
        self.edisgo.set_timeindex(timeindex)
        ts_solar = np.array([0.1, 0.2, 0.3])
        ts_wind = [0.4, 0.5, 0.6]
        self.edisgo.set_time_series_active_power_predefined(
            fluctuating_generators_ts=pd.DataFrame(
                {"solar": ts_solar, "wind": ts_wind}, index=timeindex
            ),
            dispatchable_generators_ts=pd.DataFrame(
                {"other": ts_solar}, index=timeindex
            ),
            conventional_loads_ts="demandlib",
        )

        # test only setting reactive power for one generator
        gen = "GeneratorFluctuating_4"  # solar MV generator
        self.edisgo.set_time_series_reactive_power_control(
            generators_parametrisation=pd.DataFrame(
                {
                    "components": [[gen]],
                    "mode": ["default"],
                    "power_factor": ["default"],
                },
                index=[1],
            ),
            loads_parametrisation=None,
            storage_units_parametrisation=None,
        )
        assert self.edisgo.timeseries.generators_reactive_power.shape == (3, 1)
        assert self.edisgo.timeseries.loads_reactive_power.empty
        assert self.edisgo.timeseries.storage_units_reactive_power.empty
        assert (
            np.isclose(
                self.edisgo.timeseries.generators_reactive_power.loc[:, gen],
                ts_solar * -np.tan(np.arccos(0.9)) * 1.93,
            )
        ).all()

        # test changing only configuration of one load
        load = "Load_residential_LVGrid_1_5"
        self.edisgo.set_time_series_reactive_power_control(
            loads_parametrisation=pd.DataFrame(
                {
                    "components": [
                        [load],
                        self.edisgo.topology.loads_df.index.drop([load]),
                    ],
                    "mode": ["capacitive", "default"],
                    "power_factor": [0.98, "default"],
                },
                index=[1, 2],
            ),
            storage_units_parametrisation=None,
        )
        assert self.edisgo.timeseries.generators_reactive_power.shape == (3, 28)
        assert self.edisgo.timeseries.loads_reactive_power.shape == (3, 50)
        assert (
            np.isclose(
                self.edisgo.timeseries.loads_reactive_power.loc[:, load],
                self.edisgo.timeseries.loads_active_power.loc[:, load]
                * -np.tan(np.arccos(0.98)),
            )
        ).all()

    def test_to_pypsa(self):
        self.setup_worst_case_time_series()

        # test mode None and timesteps None (default)
        pypsa_network = self.edisgo.to_pypsa()
        assert len(pypsa_network.buses) == 142
        assert len(pypsa_network.buses_t.v_mag_pu_set) == 4

        # test mode "mv" and timesteps given
        pypsa_network = self.edisgo.to_pypsa(
            mode="mv", timesteps=self.edisgo.timeseries.timeindex[0]
        )
        assert len(pypsa_network.buses) == 31
        assert len(pypsa_network.buses_t.v_mag_pu_set) == 1

        # test exception
        msg = "Provide proper mode or leave it empty to export entire network topology."
        with pytest.raises(ValueError, match=msg):
            self.edisgo.to_pypsa(mode="unknown")

    def test_to_graph(self):
        graph = self.edisgo.to_graph()
        assert len(graph.nodes) == len(self.edisgo.topology.buses_df)
        assert len(graph.edges) == (
            len(self.edisgo.topology.lines_df)
            + len(self.edisgo.topology.transformers_df.bus0.unique())
        )

    @pytest.mark.slow
    def test_generator_import(self):
        edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_2_path)
        edisgo.import_generators("nep2035")
        assert len(edisgo.topology.generators_df) == 524

    def test_analyze(self, caplog):
        self.setup_worst_case_time_series()

        # test mode None and timesteps None (default)
        self.edisgo.analyze()
        results_analyze = deepcopy(self.edisgo.results)
        assert self.edisgo.results.v_res.shape == (4, 142)

        # test mode "mv" and timesteps given
        self.edisgo.analyze(mode="mv", timesteps=self.edisgo.timeseries.timeindex[0])
        assert self.edisgo.results.v_res.shape == (1, 31)

        # test mode "lv"
        self.edisgo.analyze(mode="lv", lv_grid_id=1)
        assert self.edisgo.results.v_res.shape == (4, 15)

        # test troubleshooting_mode "lpf"
        self.edisgo.analyze(troubleshooting_mode="lpf")
        assert self.edisgo.results.v_res.shape == (4, 142)
        assert self.edisgo.results.equality_check(results_analyze)

        # test mode None and troubleshooting_mode "iteration"
        self.edisgo.analyze(troubleshooting_mode="iteration")
        assert self.edisgo.results.v_res.shape == (4, 142)
        assert self.edisgo.results.equality_check(results_analyze)

        # test non convergence
        msg = "Power flow analysis did not converge for the"
        with pytest.raises(ValueError, match=msg):
            self.edisgo.analyze(troubleshooting_mode="iteration", range_start=5)

        caplog.clear()
        with caplog.at_level("INFO"):
            self.edisgo.analyze(
                troubleshooting_mode="iteration",
                range_start=5,
                range_num=2,
                raise_not_converged=False,
            )
        assert "Current fraction in iterative process: 5.0." in caplog.text
        assert "Current fraction in iterative process: 1.0." in caplog.text

    def test_reinforce(self):
        # ToDo add tests to check content of equipment_changes
        # ###################### test with default settings ##########################
        self.setup_worst_case_time_series()
        results = self.edisgo.reinforce()
        assert results.unresolved_issues.empty
        assert len(results.grid_expansion_costs) == 10
        assert len(results.equipment_changes) == 10
        assert results.v_res.shape == (4, 142)
        assert self.edisgo.results.v_res.shape == (4, 142)

        # ###################### test without worst case settings ####################
        self.setup_worst_case_time_series()
        results = self.edisgo.reinforce(is_worst_case=False)
        assert results.unresolved_issues.empty
        assert len(results.grid_expansion_costs) == 10
        assert len(results.equipment_changes) == 10
        assert results.v_res.shape == (4, 142)
        assert self.edisgo.results.v_res.shape == (4, 142)

        # ###################### test mode mv and copy grid ##########################
        self.setup_edisgo_object()
        self.setup_worst_case_time_series()
        results = self.edisgo.reinforce(mode="mv", copy_grid=True)
        assert results.unresolved_issues.empty
        assert len(results.grid_expansion_costs) == 4
        assert len(results.equipment_changes) == 4
        assert results.v_res.shape == (4, 31)
        assert self.edisgo.results.v_res.empty

        # ###################### test mode lv and copy grid ##########################
        results = self.edisgo.reinforce(mode="lv", copy_grid=True)
        assert results.unresolved_issues.empty
        assert len(results.grid_expansion_costs) == 6
        assert len(results.equipment_changes) == 6
        assert results.v_res.shape == (4, 142)
        assert self.edisgo.results.v_res.empty

        # ################# test mode mvlv and combined analysis ####################
        results = self.edisgo.reinforce(
            mode="mvlv", combined_analysis=False, is_worst_case=True
        )
        assert results.unresolved_issues.empty
        assert len(results.grid_expansion_costs) == 4
        assert len(results.equipment_changes) == 4
        assert results.v_res.shape == (4, 41)

        # ###################### test with only one lv grid ##########################
        # test grid without issues
        self.edisgo.results = Results(self.edisgo)
        lv_grid_id = 1
        results = self.edisgo.reinforce(mode="lv", lv_grid_id=lv_grid_id)
        assert results.unresolved_issues.empty
        assert results.equipment_changes.empty
        assert results.v_res.shape == (4, 15)
        # test grid with issues
        lv_grid_id = 5
        results = self.edisgo.reinforce(mode="lv", lv_grid_id=lv_grid_id)
        assert len(results.grid_expansion_costs) == 1
        assert len(results.equipment_changes) == 1
        assert results.v_res.shape == (4, 9)

    def test_reinforce_catch_convergence(self):
        # ###################### test that wrong mode is raised ######################
        msg = "Provided mode mvl is not a valid mode."
        with pytest.raises(ValueError, match=msg):
            self.edisgo.reinforce(
                catch_convergence_problems=True, is_worst_case=False, mode="mvl"
            )

        # ###################### test with catch convergence ##########################
        self.setup_worst_case_time_series()
        self.edisgo.timeseries.scale_timeseries(
            p_scaling_factor=10, q_scaling_factor=10
        )
        results = self.edisgo.reinforce(
            catch_convergence_problems=True,
            is_worst_case=False,
            copy_grid=True,
        )
        assert results.unresolved_issues.empty
        assert len(results.grid_expansion_costs) == 134
        assert len(results.equipment_changes) == 230
        assert results.v_res.shape == (4, 142)

        # ############### test with catch convergence worst case true ################
        self.setup_worst_case_time_series()
        self.edisgo.timeseries.scale_timeseries(
            p_scaling_factor=10, q_scaling_factor=10
        )
        results = self.edisgo.reinforce(catch_convergence_problems=True)
        assert results.unresolved_issues.empty
        assert len(results.grid_expansion_costs) == 134
        assert len(results.equipment_changes) == 218
        assert results.v_res.shape == (4, 142)

    @pytest.mark.slow
    def test_enhanced_reinforce_grid(self):
        self.setup_edisgo_object()

        self.setup_worst_case_time_series()
        self.edisgo.timeseries.scale_timeseries(
            p_scaling_factor=50, q_scaling_factor=50
        )

        edisgo_obj = copy.deepcopy(self.edisgo)
        edisgo_obj = enhanced_reinforce_grid(
            edisgo_obj,
            activate_cost_results_disturbing_mode=True,
            separate_lv_grids=False,
        )

        results = edisgo_obj.results

        assert len(results.grid_expansion_costs) == 454
        assert len(results.equipment_changes) == 892
        assert results.v_res.shape == (4, 148)

        edisgo_obj = copy.deepcopy(self.edisgo)
        edisgo_obj = enhanced_reinforce_grid(
            edisgo_obj,
            reduced_analysis=True,
            is_worst_case=False,
            separate_lv_grids=True,
            num_steps_loading=1,
            num_steps_voltage=1,
        )
        assert edisgo_obj.results.v_res.shape == (2, 162)

    def test_add_component(self, caplog):
        self.setup_worst_case_time_series()
        index = self.edisgo.timeseries.timeindex
        dummy_ts = pd.Series(data=[0.1, 0.2, 0.1, 0.2], index=index)

        # Test add bus
        num_buses = len(self.edisgo.topology.buses_df)
        bus_name = self.edisgo.add_component(
            comp_type="bus", bus_name="Testbus", v_nom=20
        )
        assert bus_name == "Testbus"
        assert len(self.edisgo.topology.buses_df) == num_buses + 1
        assert self.edisgo.topology.buses_df.loc["Testbus", "v_nom"] == 20

        # Test add line
        num_lines = len(self.edisgo.topology.lines_df)
        line_name = self.edisgo.add_component(
            comp_type="line",
            bus0="Bus_MVStation_1",
            bus1="Testbus",
            length=0.001,
            type_info="NA2XS2Y 3x1x185 RM/25",
        )
        assert line_name == "Line_Bus_MVStation_1_Testbus"
        assert len(self.edisgo.topology.lines_df) == num_lines + 1
        assert self.edisgo.topology.lines_df.loc[line_name, "bus0"] == "Bus_MVStation_1"
        assert self.edisgo.topology.lines_df.loc[line_name, "bus1"] == "Testbus"
        assert self.edisgo.topology.lines_df.loc[line_name, "length"] == 0.001

        # Test add load (with time series)
        num_loads = len(self.edisgo.topology.loads_df)
        load_name = self.edisgo.add_component(
            comp_type="load",
            type="conventional_load",
            load_id=4,
            bus="Testbus",
            p_set=0.2,
            annual_consumption=3.2,
            sector="residential",
            ts_active_power=dummy_ts,
            ts_reactive_power=dummy_ts,
        )
        assert load_name == "Conventional_Load_MVGrid_1_residential_4"
        assert len(self.edisgo.topology.loads_df) == num_loads + 1
        assert self.edisgo.topology.loads_df.loc[load_name, "bus"] == "Testbus"
        assert self.edisgo.topology.loads_df.loc[load_name, "p_set"] == 0.2
        assert self.edisgo.topology.loads_df.loc[load_name, "annual_consumption"] == 3.2
        assert self.edisgo.topology.loads_df.loc[load_name, "sector"] == "residential"
        assert (
            self.edisgo.timeseries.loads_active_power.loc[:, load_name] == dummy_ts
        ).all()
        assert (
            self.edisgo.timeseries.loads_reactive_power.loc[:, load_name] == dummy_ts
        ).all()

        # Test add load (with reactive power time series default mode)
        load_name = self.edisgo.add_component(
            comp_type="load",
            type="conventional_load",
            load_id=4,
            bus="Testbus",
            p_set=0.2,
            annual_consumption=3.2,
            sector="residential",
            ts_active_power=dummy_ts,
            ts_reactive_power="default",
        )
        assert (
            self.edisgo.timeseries.loads_active_power.loc[:, load_name] == dummy_ts
        ).all()
        assert (
            self.edisgo.timeseries.loads_reactive_power.loc[:, load_name]
            == dummy_ts * np.tan(np.arccos(0.9))
        ).all()
        # check that reactive power time series were not all set to default
        assert (
            self.edisgo.timeseries.loads_active_power.loc[
                :, "Conventional_Load_MVGrid_1_residential_4"
            ]
            == dummy_ts
        ).all()

        # Test add generator (without time series)
        num_gens = len(self.edisgo.topology.generators_df)
        gen_name = self.edisgo.add_component(
            "generator",
            generator_id=5,
            bus="Testbus",
            p_nom=2.5,
            generator_type="solar",
        )
        assert gen_name == "Generator_MVGrid_1_solar_5"
        assert len(self.edisgo.topology.generators_df) == num_gens + 1
        assert self.edisgo.topology.generators_df.loc[gen_name, "bus"] == "Testbus"
        assert self.edisgo.topology.generators_df.loc[gen_name, "p_nom"] == 2.5
        assert self.edisgo.topology.generators_df.loc[gen_name, "type"] == "solar"
        assert self.edisgo.timeseries.generators_active_power.shape == (4, num_gens)
        assert self.edisgo.timeseries.generators_reactive_power.shape == (4, num_gens)

        # Test add generator (test that warning is raised when no active power time
        # series is provided for default mode)
        gen_name = self.edisgo.add_component(
            "generator",
            generator_id=5,
            bus="Testbus",
            p_nom=2.5,
            generator_type="solar",
            ts_reactive_power="default",
        )
        assert (
            f"Default reactive power time series of {gen_name} cannot be set as "
            f"active power time series was not provided." in caplog.text
        )

        # Test add generator (with reactive power time series default mode)
        gen_name = self.edisgo.add_component(
            "generator",
            generator_id=5,
            bus="Testbus",
            p_nom=2.5,
            generator_type="solar",
            ts_active_power=dummy_ts,
            ts_reactive_power="default",
        )
        assert (
            self.edisgo.timeseries.generators_reactive_power.loc[:, gen_name]
            == dummy_ts * -np.tan(np.arccos(0.9))
        ).all()

        # Test add storage unit
        num_storages = len(self.edisgo.topology.storage_units_df)
        storage_name = self.edisgo.add_component(
            comp_type="storage_unit", bus="Testbus", p_nom=3.1, add_ts=False
        )
        assert storage_name == "StorageUnit_MVGrid_1_2"
        assert len(self.edisgo.topology.storage_units_df) == num_storages + 1
        assert (
            self.edisgo.topology.storage_units_df.loc[storage_name, "bus"] == "Testbus"
        )
        assert self.edisgo.topology.storage_units_df.loc[storage_name, "p_nom"] == 3.1

    def test_integrate_component_based_on_geolocation(self):
        self.setup_worst_case_time_series()

        num_gens = len(self.edisgo.topology.generators_df)

        random_bus = "Bus_BranchTee_MVGrid_1_1"
        x = self.edisgo.topology.buses_df.at[random_bus, "x"]
        y = self.edisgo.topology.buses_df.at[random_bus, "y"]
        geom = Point((x, y))

        # ##### MV integration
        # test generator integration by voltage level, geom as tuple, without
        # time series
        comp_data = {
            "generator_id": 13,
            "p_nom": 4,
            "generator_type": "misc",
            "subtype": "misc_sub",
        }
        comp_name = self.edisgo.integrate_component_based_on_geolocation(
            comp_type="generator",
            geolocation=(x, y),
            voltage_level=4,
            add_ts=False,
            **comp_data,
        )

        assert len(self.edisgo.topology.generators_df) == num_gens + 1
        assert self.edisgo.topology.generators_df.at[comp_name, "subtype"] == "misc_sub"
        # check that generator is directly connected to HV/MV station
        assert (
            self.edisgo.topology.get_connected_lines_from_bus(
                self.edisgo.topology.generators_df.at[comp_name, "bus"]
            ).bus0[0]
            == "Bus_MVStation_1"
        )

        # test charging point integration by nominal power, geom as shapely
        # Point, with time series
        num_cps = len(self.edisgo.topology.charging_points_df)

        comp_data = {"p_set": 4, "sector": "fast"}
        dummy_ts = pd.Series(
            data=[0.1, 0.2, 0.1, 0.2], index=self.edisgo.timeseries.timeindex
        )
        ts_active_power = dummy_ts
        ts_reactive_power = dummy_ts

        comp_name = self.edisgo.integrate_component_based_on_geolocation(
            comp_type="charging_point",
            geolocation=geom,
            ts_active_power=ts_active_power,
            ts_reactive_power=ts_reactive_power,
            **comp_data,
        )

        assert len(self.edisgo.topology.charging_points_df) == num_cps + 1
        assert self.edisgo.topology.charging_points_df.at[comp_name, "sector"] == "fast"
        # check voltage level
        assert (
            self.edisgo.topology.buses_df.at[
                self.edisgo.topology.charging_points_df.at[comp_name, "bus"],
                "v_nom",
            ]
            == 20
        )
        # check that charging point is connected to the random bus chosen
        # above
        assert (
            self.edisgo.topology.get_connected_lines_from_bus(
                self.edisgo.topology.charging_points_df.at[comp_name, "bus"]
            ).bus0[0]
            == random_bus
        )
        # check time series
        assert (
            self.edisgo.timeseries.loads_active_power.loc[:, comp_name].values
            == [0.1, 0.2, 0.1, 0.2]
        ).all()
        assert (
            self.edisgo.timeseries.loads_reactive_power.loc[:, comp_name].values
            == [0.1, 0.2, 0.1, 0.2]
        ).all()

        # test heat pump integration by nominal power, geom as shapely
        # Point, with time series
        num_loads = len(self.edisgo.topology.loads_df)

        comp_data = {"p_set": 2.5}
        dummy_ts = pd.Series(
            data=[0.1, 0.2, 0.1, 0.2], index=self.edisgo.timeseries.timeindex
        )
        ts_active_power = dummy_ts
        ts_reactive_power = dummy_ts

        comp_name = self.edisgo.integrate_component_based_on_geolocation(
            comp_type="heat_pump",
            geolocation=geom,
            ts_active_power=ts_active_power,
            ts_reactive_power=ts_reactive_power,
            **comp_data,
        )

        assert len(self.edisgo.topology.loads_df) == num_loads + 1
        assert self.edisgo.topology.loads_df.at[comp_name, "type"] == "heat_pump"
        # check voltage level
        bus = self.edisgo.topology.loads_df.at[comp_name, "bus"]
        assert (
            self.edisgo.topology.buses_df.at[
                bus,
                "v_nom",
            ]
            == 20
        )
        # check that charging point is connected to the random bus chosen
        # above
        assert (
            self.edisgo.topology.get_connected_lines_from_bus(bus).bus0[0] == random_bus
        )
        # check time series
        assert (
            self.edisgo.timeseries.loads_active_power.loc[:, comp_name].values
            == [0.1, 0.2, 0.1, 0.2]
        ).all()
        assert (
            self.edisgo.timeseries.loads_reactive_power.loc[:, comp_name].values
            == [0.1, 0.2, 0.1, 0.2]
        ).all()

        # ##### LV integration

        # test charging point integration by nominal power, geom as shapely
        # Point, with time series
        comp_data = {"number": 13, "p_set": 0.04, "sector": "fast"}
        comp_name = self.edisgo.integrate_component_based_on_geolocation(
            comp_type="charging_point",
            geolocation=geom,
            ts_active_power=ts_active_power,
            ts_reactive_power=ts_reactive_power,
            **comp_data,
        )

        assert len(self.edisgo.topology.loads_df) == num_loads + 2
        assert self.edisgo.topology.charging_points_df.at[comp_name, "number"] == 13
        # check bus
        assert (
            self.edisgo.topology.charging_points_df.at[comp_name, "bus"]
            == "Bus_BranchTee_LVGrid_1_7"
        )
        # check time series
        assert (
            self.edisgo.timeseries.loads_active_power.loc[:, comp_name].values
            == [0.1, 0.2, 0.1, 0.2]
        ).all()
        assert (
            self.edisgo.timeseries.loads_reactive_power.loc[:, comp_name].values
            == [0.1, 0.2, 0.1, 0.2]
        ).all()

        # test heat pump integration by voltage level, geom as shapely
        # Point, without time series
        comp_data = {
            "voltage_level": 7,
            "sector": "individual_heating",
            "p_set": 0.2,
            "mvlv_subst_id": 3.0,
        }
        x = self.edisgo.topology.buses_df.at["Bus_GeneratorFluctuating_6", "x"]
        y = self.edisgo.topology.buses_df.at["Bus_GeneratorFluctuating_6", "y"]
        geom = Point((x, y))
        comp_name = self.edisgo.integrate_component_based_on_geolocation(
            comp_type="heat_pump",
            geolocation=geom,
            add_ts=False,
            **comp_data,
        )

        assert len(self.edisgo.topology.loads_df) == num_loads + 3
        assert (
            self.edisgo.topology.loads_df.at[comp_name, "sector"]
            == "individual_heating"
        )
        # check bus
        assert (
            self.edisgo.topology.loads_df.at[comp_name, "bus"]
            == "Bus_BranchTee_LVGrid_3_2"
        )

    def test_remove_component(self):
        self.setup_worst_case_time_series()

        # Test remove bus (where bus cannot be removed, because load is still connected)
        num_buses = len(self.edisgo.topology.buses_df)
        self.edisgo.remove_component(
            comp_type="bus", comp_name="Bus_BranchTee_LVGrid_2_2"
        )
        assert len(self.edisgo.topology.buses_df) == num_buses
        assert "Bus_BranchTee_LVGrid_2_2" in self.edisgo.topology.buses_df.index

        # Test remove load (with time series)
        num_loads = len(self.edisgo.topology.loads_df)
        load_name = "Load_residential_LVGrid_1_6"
        self.edisgo.remove_component(
            comp_type="load",
            comp_name=load_name,
        )
        assert len(self.edisgo.topology.loads_df) == num_loads - 1
        assert load_name not in self.edisgo.timeseries.loads_active_power.columns
        assert load_name not in self.edisgo.timeseries.loads_reactive_power.columns

        # Test remove line
        num_lines = len(self.edisgo.topology.lines_df)
        self.edisgo.remove_component(comp_type="line", comp_name="Line_20000002")
        assert len(self.edisgo.topology.lines_df) == num_lines

        # Test remove generator (without time series)
        num_gens = len(self.edisgo.topology.generators_df)
        self.edisgo.remove_component(
            "generator", comp_name="GeneratorFluctuating_10", drop_ts=False
        )
        assert len(self.edisgo.topology.generators_df) == num_gens - 1
        assert self.edisgo.timeseries.generators_active_power.shape == (4, num_gens)
        assert self.edisgo.timeseries.generators_reactive_power.shape == (4, num_gens)

        # Test remove storage unit (with time series)
        num_storages = len(self.edisgo.topology.storage_units_df)
        self.edisgo.remove_component(comp_type="storage_unit", comp_name="Storage_1")
        assert len(self.edisgo.topology.storage_units_df) == num_storages - 1
        assert load_name not in self.edisgo.timeseries.loads_active_power.columns
        assert load_name not in self.edisgo.timeseries.loads_reactive_power.columns

    def test_aggregate_components(self):
        self.setup_worst_case_time_series()

        # ##### test without any aggregation

        self.edisgo.topology._loads_df.at[
            "Load_residential_LVGrid_1_4", "bus"
        ] = "Bus_BranchTee_LVGrid_1_10"

        # save original values
        number_gens_before = len(self.edisgo.topology.generators_df)
        number_loads_before = len(self.edisgo.topology.loads_df)

        self.edisgo.aggregate_components(
            aggregate_generators_by_cols=[], aggregate_loads_by_cols=[]
        )

        assert number_gens_before == len(self.edisgo.topology.generators_df)
        assert number_loads_before == len(self.edisgo.topology.loads_df)

        # ##### test default (aggregate by bus only) - same EDisGo object as above
        # is used

        # save original values
        gens_p_nom_before = self.edisgo.topology.generators_df.p_nom.sum()
        loads_p_set_before = self.edisgo.topology.loads_df.p_set.sum()
        gens_feedin_before = self.edisgo.timeseries.generators_active_power.sum().sum()
        gens_feedin_reactive_before = (
            self.edisgo.timeseries.generators_reactive_power.sum().sum()
        )
        loads_demand_before = self.edisgo.timeseries.loads_active_power.sum().sum()
        loads_demand_reactive_before = (
            self.edisgo.timeseries.loads_reactive_power.sum().sum()
        )
        num_gens_before = len(self.edisgo.topology.generators_df)
        num_loads_before = len(self.edisgo.topology.loads_df)
        feedin_before = (
            self.edisgo.timeseries.generators_active_power.loc[
                :, ["GeneratorFluctuating_13", "GeneratorFluctuating_14"]
            ]
            .sum()
            .sum()
        )
        load_before = (
            self.edisgo.timeseries.loads_active_power.loc[
                :,
                ["Load_residential_LVGrid_1_5", "Load_residential_LVGrid_1_4"],
            ]
            .sum()
            .sum()
        )

        self.edisgo.aggregate_components()

        # test that total p_nom and total feed-in/demand stayed the same
        assert np.isclose(
            gens_p_nom_before, self.edisgo.topology.generators_df.p_nom.sum()
        )
        assert np.isclose(
            gens_feedin_before,
            self.edisgo.timeseries.generators_active_power.sum().sum(),
        )
        assert np.isclose(
            gens_feedin_reactive_before,
            self.edisgo.timeseries.generators_reactive_power.sum().sum(),
        )
        assert np.isclose(loads_p_set_before, self.edisgo.topology.loads_df.p_set.sum())
        assert np.isclose(
            loads_demand_before,
            self.edisgo.timeseries.loads_active_power.sum().sum(),
        )
        assert np.isclose(
            loads_demand_reactive_before,
            self.edisgo.timeseries.loads_reactive_power.sum().sum(),
        )
        # test that two generators and two loads were aggregated
        assert num_gens_before - 4 == len(self.edisgo.topology.generators_df)
        assert (
            self.edisgo.topology.generators_df.at[
                "Generators_Bus_BranchTee_LVGrid_1_14", "p_nom"
            ]
            == 0.034
        )
        assert (
            self.edisgo.timeseries.generators_active_power.loc[
                :, "Generators_Bus_BranchTee_LVGrid_1_14"
            ].sum()
            == feedin_before
        )
        assert num_loads_before - 1 == len(self.edisgo.topology.loads_df)
        assert self.edisgo.topology.loads_df.at[
            "Loads_Bus_BranchTee_LVGrid_1_10", "p_set"
        ] == (2 * 0.001397)
        assert (
            self.edisgo.timeseries.loads_active_power.loc[
                :, "Loads_Bus_BranchTee_LVGrid_1_10"
            ].sum()
            == load_before
        )
        # test that analyze does not fail
        self.edisgo.analyze()

        # ##### test with charging points, aggregation of loads by bus, type and sector
        # and aggregation of generators only by bus

        # reset EDisGo object
        self.setup_edisgo_object()
        self.setup_worst_case_time_series()

        # add charging point
        self.edisgo.add_component(
            comp_type="load",
            ts_active_power=pd.Series(
                data=[0.1, 0.2, 0.1, 0.2], index=self.edisgo.timeseries.timeindex
            ),
            ts_reactive_power=pd.Series(
                data=[0, 0, 0, 0], index=self.edisgo.timeseries.timeindex
            ),
            bus="Bus_BranchTee_LVGrid_1_10",
            type="charging_point",
            sector="home",
            p_set=0.2,
        )
        # manipulate grid so that more than one load of the same sector is
        # connected at the same bus
        self.edisgo.topology._loads_df.at[
            "Load_residential_LVGrid_1_4", "bus"
        ] = "Bus_BranchTee_LVGrid_1_10"

        # save original values (only loads, as generators did not change)
        loads_p_set_before = self.edisgo.topology.loads_df.p_set.sum()
        loads_demand_before = self.edisgo.timeseries.loads_active_power.sum().sum()
        loads_demand_reactive_before = (
            self.edisgo.timeseries.loads_reactive_power.sum().sum()
        )
        num_loads_before = len(self.edisgo.topology.loads_df)

        self.edisgo.aggregate_components(
            aggregate_loads_by_cols=["bus", "type", "sector"],
            aggregate_generators_by_cols=["bus"],
        )

        # test that total p_nom and total feed-in/demand stayed the same
        assert np.isclose(
            gens_p_nom_before, self.edisgo.topology.generators_df.p_nom.sum()
        )
        assert np.isclose(
            gens_feedin_before,
            self.edisgo.timeseries.generators_active_power.sum().sum(),
        )
        assert np.isclose(
            gens_feedin_reactive_before,
            self.edisgo.timeseries.generators_reactive_power.sum().sum(),
        )
        assert np.isclose(
            loads_p_set_before,
            self.edisgo.topology.loads_df.p_set.sum(),
        )
        assert np.isclose(
            loads_demand_before,
            self.edisgo.timeseries.loads_active_power.sum().sum(),
        )
        assert np.isclose(
            loads_demand_reactive_before,
            self.edisgo.timeseries.loads_reactive_power.sum().sum(),
        )
        charging_points_df = self.edisgo.topology.charging_points_df
        assert np.isclose(0.2, charging_points_df.p_set.sum())
        assert np.isclose(
            0.6,
            self.edisgo.timeseries.loads_active_power.loc[:, charging_points_df.index]
            .sum()
            .sum(),
        )
        assert np.isclose(
            0,
            self.edisgo.timeseries.loads_reactive_power.loc[:, charging_points_df.index]
            .sum()
            .sum(),
        )
        # test that generators were aggregated
        assert num_gens_before - 4 == len(self.edisgo.topology.generators_df)
        # test that two loads were aggregated and that charging point was not aggregated
        # with load
        assert num_loads_before - 1 == len(self.edisgo.topology.loads_df)
        assert self.edisgo.topology.loads_df.at[
            "Loads_Bus_BranchTee_LVGrid_1_10_conventional_load_residential", "p_set"
        ] == (2 * 0.001397)
        assert (
            self.edisgo.timeseries.loads_active_power.loc[
                :, "Loads_Bus_BranchTee_LVGrid_1_10_conventional_load_residential"
            ].sum()
            == load_before
        )

        # test that analyze does not fail
        self.edisgo.analyze()

        # #### test without aggregation of loads and aggregation of generators
        # by bus and type

        # reset EDisGo object
        self.setup_edisgo_object()
        self.setup_worst_case_time_series()

        # manipulate grid so that two generators of different types are
        # connected at the same bus
        self.edisgo.topology._generators_df.at[
            "GeneratorFluctuating_13", "type"
        ] = "misc"

        # save original values (values of loads were changed in previous aggregation)
        loads_p_set_before = self.edisgo.topology.loads_df.p_set.sum()
        loads_demand_before = self.edisgo.timeseries.loads_active_power.sum().sum()
        loads_demand_reactive_before = (
            self.edisgo.timeseries.loads_reactive_power.sum().sum()
        )
        num_loads_before = len(self.edisgo.topology.loads_df)

        self.edisgo.aggregate_components(
            aggregate_generators_by_cols=["bus", "type"], aggregate_loads_by_cols=[]
        )
        # test that total p_nom and total feed-in/demand stayed the same
        assert np.isclose(
            gens_p_nom_before, self.edisgo.topology.generators_df.p_nom.sum()
        )
        assert np.isclose(
            gens_feedin_before,
            self.edisgo.timeseries.generators_active_power.sum().sum(),
        )
        assert np.isclose(
            gens_feedin_reactive_before,
            self.edisgo.timeseries.generators_reactive_power.sum().sum(),
        )
        assert np.isclose(loads_p_set_before, self.edisgo.topology.loads_df.p_set.sum())
        assert np.isclose(
            loads_demand_before,
            self.edisgo.timeseries.loads_active_power.sum().sum(),
        )
        assert np.isclose(
            loads_demand_reactive_before,
            self.edisgo.timeseries.loads_reactive_power.sum().sum(),
        )
        # test that generators at the same bus were aggregated and loads stayed the same
        assert num_gens_before - 3 == len(self.edisgo.topology.generators_df)
        assert num_loads_before == len(self.edisgo.topology.loads_df)

        # test that analyze does not fail
        self.edisgo.analyze()

    def test_import_electromobility(self):
        """
        Test import from directories.
        """
        self.edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_2_path)

        # test with default parameters
        simbev_path = pytest.simbev_example_scenario_path
        tracbev_path = pytest.tracbev_example_scenario_path
        self.edisgo.import_electromobility(
            data_source="directory",
            charging_processes_dir=simbev_path,
            potential_charging_points_dir=tracbev_path,
        )

        assert len(self.edisgo.electromobility.charging_processes_df) == 48
        assert len(self.edisgo.electromobility.potential_charging_parks_gdf) == 1621
        assert self.edisgo.electromobility.eta_charging_points == 0.9

        total_charging_demand_at_charging_parks = sum(
            cp.charging_processes_df.chargingdemand_kWh.sum()
            for cp in list(self.edisgo.electromobility.potential_charging_parks)
            if cp.designated_charging_point_capacity > 0
        )
        total_charging_demand = (
            self.edisgo.electromobility.charging_processes_df.chargingdemand_kWh.sum()
        )
        assert np.isclose(
            total_charging_demand_at_charging_parks, total_charging_demand
        )

        # fmt: off
        charging_park_ids = (
            self.edisgo.electromobility.charging_processes_df.charging_park_id.
            sort_values().unique()
        )
        potential_charging_parks_with_capacity = np.sort(
            [
                cp.id
                for cp in list(self.edisgo.electromobility.potential_charging_parks)
                if cp.designated_charging_point_capacity > 0.0
            ]
        )
        # fmt: on

        assert set(charging_park_ids) == set(potential_charging_parks_with_capacity)

        assert len(self.edisgo.electromobility.integrated_charging_parks_df) == 3

        # fmt: off
        assert set(
            self.edisgo.electromobility.integrated_charging_parks_df.edisgo_id.
            sort_values().values
        ) == set(
            self.edisgo.topology.loads_df[
                self.edisgo.topology.loads_df.type == "charging_point"
            ]
            .index.sort_values()
            .values
        )
        # fmt: on

        # test with kwargs
        self.edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_2_path)
        self.edisgo.import_electromobility(
            data_source="directory",
            charging_processes_dir=simbev_path,
            potential_charging_points_dir=tracbev_path,
            import_electromobility_data_kwds={"mode_parking_times": "not_frugal"},
            allocate_charging_demand_kwds={"mode": "grid_friendly"},
        )

        # Length of charging_processes_df, potential_charging_parks_gdf and
        # integrated_charging_parks_df changed compared to test without kwargs
        # TODO: needs to be checked if that is correct
        assert len(self.edisgo.electromobility.charging_processes_df) == 427
        assert len(self.edisgo.electromobility.potential_charging_parks_gdf) == 1621
        assert self.edisgo.electromobility.simulated_days == 7

        assert np.isclose(
            total_charging_demand,
            self.edisgo.electromobility.charging_processes_df.chargingdemand_kWh.sum(),
        )

        # fmt: off
        charging_park_ids = (
            self.edisgo.electromobility.charging_processes_df.charging_park_id.dropna(
            ).unique()
        )
        # fmt: on

        potential_charging_parks_with_capacity = np.sort(
            [
                cp.id
                for cp in list(self.edisgo.electromobility.potential_charging_parks)
                if cp.designated_charging_point_capacity > 0.0
            ]
        )
        assert set(charging_park_ids) == set(potential_charging_parks_with_capacity)

        assert len(self.edisgo.electromobility.integrated_charging_parks_df) == 3

        # fmt: off
        assert set(
            self.edisgo.electromobility.integrated_charging_parks_df.edisgo_id.
            sort_values().values
        ) == set(
            self.edisgo.topology.loads_df[
                self.edisgo.topology.loads_df.type == "charging_point"
            ]
            .index.sort_values()
            .values
        )
        # fmt: on

    def test_import_electromobility_oedb(self):
        """
        Test import from oedb.
        """
        self.edisgo = EDisGo(
            ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False
        )

        # test with default parameters
        self.edisgo.import_electromobility(
            data_source="oedb", scenario="eGon2035", engine=pytest.engine
        )

        assert len(self.edisgo.electromobility.charging_processes_df) == 324117
        assert self.edisgo.electromobility.eta_charging_points == 0.9

        total_charging_demand_at_charging_parks = sum(
            cp.charging_processes_df.chargingdemand_kWh.sum()
            for cp in list(self.edisgo.electromobility.potential_charging_parks)
            if cp.designated_charging_point_capacity > 0
        )
        total_charging_demand = (
            self.edisgo.electromobility.charging_processes_df.chargingdemand_kWh.sum()
        )
        assert np.isclose(
            total_charging_demand_at_charging_parks, total_charging_demand
        )

        # fmt: off
        charging_park_ids = (
            self.edisgo.electromobility.charging_processes_df.charging_park_id.
            sort_values().unique()
        )
        potential_charging_parks_with_capacity = np.sort(
            [
                cp.id
                for cp in list(self.edisgo.electromobility.potential_charging_parks)
                if cp.designated_charging_point_capacity > 0.0
            ]
        )
        # fmt: on

        assert set(charging_park_ids) == set(potential_charging_parks_with_capacity)

        # fmt: off
        assert set(
            self.edisgo.electromobility.integrated_charging_parks_df.edisgo_id.
            sort_values().values
        ) == set(
            self.edisgo.topology.loads_df[
                self.edisgo.topology.loads_df.type == "charging_point"
            ]
            .index.sort_values()
            .values
        )
        # fmt: on

    @pytest.mark.oedbtest
    def test_import_heat_pumps(self):
        edisgo_object = EDisGo(
            ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False
        )

        # ################# test with wrong scenario name #############
        with pytest.raises(ValueError):
            edisgo_object.import_heat_pumps(
                scenario="eGon",
                engine=pytest.engine,
            )

        # ################# test with leap year #############
        edisgo_object.import_heat_pumps(
            scenario="eGon2035",
            engine=pytest.engine,
            timeindex=pd.date_range("1/1/2020", periods=2, freq="H"),
            import_types=["individual_heat_pumps", "central_heat_pumps"],
        )

        loads_df = edisgo_object.topology.loads_df
        hp_df = loads_df[loads_df.type == "heat_pump"]
        assert len(hp_df) == 151
        assert edisgo_object.heat_pump.heat_demand_df.shape == (8760, 151)
        assert edisgo_object.heat_pump.heat_demand_df.index[0].year == 2035
        assert edisgo_object.heat_pump.cop_df.shape == (8760, 151)
        assert edisgo_object.heat_pump.cop_df.index[0].year == 2035

    def test_apply_charging_strategy(self):
        self.edisgo_obj = EDisGo(ding0_grid=pytest.ding0_test_network_2_path)
        timeindex = pd.date_range("1/1/2011", periods=24 * 7, freq="H")
        self.edisgo_obj.set_timeindex(timeindex)

        self.edisgo_obj.resample_timeseries()
        # test with default parameters
        simbev_path = pytest.simbev_example_scenario_path
        tracbev_path = pytest.tracbev_example_scenario_path
        self.edisgo_obj.import_electromobility(
            data_source="directory",
            charging_processes_dir=simbev_path,
            potential_charging_points_dir=tracbev_path,
        )
        self.edisgo_obj.apply_charging_strategy()

        # Check if all charging points have a valid chargingdemand_kWh > 0
        cps = self.edisgo_obj.topology.loads_df[
            self.edisgo_obj.topology.loads_df.type == "charging_point"
        ].index
        ts = self.edisgo_obj.timeseries.loads_active_power.loc[:, cps]
        df = ts.loc[:, (ts <= 0).any(axis=0)]
        assert df.shape == ts.shape

    def test_plot_mv_grid_topology(self):
        plt.ion()
        self.edisgo.plot_mv_grid_topology(technologies=True)
        plt.close("all")
        self.edisgo.plot_mv_grid_topology()
        plt.close("all")

    def test_plot_mv_voltages(self):
        self.setup_worst_case_time_series()
        plt.ion()
        self.edisgo.analyze()
        self.edisgo.plot_mv_voltages()
        plt.close("all")

    def test_plot_mv_line_loading(self):
        self.setup_worst_case_time_series()
        plt.ion()
        self.edisgo.analyze()
        self.edisgo.plot_mv_line_loading()
        plt.close("all")
        self.edisgo.plot_mv_line_loading(timestep=self.edisgo.timeseries.timeindex[0])
        plt.close("all")

    def test_plot_mv_grid_expansion_costs(self):
        # test with storage
        self.setup_worst_case_time_series()
        plt.ion()
        self.edisgo.reinforce()
        self.edisgo.plot_mv_grid_expansion_costs()
        plt.close("all")

        # test without storage
        self.setup_edisgo_object()
        self.edisgo.remove_component("storage_unit", "Storage_1", False)
        self.setup_worst_case_time_series()
        plt.ion()
        self.edisgo.reinforce()
        self.edisgo.plot_mv_grid_expansion_costs()
        plt.close("all")

    def test_plot_mv_storage_integration(self):
        plt.ion()
        storage_1 = self.edisgo.topology.add_storage_unit(
            "Bus_BranchTee_MVGrid_1_8", 0.3
        )
        storage_2 = self.edisgo.topology.add_storage_unit(
            "Bus_BranchTee_MVGrid_1_8", 0.6
        )
        storage_3 = self.edisgo.topology.add_storage_unit(
            "Bus_BranchTee_MVGrid_1_10", 0.3
        )
        self.edisgo.plot_mv_storage_integration()
        plt.close("all")
        self.edisgo.topology.remove_storage_unit(storage_1)
        self.edisgo.topology.remove_storage_unit(storage_2)
        self.edisgo.topology.remove_storage_unit(storage_3)

    def test_histogramm_voltage(self):
        self.setup_worst_case_time_series()
        plt.ion()
        self.edisgo.analyze()
        self.edisgo.histogram_voltage()
        plt.close("all")

    def test_histogramm_relative_line_load(self):
        self.setup_worst_case_time_series()
        plt.ion()
        self.edisgo.analyze()
        self.edisgo.histogram_relative_line_load()
        plt.close("all")

    def test_save(self):
        self.setup_worst_case_time_series()
        save_dir = os.path.join(os.getcwd(), "edisgo_network")

        # add heat pump, electromobility, overlying grid and dsm dummy data
        self.edisgo.heat_pump.cop = pd.DataFrame(
            data={
                "hp1": [5.0, 6.0, 5.0, 6.0],
                "hp2": [7.0, 8.0, 7.0, 8.0],
            },
            index=self.edisgo.timeseries.timeindex,
        )
        self.edisgo.electromobility.charging_processes_df = pd.DataFrame(
            data={
                "ags": [5.0, 6.0],
                "car_id": [7.0, 8.0],
            },
            index=[0, 1],
        )
        self.edisgo.electromobility.potential_charging_parks_gdf = pd.DataFrame(
            data={
                "ags": [5.0, 6.0],
                "car_id": [7.0, 8.0],
            },
            index=[0, 1],
        )
        self.edisgo.overlying_grid.dsm_active_power = pd.Series(
            data=[2.4], index=[self.edisgo.timeseries.timeindex[0]]
        )
        self.edisgo.overlying_grid.feedin_district_heating = pd.DataFrame(
            {"dh1": [1.4, 2.3], "dh2": [2.4, 1.3]},
            index=self.edisgo.timeseries.timeindex[0:2],
        )
        self.edisgo.dsm.p_max = pd.DataFrame(
            data={
                "load_1": [5.0, 6.0],
                "load_2": [7.0, 8.0],
            },
            index=self.edisgo.timeseries.timeindex[0:2],
        )

        # ################### test with default parameters ###################
        self.edisgo.save(save_dir)

        # check that sub-directories are created
        dirs_in_save_dir = os.listdir(save_dir)
        assert len(dirs_in_save_dir) == 4
        assert "configs.json" in dirs_in_save_dir

        shutil.rmtree(save_dir)

        # ############## test with saving additional data #############
        self.edisgo.save(
            save_dir,
            save_electromobility=True,
            save_heatpump=True,
            save_overlying_grid=True,
            save_dsm=True,
            electromobility_attributes=["charging_processes_df"],
        )

        # check that sub-directories are created
        dirs_in_save_dir = os.listdir(save_dir)
        assert len(dirs_in_save_dir) == 8
        assert "electromobility" in dirs_in_save_dir
        assert "overlying_grid" in dirs_in_save_dir

        shutil.rmtree(save_dir)

        # ############## test with archiving ##############
        self.edisgo.save(
            save_dir, archive=True, save_electromobility=True, save_overlying_grid=True
        )
        zip_file = os.path.join(os.path.dirname(save_dir), "edisgo_network.zip")
        assert os.path.exists(zip_file)

        zip = ZipFile(zip_file)
        files = zip.namelist()
        zip.close()
        assert len(files) == 28

        os.remove(zip_file)

    def test_reduce_memory(self):
        # set up test data
        self.setup_worst_case_time_series()
        self.edisgo.analyze()
        timeindex = pd.date_range("1/1/2011 12:00", periods=2, freq="H")
        self.edisgo.heat_pump.heat_demand_df = pd.DataFrame(
            data={
                "hp1": [1.0, 2.0],
                "hp2": [3.0, 4.0],
            },
            index=timeindex,
        )
        og = self.edisgo.overlying_grid
        og.dsm_active_power = pd.Series(
            data=[2.4], index=[self.edisgo.timeseries.timeindex[0]]
        )
        og.feedin_district_heating = pd.DataFrame(
            {"dh1": [1.4, 2.3], "dh2": [2.4, 1.3]},
            index=self.edisgo.timeseries.timeindex[0:2],
        )

        # check one attribute from each class
        mem_ts_before = self.edisgo.timeseries.generators_active_power.memory_usage(
            deep=True
        ).sum()
        mem_res_before = self.edisgo.results.pfa_p.memory_usage(deep=True).sum()
        mem_hp_before = self.edisgo.heat_pump.heat_demand_df.memory_usage(
            deep=True
        ).sum()
        mem_og_before = og.feedin_district_heating.memory_usage(deep=True).sum()

        # check with default value
        self.edisgo.reduce_memory()

        mem_ts_with_default = (
            self.edisgo.timeseries.generators_active_power.memory_usage(deep=True).sum()
        )
        mem_res_with_default = self.edisgo.results.pfa_p.memory_usage(deep=True).sum()
        mem_hp_with_default = self.edisgo.heat_pump.heat_demand_df.memory_usage(
            deep=True
        ).sum()
        mem_og_with_default = og.feedin_district_heating.memory_usage(deep=True).sum()

        assert mem_ts_before > mem_ts_with_default
        assert mem_res_before > mem_res_with_default
        assert mem_hp_before > mem_hp_with_default
        assert mem_og_before > mem_og_with_default

        mem_ts_with_default_2 = self.edisgo.timeseries.loads_active_power.memory_usage(
            deep=True
        ).sum()
        mem_res_with_default_2 = self.edisgo.results.i_res.memory_usage(deep=True).sum()
        mem_og_with_default_2 = og.dsm_active_power.memory_usage(deep=True)

        # check passing kwargs
        self.edisgo.reduce_memory(
            to_type="float16",
            results_attr_to_reduce=["pfa_p"],
            timeseries_attr_to_reduce=["generators_active_power"],
            overlying_grid_attr_to_reduce=["feedin_district_heating"],
        )

        assert (
            mem_ts_with_default
            > self.edisgo.timeseries.generators_active_power.memory_usage(
                deep=True
            ).sum()
        )
        assert (
            mem_res_with_default
            > self.edisgo.results.pfa_p.memory_usage(deep=True).sum()
        )
        assert (
            mem_og_with_default
            > og.feedin_district_heating.memory_usage(deep=True).sum()
        )
        # check that i_res, loads_active_power and dsm_active_power were not reduced
        assert np.isclose(
            mem_ts_with_default_2,
            self.edisgo.timeseries.loads_active_power.memory_usage(deep=True).sum(),
        )
        assert np.isclose(
            mem_res_with_default_2,
            self.edisgo.results.i_res.memory_usage(deep=True).sum(),
        )
        assert np.isclose(
            mem_og_with_default_2,
            og.dsm_active_power.memory_usage(deep=True),
        )

    def test_spatial_complexity_reduction(self):
        # test with copying edisgo object
        (
            edisgo_obj,
            busmap_df,
            linemap_df,
        ) = self.edisgo.spatial_complexity_reduction(
            copy_edisgo=True,
            mode="kmeans",
            cluster_area="grid",
            reduction_factor=0.2,
            reduction_factor_not_focused=False,
        )
        # check for deterministic behaviour
        assert len(self.edisgo.topology.buses_df) != len(edisgo_obj.topology.buses_df)
        assert len(self.edisgo.topology.loads_df) == len(edisgo_obj.topology.loads_df)
        assert len(self.edisgo.topology.generators_df) == len(
            edisgo_obj.topology.generators_df
        )
        assert len(set(busmap_df["new_bus"].to_list())) == 32
        assert len(edisgo_obj.topology.buses_df) == 32
        assert len(set(linemap_df["new_line_name"].to_list())) == 23
        assert len(edisgo_obj.topology.lines_df) == 23

        # test without copying edisgo object
        edisgo_orig = copy.deepcopy(self.edisgo)
        (
            _,
            busmap_df,
            linemap_df,
        ) = self.edisgo.spatial_complexity_reduction(
            mode="kmeans",
            cluster_area="grid",
            reduction_factor=0.2,
            reduction_factor_not_focused=False,
            aggregation_mode=True,
            mv_pseudo_coordinates=True,
        )
        # Check for deterministic behaviour
        assert len(self.edisgo.topology.buses_df) == len(edisgo_obj.topology.buses_df)
        assert len(edisgo_orig.topology.loads_df) != len(self.edisgo.topology.loads_df)
        assert len(edisgo_orig.topology.generators_df) != len(
            self.edisgo.topology.generators_df
        )
        assert len(self.edisgo.topology.loads_df) == 28
        assert len(self.edisgo.topology.generators_df) == 17
        assert len(set(busmap_df["new_bus"].to_list())) == 32
        assert len(set(linemap_df["new_line_name"].to_list())) == 21

    def test_check_integrity(self, caplog):
        self.edisgo.check_integrity()
        assert (
            "The following generators are missing in generators_active_power: "
            "{}".format(self.edisgo.topology.generators_df.index.values) in caplog.text
        )
        assert (
            "The following generators are missing in generators_reactive_power: "
            "{}".format(self.edisgo.topology.generators_df.index.values) in caplog.text
        )
        assert (
            "The following loads are missing in loads_active_power: "
            "{}".format(self.edisgo.topology.loads_df.index.values) in caplog.text
        )
        assert (
            "The following loads are missing in loads_reactive_power: "
            "{}".format(self.edisgo.topology.loads_df.index.values) in caplog.text
        )
        assert (
            "The following storage_units are missing in storage_units_active_power"
            ": {}".format(self.edisgo.topology.storage_units_df.index.values)
            in caplog.text
        )
        assert (
            "The following storage_units are missing in storage_units_reactive_power"
            ": {}".format(self.edisgo.topology.storage_units_df.index.values)
            in caplog.text
        )
        caplog.clear()

        # ########################### check time series ##############################
        # set timeseries
        index = pd.date_range("1/1/2018", periods=3, freq="H")
        ts_gens = pd.DataFrame(
            index=index, columns=self.edisgo.topology.generators_df.index, data=0
        )
        ts_loads = pd.DataFrame(
            index=index, columns=self.edisgo.topology.loads_df.index, data=0
        )
        ts_stor = pd.DataFrame(
            index=index, columns=self.edisgo.topology.storage_units_df.index, data=0
        )
        self.edisgo.timeseries.timeindex = index
        self.edisgo.timeseries.generators_active_power = ts_gens
        self.edisgo.timeseries.generators_reactive_power = ts_gens
        self.edisgo.timeseries.loads_active_power = ts_loads
        self.edisgo.timeseries.loads_reactive_power = ts_loads
        self.edisgo.timeseries.storage_units_active_power = ts_stor
        self.edisgo.timeseries.storage_units_reactive_power = ts_stor
        # check that time series warnings are not raised anymore
        self.edisgo.check_integrity()
        assert len(caplog.records) == 1
        assert "There are lines with very short line lengths" in caplog.text
        manipulated_comps = {
            "generators": ["Generator_1", "GeneratorFluctuating_4"],
            "loads": ["Load_agricultural_LVGrid_1_3"],
            "storage_units": ["Storage_1"],
        }
        for comp_type, comp_names in manipulated_comps.items():
            comps = getattr(self.edisgo.topology, comp_type + "_df")
            # remove timeseries of single components and check for warning
            for ts_type in ["active_power", "reactive_power"]:
                comp_ts_tmp = getattr(
                    self.edisgo.timeseries, "_".join([comp_type, ts_type])
                )
                setattr(
                    self.edisgo.timeseries,
                    "_".join([comp_type, ts_type]),
                    comp_ts_tmp.drop(columns=comp_names),
                )
                self.edisgo.check_integrity()
                assert (
                    "The following {type} are missing in {ts}: {comps}".format(
                        type=comp_type,
                        ts="_".join([comp_type, ts_type]),
                        comps=str(comp_names).replace(",", ""),
                    )
                    in caplog.text
                )
                setattr(
                    self.edisgo.timeseries, "_".join([comp_type, ts_type]), comp_ts_tmp
                )
                caplog.clear()
            # remove topology entries for single components and check for warning
            setattr(self.edisgo.topology, comp_type + "_df", comps.drop(comp_names))
            self.edisgo.check_integrity()
            for ts_type in ["active_power", "reactive_power"]:
                assert (
                    "The following {type} have entries in {type}_{ts_type}, but not "
                    "in {top}: {comps}".format(
                        type=comp_type,
                        top=comp_type + "_df",
                        comps=str(comp_names).replace(",", ""),
                        ts_type=ts_type,
                    )
                    in caplog.text
                )
            caplog.clear()
            setattr(self.edisgo.topology, comp_type + "_df", comps)
            # set values higher than nominal power for single components and check for
            # warning
            comp_ts_tmp = getattr(
                self.edisgo.timeseries, "_".join([comp_type, "active_power"])
            )
            comp_ts_tmp_adapted = comp_ts_tmp.copy()
            comp_ts_tmp_adapted.loc[index[2], comp_names] = 100
            setattr(
                self.edisgo.timeseries,
                "_".join([comp_type, "active_power"]),
                comp_ts_tmp_adapted,
            )
            self.edisgo.check_integrity()
            if comp_type in ["generators", "storage_units"]:
                attr = "p_nom"
            else:
                attr = "p_set"
            assert (
                "Values of active power in the timeseries object exceed {} for "
                "the following {}: {}".format(
                    attr, comp_type, str(comp_names).replace(",", "")
                )
                in caplog.text
            )
            setattr(
                self.edisgo.timeseries,
                "_".join([comp_type, "active_power"]),
                comp_ts_tmp,
            )
            caplog.clear()

        # ########################### check electromobility ##########################
        # test electromobility time index not matching
        # set up valid flexibility bands
        timeindex = pd.date_range("1/1/1970", periods=6, freq="30min")
        flex_bands = {}
        flex_bands["upper_power"] = pd.DataFrame(
            data={
                "CP1": [0.0, 12.0, 12.0, 12.0, 12.0, 0.0],
                "CP2": [3.0, 3.0, 0.0, 0.0, 3.0, 3.0],
            },
            index=timeindex,
        )
        flex_bands["upper_energy"] = pd.DataFrame(
            data={
                "CP1": [0.0, 6.0, 12.0, 12.0, 12.0, 12.0],
                "CP2": [1.5, 2.0, 2.0, 2.0, 3.5, 4.0],
            },
            index=timeindex,
        )
        flex_bands["lower_energy"] = pd.DataFrame(
            data={
                "CP1": [0.0, 0.0, 0.0, 6.0, 12.0, 12.0],
                "CP2": [0.5, 2.0, 2.0, 2.0, 2.5, 4.0],
            },
            index=timeindex,
        )
        self.edisgo.electromobility.flexibility_bands = flex_bands
        self.edisgo.electromobility.simbev_config_df = pd.DataFrame(
            data={"eta_cp": [1.0]}, index=[0]
        )
        self.edisgo.check_integrity()
        assert (
            "There are time steps in timeindex of TimeSeries object that are not in "
            "the index of Electromobility.flexibility_bands" in caplog.text
        )

        # check electromobility upper energy band lower than lower energy band
        # modify flex band such that error is raised
        self.edisgo.electromobility.flexibility_bands["upper_energy"].at[
            timeindex[1], "CP2"
        ] = 1.0
        msg = "Lower energy band is higher than upper energy band for the "
        with pytest.raises(ValueError, match=msg):
            self.edisgo.check_integrity()

        # reset values
        caplog.clear()
        self.edisgo.electromobility.flexibility_bands["upper_energy"].at[
            timeindex[1], "CP2"
        ] = 2.0

        # ########################### check time index ##########################
        # test heat pump, overlying grid and dsm time index not matching
        # (electromobility is checked above)
        timeindex = pd.date_range("1/1/2011 12:00", periods=2, freq="H")
        self.edisgo.heat_pump.cop_df = pd.DataFrame(
            data={"hp1": [5.0, 6.0], "hp2": [7.0, 8.0]},
            index=timeindex,
        )
        self.edisgo.overlying_grid.dsm_active_power = pd.DataFrame(
            {"dh1": [1.4, 2.3], "dh2": [2.4, 1.3]}, index=timeindex
        )
        self.edisgo.dsm.p_max = pd.DataFrame(
            data={"load_1": [5.0, 6.0], "load_2": [7.0, 8.0]},
            index=self.edisgo.timeseries.timeindex[0:2],
        )
        self.edisgo.check_integrity()
        assert (
            "There are time steps in timeindex of TimeSeries object that are not in "
            "the index of OverlyingGrid.dsm_active_power" in caplog.text
        )
        assert (
            "There are time steps in timeindex of TimeSeries object that are not in "
            "the index of HeatPump.cop_df" in caplog.text
        )
        assert (
            "There are time steps in timeindex of TimeSeries object that are not in "
            "the index of DSM.p_max" in caplog.text
        )

    def test_resample_timeseries(self):
        self.setup_worst_case_time_series()
        self.edisgo.resample_timeseries()
        assert len(self.edisgo.timeseries.loads_active_power) == 16

        self.edisgo.heat_pump.cop_df = pd.DataFrame(
            data={
                "hp1": [5.0, 6.0],
                "hp2": [7.0, 8.0],
            },
            index=pd.date_range("1/1/2011 12:00", periods=2, freq="H"),
        )
        self.edisgo.resample_timeseries(freq="30min")
        assert len(self.edisgo.timeseries.loads_active_power) == 8
        assert len(self.edisgo.heat_pump.cop_df) == 4


class TestEDisGoFunc:
    def test_import_edisgo_from_files(self):
        edisgo_obj = EDisGo(ding0_grid=pytest.ding0_test_network_path)
        edisgo_obj.set_time_series_worst_case_analysis()
        edisgo_obj.analyze()
        save_dir = os.path.join(os.getcwd(), "edisgo_network")

        # add heat pump, electromobility, overlying grid dummy data
        edisgo_obj.heat_pump.cop = pd.DataFrame(
            data={
                "hp1": [5.0, 6.0, 5.0, 6.0],
                "hp2": [7.0, 8.0, 7.0, 8.0],
            },
            index=edisgo_obj.timeseries.timeindex,
        )
        edisgo_obj.electromobility.charging_processes_df = pd.DataFrame(
            data={
                "ags": [5.0, 6.0],
                "car_id": [7.0, 8.0],
            },
            index=[0, 1],
        )
        flex_bands = {
            "upper_energy": pd.DataFrame(
                {"cp_1": [1, 2]}, index=edisgo_obj.timeseries.timeindex[0:2]
            ),
            "upper_power": pd.DataFrame(
                {"cp_1": [1, 2]}, index=edisgo_obj.timeseries.timeindex[0:2]
            ),
        }
        edisgo_obj.electromobility.flexibility_bands = flex_bands
        edisgo_obj.overlying_grid.heat_pump_decentral_active_power = pd.Series(
            data=[2.4], index=[edisgo_obj.timeseries.timeindex[0]]
        )
        edisgo_obj.dsm.p_min = pd.DataFrame(
            data={"load_1": [5.0, 6.0], "load_2": [7.0, 8.0]},
            index=edisgo_obj.timeseries.timeindex[0:2],
        )

        # ################ test with non-existing path ######################

        msg = "Given edisgo_path does not exist."
        with pytest.raises(ValueError, match=msg):
            import_edisgo_from_files("dummy_dir")

        # ######################## test with default ########################
        edisgo_obj.save(
            save_dir,
            save_results=False,
            save_electromobility=True,
            save_heatpump=True,
            save_overlying_grid=True,
            save_dsm=True,
        )

        edisgo_obj_loaded = import_edisgo_from_files(save_dir)

        # check topology
        assert_frame_equal(
            edisgo_obj_loaded.topology.loads_df,
            edisgo_obj.topology.loads_df,
            check_dtype=False,
        )
        # check time series
        assert edisgo_obj_loaded.timeseries.timeindex.empty
        # check configs
        assert edisgo_obj_loaded.config._data == edisgo_obj.config._data
        # check results
        assert edisgo_obj_loaded.results.i_res.empty

        # ############ test with loading other data ###########

        edisgo_obj_loaded = import_edisgo_from_files(
            save_dir,
            import_electromobility=True,
            import_heat_pump=True,
            import_overlying_grid=True,
            import_dsm=True,
        )

        # check electromobility
        assert_frame_equal(
            edisgo_obj_loaded.electromobility.charging_processes_df,
            edisgo_obj.electromobility.charging_processes_df,
        )
        # check heat pump
        assert_frame_equal(
            edisgo_obj_loaded.heat_pump.cop_df, edisgo_obj.heat_pump.cop_df
        )
        # check overlying grid
        assert_series_equal(
            edisgo_obj_loaded.overlying_grid.heat_pump_decentral_active_power,
            edisgo_obj.overlying_grid.heat_pump_decentral_active_power,
            check_names=False,
            check_freq=False,
        )
        # check dsm
        assert_frame_equal(
            edisgo_obj_loaded.dsm.p_min,
            edisgo_obj.dsm.p_min,
            check_freq=False,
        )

        # delete directory
        shutil.rmtree(save_dir)

        # ########### test with loading from zip ###########
        edisgo_obj.save(
            save_dir,
            archive=True,
            save_electromobility=True,
            save_overlying_grid=True,
            save_dsm=True,
        )
        zip_file = f"{save_dir}.zip"
        edisgo_obj_loaded = import_edisgo_from_files(
            zip_file,
            import_results=True,
            import_timeseries=True,
            import_electromobility=True,
            import_overlying_grid=True,
            import_dsm=True,
            from_zip_archive=True,
        )

        # check topology
        assert_frame_equal(
            edisgo_obj_loaded.topology.loads_df,
            edisgo_obj.topology.loads_df,
            check_dtype=False,
        )
        # check time series
        assert_frame_equal(
            edisgo_obj_loaded.timeseries.loads_active_power,
            edisgo_obj.timeseries.loads_active_power,
            check_freq=False,
        )
        # check configs
        assert edisgo_obj_loaded.config._data == edisgo_obj.config._data
        # check results
        assert_frame_equal(
            edisgo_obj_loaded.results.i_res,
            edisgo_obj.results.i_res,
            check_freq=False,
            check_names=False,
        )
        # check electromobility
        assert_frame_equal(
            edisgo_obj_loaded.electromobility.flexibility_bands["upper_energy"],
            edisgo_obj.electromobility.flexibility_bands["upper_energy"],
            check_freq=False,
        )
        assert_frame_equal(
            edisgo_obj_loaded.electromobility.charging_processes_df,
            edisgo_obj.electromobility.charging_processes_df,
        )
        # check overlying grid
        assert_series_equal(
            edisgo_obj_loaded.overlying_grid.heat_pump_decentral_active_power,
            edisgo_obj.overlying_grid.heat_pump_decentral_active_power,
            check_names=False,
            check_freq=False,
        )
        # check dsm
        assert_frame_equal(
            edisgo_obj_loaded.dsm.p_min,
            edisgo_obj.dsm.p_min,
            check_freq=False,
        )

        # delete zip file
        os.remove(zip_file)
