# -*- 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, 9, 19, 36), 'logging.getLogger', 'logging.getLogger', ({(19, 27, 19, 35): '__name__'}, {}), '(__name__)', False, 'import logging\n'), ((31, 10, 31, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((32, 4, 32, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((33, 4, 33, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((34, 4, 35, 33), 'pandapower.create_gen', 'pp.create_gen', (), '', True, 'import pandapower as pp\n'), ((36, 4, 36, 30), 'pandapower.create_ext_grid', 'pp.create_ext_grid', ({(36, 23, 36, 26): 'net', (36, 28, 36, 29): '(0)'}, {}), '(net, 0)', True, 'import pandapower as pp\n'), ((37, 4, 37, 55), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((38, 4, 40, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((44, 4, 44, 33), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((59, 10, 59, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((60, 4, 60, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((61, 4, 61, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((62, 4, 62, 56), 'pandapower.create_ext_grid', 'pp.create_ext_grid', (), '', True, 'import pandapower as pp\n'), ((63, 4, 63, 80), 'pandapower.create_gen', 'pp.create_gen', (), '', True, 'import pandapower as pp\n'), ((65, 4, 65, 55), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((66, 4, 68, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((72, 4, 72, 33), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((88, 10, 88, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((89, 4, 89, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((90, 4, 90, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((91, 4, 92, 33), 'pandapower.create_gen', 'pp.create_gen', (), '', True, 'import pandapower as pp\n'), ((93, 4, 93, 30), 'pandapower.create_ext_grid', 'pp.create_ext_grid', ({(93, 23, 93, 26): 'net', (93, 28, 93, 29): '(0)'}, {}), '(net, 0)', True, 'import pandapower as pp\n'), ((94, 4, 94, 55), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((95, 4, 97, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((101, 4, 101, 33), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((118, 10, 118, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((119, 4, 119, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((120, 4, 120, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((121, 4, 122, 34), 'pandapower.create_sgen', 'pp.create_sgen', (), '', True, 'import pandapower as pp\n'), ((123, 4, 123, 30), 'pandapower.create_ext_grid', 'pp.create_ext_grid', ({(123, 23, 123, 26): 'net', (123, 28, 123, 29): '(0)'}, {}), '(net, 0)', True, 'import pandapower as pp\n'), ((124, 4, 124, 55), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((125, 4, 127, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((131, 4, 131, 33), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((146, 10, 146, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((147, 4, 147, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((148, 4, 148, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((149, 4, 150, 32), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((151, 4, 151, 30), 'pandapower.create_ext_grid', 'pp.create_ext_grid', ({(151, 23, 151, 26): 'net', (151, 28, 151, 29): '(0)'}, {}), '(net, 0)', True, 'import pandapower as pp\n'), ((152, 4, 154, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((158, 4, 158, 33), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((172, 10, 172, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((173, 4, 173, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((174, 4, 174, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((175, 4, 176, 34), 'pandapower.create_sgen', 'pp.create_sgen', (), '', True, 'import pandapower as pp\n'), ((177, 4, 177, 30), 'pandapower.create_ext_grid', 'pp.create_ext_grid', ({(177, 23, 177, 26): 'net', (177, 28, 177, 29): '(0)'}, {}), '(net, 0)', True, 'import pandapower as pp\n'), ((178, 4, 178, 55), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((179, 4, 181, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((185, 4, 185, 33), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((200, 10, 200, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((201, 4, 201, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((202, 4, 202, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((203, 4, 204, 32), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((205, 4, 205, 30), 'pandapower.create_ext_grid', 'pp.create_ext_grid', ({(205, 23, 205, 26): 'net', (205, 28, 205, 29): '(0)'}, {}), '(net, 0)', True, 'import pandapower as pp\n'), ((206, 4, 208, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((227, 10, 227, 35), 'pandapower.create_empty_network', 'pp.create_empty_network', ({}, {}), '()', True, 'import pandapower as pp\n'), ((228, 4, 228, 69), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((229, 4, 229, 68), 'pandapower.create_bus', 'pp.create_bus', (), '', True, 'import pandapower as pp\n'), ((230, 4, 232, 34), 'pandapower.create_sgen', 'pp.create_sgen', (), '', True, 'import pandapower as pp\n'), ((233, 4, 233, 30), 'pandapower.create_ext_grid', 'pp.create_ext_grid', ({(233, 23, 233, 26): 'net', (233, 28, 233, 29): '(0)'}, {}), '(net, 0)', True, 'import pandapower as pp\n'), ((234, 4, 234, 55), 'pandapower.create_load', 'pp.create_load', (), '', True, 'import pandapower as pp\n'), ((235, 4, 237, 65), 'pandapower.create_line_from_parameters', 'pp.create_line_from_parameters', (), '', True, 'import pandapower as pp\n'), ((241, 4, 241, 33), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((251, 4, 251, 44), 'pytest.main', 'pytest.main', ({(251, 16, 251, 43): "['test_costs_pwl.py', '-s']"}, {}), "(['test_costs_pwl.py', '-s'])", False, 'import pytest\n'), ((42, 51, 42, 95), 'numpy.array', 'np.array', ({(42, 60, 42, 94): '[[-150, -100], [-75, -50], [0, 0]]'}, {}), '([[-150, -100], [-75, -50], [0, 0]])', True, 'import numpy as np\n'), ((70, 56, 70, 87), 'numpy.array', 'np.array', ({(70, 65, 70, 86): '[[-50, -500], [0, 0]]'}, {}), '([[-50, -500], [0, 0]])', True, 'import numpy as np\n'), ((99, 51, 99, 83), 'numpy.array', 'np.array', ({(99, 60, 99, 82): '[[-150, -300], [0, 0]]'}, {}), '([[-150, -300], [0, 0]])', True, 'import numpy as np\n'), ((129, 52, 129, 96), 'numpy.array', 'np.array', ({(129, 61, 129, 95): '[[-150, -100], [-75, -50], [0, 0]]'}, {}), '([[-150, -100], [-75, -50], [0, 0]])', True, 'import numpy as np\n'), ((156, 52, 156, 92), 'numpy.array', 'np.array', ({(156, 61, 156, 91): '[[0, 0], [75, 50], [150, 100]]'}, {}), '([[0, 0], [75, 50], [150, 100]])', True, 'import numpy as np\n'), ((183, 52, 183, 96), 'numpy.array', 'np.array', ({(183, 61, 183, 95): '[[-150, -200], [-75, -50], [0, 0]]'}, {}), '([[-150, -200], [-75, -50], [0, 0]])', True, 'import numpy as np\n'), ((211, 52, 211, 92), 'numpy.array', 'np.array', ({(211, 61, 211, 91): '[[0, 0], [75, 51], [150, 101]]'}, {}), '([[0, 0], [75, 51], [150, 101]])', True, 'import numpy as np\n'), ((213, 9, 213, 39), 'pytest.raises', 'pytest.raises', ({(213, 23, 213, 38): 'OPFNotConverged'}, {}), '(OPFNotConverged)', False, 'import pytest\n'), ((214, 8, 214, 37), 'pandapower.runopp', 'pp.runopp', (), '', True, 'import pandapower as pp\n'), ((239, 52, 239, 91), 'numpy.array', 'np.array', ({(239, 61, 239, 90): '[[-1500, 2], [-750, 1], [0, 2]]'}, {}), '([[-1500, 2], [-750, 1], [0, 2]])', True, 'import numpy as np\n')]