# -*- coding: utf-8 -*-

# Copyright (c) 2016-2018 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.


import numpy as np
import pytest
from pandapower.optimal_powerflow import OPFNotConverged


import pandapower as pp

try:
    import pplog as logging
except ImportError:
    import logging

logger = logging.getLogger(__name__)
logger.setLevel("DEBUG")


def test_cost_piecewise_linear_gen():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """
    # boundaries:
    vm_max = 1.05
    vm_min = 0.95

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=.4)
    pp.create_gen(net, 1, p_kw=-100, controllable=True, max_p_kw=-5, min_p_kw=-150, max_q_kvar=50,
                  min_q_kvar=-50)
    pp.create_ext_grid(net, 0)
    pp.create_load(net, 1, p_kw=20, controllable=False)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)

    pp.create_piecewise_linear_cost(net, 0, "gen", np.array([[-150, -100], [-75, -50], [0, 0]]))
    # run OPF
    pp.runopp(net, verbose=False)

    assert net["OPF_converged"]
    assert net.res_cost - net.res_gen.p_kw.values / 1.5 < 1e-3


def test_cost_piecewise_linear_eg():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """

    # boundaries:
    vm_max = 1.05
    vm_min = 0.95

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10)
    pp.create_ext_grid(net, 0, max_p_kw=0, min_p_kw=-50)
    pp.create_gen(net, 1, p_kw=-10, max_p_kw=0, min_p_kw=-50, controllable=True)
    # pp.create_ext_grid(net, 0)
    pp.create_load(net, 1, p_kw=20, controllable=False)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)

    pp.create_piecewise_linear_cost(net, 0, "ext_grid", np.array([[-50, -500], [0, 0]]))
    # run OPF
    pp.runopp(net, verbose=False)

    assert net["OPF_converged"]
    assert net.res_cost - - net.res_ext_grid.p_kw.values * 10 < 1e-3
    # check and assert result


def test_get_costs():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """

    # boundaries:
    vm_max = 1.05
    vm_min = 0.95

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=.4)
    pp.create_gen(net, 1, p_kw=-100, controllable=True, max_p_kw=-5, min_p_kw=-150, max_q_kvar=50,
                  min_q_kvar=-50)
    pp.create_ext_grid(net, 0)
    pp.create_load(net, 1, p_kw=20, controllable=False)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)

    pp.create_piecewise_linear_cost(net, 0, "gen", np.array([[-150, -300], [0, 0]]))
    # run OPF
    pp.runopp(net, verbose=False)

    assert net["OPF_converged"]
    assert net.res_cost == 2 * net.res_gen.p_kw.values

    # check and assert result


def test_cost_piecewise_linear_sgen():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """

    # boundaries:
    vm_max = 1.05
    vm_min = 0.95

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=.4)
    pp.create_sgen(net, 1, p_kw=-100, controllable=True, max_p_kw=-5, min_p_kw=-150, max_q_kvar=50,
                   min_q_kvar=-50)
    pp.create_ext_grid(net, 0)
    pp.create_load(net, 1, p_kw=20, controllable=False)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)

    pp.create_piecewise_linear_cost(net, 0, "sgen", np.array([[-150, -100], [-75, -50], [0, 0]]))
    # run OPF
    pp.runopp(net, verbose=False)

    assert net["OPF_converged"]
    assert net.res_cost - net.res_sgen.p_kw.values / 1.5 < 1e-3


def test_cost_piecewise_linear_load():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """

    # boundaries:
    vm_max = 1.05
    vm_min = 0.95

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=.4)
    pp.create_load(net, 1, p_kw=100, controllable=True, max_p_kw=150, min_p_kw=50, max_q_kvar=0,
                   min_q_kvar=0)
    pp.create_ext_grid(net, 0)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)

    pp.create_piecewise_linear_cost(net, 0, "load", np.array([[0, 0], [75, 50], [150, 100]]))
    # run OPF
    pp.runopp(net, verbose=False)

    assert net["OPF_converged"]
    assert abs(net.res_cost - net.res_load.p_kw.values / 1.5) < 1e-3

def test_cost_piecewise_linear_sgen_uneven_slopes():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """

    # boundaries:
    vm_max = 1.05
    vm_min = 0.95

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=.4)
    pp.create_sgen(net, 1, p_kw=-100, controllable=True, max_p_kw=-5, min_p_kw=-150, max_q_kvar=50,
                   min_q_kvar=-50)
    pp.create_ext_grid(net, 0)
    pp.create_load(net, 1, p_kw=20, controllable=False)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)

    pp.create_piecewise_linear_cost(net, 0, "sgen", np.array([[-150, -200], [-75, -50], [0, 0]]))
    # run OPF
    pp.runopp(net, verbose=False)

    assert net["OPF_converged"]
    assert net.res_cost - net.res_sgen.p_kw.values / 1.5 < 1e-3


def test_cost_piecewise_linear_load_uneven_slopes():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """

    # boundaries:
    vm_max = 1.05
    vm_min = 0.95

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=.4)
    pp.create_load(net, 1, p_kw=100, controllable=True, max_p_kw=150, min_p_kw=50, max_q_kvar=0,
                   min_q_kvar=0)
    pp.create_ext_grid(net, 0)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)


    pp.create_piecewise_linear_cost(net, 0, "load", np.array([[0, 0], [75, 51], [150, 101]]))
    # run OPF
    with pytest.raises(OPFNotConverged):
        pp.runopp(net, verbose=False)
        assert net["OPF_converged"]
        assert abs(net.res_cost - net.res_load.p_kw.values / 1.5) < 1e-3

def test_cost_piecewise_linear_sgen_very_unsteady_slopes():
    """ Testing a very simple network for the resulting cost value
    constraints with OPF """

    # boundaries:
    vm_max = 1.5
    vm_min = 0.5

    # create net
    net = pp.create_empty_network()
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=10.)
    pp.create_bus(net, max_vm_pu=vm_max, min_vm_pu=vm_min, vn_kv=.4)
    pp.create_sgen(net, 1, p_kw=-1000, controllable=True, max_p_kw=0, min_p_kw=-1500,
                   max_q_kvar=50,
                   min_q_kvar=-50)
    pp.create_ext_grid(net, 0)
    pp.create_load(net, 1, p_kw=20, controllable=False)
    pp.create_line_from_parameters(net, 0, 1, 50, name="line2", r_ohm_per_km=0.876,
                                   c_nf_per_km=260.0, max_i_ka=0.123, x_ohm_per_km=0.1159876,
                                   max_loading_percent=100 * 690)

    pp.create_piecewise_linear_cost(net, 0, "sgen", np.array([[-1500, 2],[-750,1 ], [0,2]]))
    # run OPF
    pp.runopp(net, verbose=False)

    assert net["OPF_converged"]
    # assert net.res_cost - net.res_sgen.p_kw.values / 1.5 < 1e-3




if __name__ == "__main__":
    # test_cost_piecewise_linear_sgen_very_unsteady_slopes()
    pytest.main(["test_costs_pwl.py", "-s"])

[(19, 'logging.getLogger', 'logging.getLogger', False, 'import logging\n'), (31, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (32, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (33, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (34, 'pandapower.create_gen', 'pp.create_gen', True, 'import pandapower as pp\n'), (36, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (37, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (38, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (44, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (59, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (60, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (61, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (62, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (63, 'pandapower.create_gen', 'pp.create_gen', True, 'import pandapower as pp\n'), (65, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (66, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (72, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (88, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (89, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (90, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (91, 'pandapower.create_gen', 'pp.create_gen', True, 'import pandapower as pp\n'), (93, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (94, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (95, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (101, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (118, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (119, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (120, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (121, 'pandapower.create_sgen', 'pp.create_sgen', True, 'import pandapower as pp\n'), (123, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (124, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (125, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (131, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (146, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (147, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (148, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (149, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (151, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (152, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (158, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (172, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (173, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (174, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (175, 'pandapower.create_sgen', 'pp.create_sgen', True, 'import pandapower as pp\n'), (177, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (178, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (179, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (185, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (200, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (201, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (202, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (203, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (205, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (206, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (227, 'pandapower.create_empty_network', 'pp.create_empty_network', True, 'import pandapower as pp\n'), (228, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (229, 'pandapower.create_bus', 'pp.create_bus', True, 'import pandapower as pp\n'), (230, 'pandapower.create_sgen', 'pp.create_sgen', True, 'import pandapower as pp\n'), (233, 'pandapower.create_ext_grid', 'pp.create_ext_grid', True, 'import pandapower as pp\n'), (234, 'pandapower.create_load', 'pp.create_load', True, 'import pandapower as pp\n'), (235, 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', True, 'import pandapower as pp\n'), (241, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (251, 'pytest.main', 'pytest.main', False, 'import pytest\n'), (42, 'numpy.array', 'np.array', True, 'import numpy as np\n'), (70, 'numpy.array', 'np.array', True, 'import numpy as np\n'), (99, 'numpy.array', 'np.array', True, 'import numpy as np\n'), (129, 'numpy.array', 'np.array', True, 'import numpy as np\n'), (156, 'numpy.array', 'np.array', True, 'import numpy as np\n'), (183, 'numpy.array', 'np.array', True, 'import numpy as np\n'), (211, 'numpy.array', 'np.array', True, 'import numpy as np\n'), (213, 'pytest.raises', 'pytest.raises', False, 'import pytest\n'), (214, 'pandapower.runopp', 'pp.runopp', True, 'import pandapower as pp\n'), (239, 'numpy.array', 'np.array', True, 'import numpy as np\n')]