Exemplo n.º 1
0
def ErrorPOZ():
    N = 6
    it = 100
    (D, Pmax, Pmin, a, b, c, alpha, beta, gamma, delta, eta, UR, DR) = load(N)
    (Zones, Units) = zones(N)

    D = 2 * D / 3
    price = SimplePriceFun(Pmin, Pmax, a, b, c, alpha, beta, gamma, D)

    (Emax, C, Pk) = SQP_MINLP(N, 0, 1, D)
    (Emin, Cmin, Pk) = SQP_MINLP(N, price, 1, D)
    (E, Cmax, Pk) = SQP_MINLP(N, 1, 0, D)
    t0 = time.time()
    LimE = np.linspace(Emin, Emax, num=it)
    E1 = np.zeros(it)
    C1 = np.zeros(it)
    for i in range(it):
        (E_i, C_i, Pk) = eConstE_SQP(N, LimE[i], D)
        C1[i] = C_i
        E1[i] = E_i

    print("OK LimE")
    print(time.time() - t0)

    LimF = np.linspace(Cmin, Cmax, num=it)
    LimC1 = np.zeros(it)
    LimE1 = np.zeros(it)
    for i in range(it):
        (E_i, C_i, Pk) = eConstF_SQP(N, LimF[i], D)
        LimC1[i] = C_i
        LimE1[i] = E_i

    C = np.hstack((LimC1[::-1], C1))
    E = np.hstack((LimE1[::-1], E1))

    plt.figure()
    plt.plot(E[:-10], C[:-10], 'g')
    plt.plot(E[-10:], C[-10:], 'g')

    plt.xlabel('Emission [lb]')
    plt.ylabel('Cost [$]')
    plt.title('Pareto-optimal front')
    plt.grid()
    """Error analysis"""
    w = np.linspace(0.001, 0.999, num=it)
    CnoPOZ = np.zeros(it)
    EnoPOZ = np.zeros(it)
    for i in range(it):  # POF of problem without POZ
        w_E = price * w[i]
        w_C = 1 - w[i]
        (Ek, Ck, Pk) = SQP(N, w_E, w_C, D)
        CnoPOZ[i] = Ck.copy()
        EnoPOZ[i] = Ek.copy()

    [e, spline] = Hermite(EnoPOZ, CnoPOZ, price * w, 1 - w)

    plt.figure()
    plt.plot(E, C, 'g.')
    plt.plot(e, spline, 'm', label='Convex front')

    plt.xlabel('Emission [lb]')
    plt.ylabel('Cost [$]')
    plt.title('Pareto-optimal front')
    plt.grid()
    plt.legend()

    # Error computation following normalized minimum distance
    ErrorEmiss = 0
    ErrorCost = 0
    E_emax = 0
    C_emax = 0

    E_cmax = 0
    C_cmax = 0
    for i in range(it):
        (E_e, E_c) = mindist(E, C, EnoPOZ[i], CnoPOZ[i])

        if E_e > ErrorEmiss:  # Maximal error on the emissions
            E_emax = EnoPOZ[i]
            C_emax = CnoPOZ[i]
        if E_c > ErrorCost:
            E_cmax = EnoPOZ[i]
            C_cmax = CnoPOZ[i]

        ErrorEmiss = max(ErrorEmiss, E_e)
        ErrorCost = max(ErrorCost, E_c)

    print("Maximal difference of POZ : ")
    print("Emissions: ", ErrorEmiss)
    print("Costs: ", ErrorCost)
    plt.plot(E_emax, C_emax, 'bo', label='Max error on E')
    plt.plot(E_cmax, C_cmax, 'ko', label='Max error on C')
Exemplo n.º 2
0
def multiPOZ():
    prop_cycle = plt.rcParams['axes.prop_cycle']
    colors = prop_cycle.by_key()['color']
    N = 6
    it = 100
    w = np.linspace(0.001, 0.999, num=it)
    (D, Pmax, Pmin, a, b, c, alpha, beta, gamma, delta, eta, UR, DR) = load(N)
    (Zones, Units) = zones(N)
    D = 2 * D / 3

    price = SimplePriceFun(Pmin, Pmax, a, b, c, alpha, beta, gamma, D)
    plt.figure()
    CnoPOZ = np.zeros(it)
    EnoPOZ = np.zeros(it)
    for i in range(it):
        w_E = price * w[i]
        w_C = 1 - w[i]
        (Ek, Ck, Pk) = SQP(N, w_E, w_C, D)
        CnoPOZ[i] = Ck.copy()
        EnoPOZ[i] = Ek.copy()

    [e, spline] = Hermite(EnoPOZ, CnoPOZ, price * w, 1 - w)
    plt.plot(e, spline, 'k', label='Convex front')

    (E, C, Pk) = SQP_MINLP(N, 1, 0, D)
    (LowerB, UpperB) = InZone(Pk, Pmin, Pmax, Zones, Units)

    (E, C, Pk) = SQP_MINLP(N, 0, 1, D)
    (ZoneL, ZoneU) = InZone(Pk, Pmin, Pmax, Zones, Units)

    status = 0
    count = 0
    nZones = N
    while (count <= nZones and status == 0):
        C = np.zeros(it)
        E = np.zeros(it)
        p = SimplePriceFun(ZoneL, ZoneU, a, b, c, alpha, beta, gamma, D)
        for i in range(it):
            w_E = p * w[i]
            w_C = 1 - w[i]
            (E_i, C_i, Pk) = SQP(N, w_E, w_C, D, ZoneL, ZoneU)
            C[i] = C_i
            E[i] = E_i
        plt.plot(E,
                 C,
                 color=colors[count],
                 label="Front for zone" + str(count + 1))
        if (np.prod(ZoneL == LowerB) == 1):
            status = 1
        if (p < price):
            (emission, cost, P) = eConstE_SQP(N, min(E), D)
        else:
            (emission, cost, P) = eConstF_SQP(N, max(C), D)

        prec = ZoneL
        (ZoneL, ZoneU) = InZone(P, Pmin, Pmax, Zones, Units)
        if (sum(prec == ZoneL) < N - 1):
            print("hidden zone")
            print(prec)
            print(ZoneL)
        count = count + 1

    if status == 0:
        print("Not covered all zones")

    plt.xlabel('Emission [lb]')
    plt.ylabel('Cost [$]')
    plt.title('Pareto-optimal front')
    plt.grid()
    plt.legend()
Exemplo n.º 3
0
def figures():
    N = 6
    it = 100
    (D, Pmax, Pmin, a, b, c, alpha, beta, gamma, delta, eta, UR, DR) = load(N)
    D = 2 * D / 3
    price = SimplePriceFun(Pmin, Pmax, a, b, c, alpha, beta, gamma, D)

    C = np.zeros(it)
    E = np.zeros(it)
    CnoPOZ = np.zeros(it)
    EnoPOZ = np.zeros(it)
    w = np.linspace(0.001, 0.999, num=it)

    Power = np.zeros([it, N])
    for i in range(it):
        w_E = price * w[i]
        w_C = 1 - w[i]
        #POZ
        (E_i, C_i, Pk) = SQP_MINLP(N, w_E, w_C, D)
        Power[i] = Pk.copy()
        C[i] = C_i
        E[i] = E_i
        #NoPOZ
        (Ek, Ck, Pk) = SQP(N, w_E, w_C, D)
        CnoPOZ[i] = Ck.copy()
        EnoPOZ[i] = Ek.copy()

    plt.figure()
    plt.plot(E, C, 'b.', label='Front with POZ')

    [e, spline] = Hermite(EnoPOZ, CnoPOZ, price * w, 1 - w)
    plt.plot(e, spline, 'm', label='Convex front')

    plt.xlabel('Emission [lb]')
    plt.ylabel('Cost [$]')
    plt.title('Pareto-optimal front')
    plt.grid()
    plt.legend()

    #Plot the outputs and the corresponding POZ
    [Zones, Units] = zones(N)
    prop_cycle = plt.rcParams['axes.prop_cycle']
    colors = prop_cycle.by_key()['color']
    plt.figure()
    for i in range(N):
        plt.plot(range(it),
                 Power[:, i],
                 label='P' + str(i + 1),
                 color=colors[i])
        Zon_i = Zones[Units == i]
        ni = len(Zon_i)
        for j in range(ni):
            cond1 = abs(Power[:, i] - Zon_i[j, 0]) < 1e-2
            cond1 = np.append(cond1, False)
            xMin = np.argmax(cond1)
            xMax = np.argmax(1 - cond1[xMin:]) + xMin
            if xMin > 0 or cond1[0]:
                xMin = xMin - 1
                xMax = xMax + 1
                plt.hlines(y=Zon_i[j, 0],
                           xmin=0,
                           xmax=it,
                           color=colors[i],
                           linestyle='--',
                           linewidth=2.0)
                plt.hlines(y=Zon_i[j, 1],
                           xmin=0,
                           xmax=it,
                           color=colors[i],
                           linestyle='--',
                           linewidth=2.0)

            cond2 = abs(Power[:, i] - Zon_i[j, 1]) < 1e-2
            cond2 = np.append(cond2, False)
            xMin = np.argmax(cond2)
            xMax = np.argmax(1 - cond2[xMin:]) + xMin
            if xMin > 0 or cond2[0]:
                xMin = xMin - 1
                xMax = xMax + 1
                plt.hlines(y=Zon_i[j, 0],
                           xmin=0,
                           xmax=it,
                           color=colors[i],
                           linestyle='--',
                           linewidth=2.0)
                plt.hlines(y=Zon_i[j, 1],
                           xmin=0,
                           xmax=it,
                           color=colors[i],
                           linestyle='--',
                           linewidth=2.0)

    plt.xlabel('min $f= \pi wE(P)+(1-w)F(P)$')
    plt.ylabel('Power [MW]')
    plt.title('Output generation with different objectives and active POZ')
    plt.legend()
Exemplo n.º 4
0
def eConstE_SQP(N, LimE, D):
    (Unused, Pmax, Pmin, a, b, c, alpha, beta, gamma, delta, eta, UR,
     DR) = load(N)
    B = loss(N)
    (Zones, Units) = zones(N)
    """Computing P0 without POZ"""
    bnds = np.transpose(np.vstack((Pmin, Pmax)))

    def P0_Obj(P):
        return (0)

    def P0_Grad(P):
        return (np.zeros(N))

    def Objective(P):
        Obj = sum(a[i] + b[i] * P[i] + c[i] * P[i] * P[i] for i in range(N))
        return (Obj)

    def Gradient(P):
        Grad = b + 2 * c * P
        return (Grad)

    def cons_f(P):
        PL = sum(
            sum(P[i] * P[j] * B[i, j] for j in range(N)) for i in range(N))
        sum_eq = sum(P) - PL - D
        return (sum_eq)

    def cons_J(P):
        Jac = np.ones(N) - 2 * P @ B
        return (Jac)

    def cons_C(P):
        constraint = LimE - sum(alpha[k] + beta[k] * P[k] + gamma[k] * P[k] *
                                P[k] + eta[k] * np.exp(delta[k] * P[k])
                                for k in range(N))
        return (constraint)

    def cons_GradC(P):
        Grad = -beta - 2 * gamma * P - delta * eta * np.exp(delta * P)
        return (Grad)

    const = [{'type': 'eq', 'fun': cons_f}, {'type': 'ineq', 'fun': cons_C}]
    solution = minimize(P0_Obj,
                        Pmin,
                        method='SLSQP',
                        jac=P0_Grad,
                        bounds=bnds,
                        constraints=const)
    P0 = solution.x
    tol = 1e-2
    Maxiter = 100
    Obj = np.zeros(Maxiter)
    Obj[0] = sum(a[k] + b[k] * P0[k] + c[k] * P0[k] * P0[k] for k in range(N))

    Pk = P0.copy()
    Prev = P0.copy()
    it = 1
    stepsize = 1
    while (it < Maxiter and stepsize > tol):
        model = gp.Model('SQP Step, MIQP')
        model.setParam('OutputFlag', False)
        DeltaP = model.addVars(range(N), lb=Pmin - Pk, ub=Pmax - Pk)
        x = model.addVars(N)
        y = model.addVars(N)
        for i in range(N):
            model.addConstr(x[i] == delta[i] * DeltaP[i])
            model.addGenConstrExp(x[i], y[i])

        Surplus = sum(Pk) - Pk @ B @ Pk - D
        model.addConstr(Surplus + sum(DeltaP[k] * (1 - 2 * Pk @ B[k])
                                      for k in range(N)) == 0)

        model.addQConstr(
            LimE -
            sum(alpha[k] + beta[k] * (Pk[k] + DeltaP[k]) + gamma[k] *
                (Pk[k] + DeltaP[k]) *
                (Pk[k] + DeltaP[k]) + eta[k] * np.exp(delta[k] * Pk[k]) * y[k]
                for k in range(N)) >= 0)

        for i in range(N):  # POZ
            Zon_i = Zones[Units == i]
            n_i = len(Zon_i)
            if n_i >= 1:
                bb = model.addVars(range(n_i + 1), vtype=GRB.BINARY)
                model.addConstr(DeltaP[i] <= Zon_i[0, 0] * bb[0] +
                                (1 - bb[0]) * Pmax[i] - Pk[i])
                for j in np.arange(1, n_i):
                    model.addConstr(
                        DeltaP[i] >= Zon_i[j - 1, 1] * bb[j] - Pk[i])
                    model.addConstr(DeltaP[i] <= Zon_i[j, 0] * bb[j] +
                                    (1 - bb[j]) * Pmax[i] - Pk[i])
                model.addConstr(DeltaP[i] >= Zon_i[-1, 1] * bb[n_i] - Pk[i])
                model.addConstr(bb.sum() == 1)

        Grad = b + c * Pk * 2
        Hessian = 2 * c
        Lagr = sum(DeltaP[k] * DeltaP[k] * Hessian[k] for k in range(N))
        objec = sum(Grad[k] * DeltaP[k] for k in range(N)) + 0.5 * Lagr
        model.setObjective(objec)
        model.optimize()
        PPrev = Prev.copy()
        Prev = Pk.copy()
        for i in range(N):
            Pk[i] = Pk[i] + DeltaP[i].x
        stepsize = np.linalg.norm(Prev - Pk)

        if np.linalg.norm(PPrev - Pk) < tol:
            res = sum(Pk) - Pk @ B @ Pk - D
            resPrev = sum(Prev) - Prev @ B @ Prev - D
            if (abs(res) <= 1e-4 or abs(resPrev) <= 1e-4):
                if (resPrev == max(res, resPrev) and res <= 0):
                    Pk = Prev.copy()
                break

            (LowerB, UpperB) = InZone(Pk, Pmin, Pmax, Zones, Units)
            Limits = np.transpose(np.vstack((LowerB, UpperB)))
            sol = minimize(Objective,
                           Pk,
                           method='SLSQP',
                           jac=Gradient,
                           bounds=Limits,
                           constraints=const)
            Pk = sol.x
            obj = sum(a[k] + b[k] * Pk[k] + c[k] * Pk[k] * Pk[k]
                      for k in range(N))

            (LowerB1, UpperB1) = InZone(Prev, Pmin, Pmax, Zones, Units)
            obj1 = Obj[it - 1]
            if np.prod(LowerB == LowerB1) == 0:
                Limits = np.transpose(np.vstack((LowerB1, UpperB1)))
                sol1 = minimize(Objective,
                                Prev,
                                method='SLSQP',
                                jac=Gradient,
                                bounds=Limits,
                                constraints=const)
                Prev = sol1.x
                obj1 = sum(a[k] + b[k] * Prev[k] + c[k] * Prev[k] * Prev[k]
                           for k in range(N))
                if obj1 < obj:
                    Pk = Prev.copy()
            stepsize = -1

        Obj[it] = sum(a[k] + b[k] * Pk[k] + c[k] * Pk[k] * Pk[k]
                      for k in range(N))
        if ((it % 10) == 0):
            print(it, " of ", Maxiter)
        it = it + 1
    """Figures"""
    opt = Obj[it - 1] + 1e-6
    plt.figure()

    Pos = Obj[:it] - np.ones(it) * opt
    Neg = -Pos.copy()

    Pos = (Obj[:it] - np.ones(it) * opt > 0) * Pos
    Neg = (Obj[:it] - np.ones(it) * opt < 0) * Neg
    plt.plot(range(it), Pos, label='Positive Part ')
    plt.plot(range(it), Neg, label='Negative Part ')

    plt.xlabel('Iterations')
    plt.ylabel('$f_k-f*$')
    plt.title("Rate of convergence of eConstE ")
    plt.legend()
    plt.grid()

    return (LimE - cons_C(Pk), Obj[it - 1], Pk)
Exemplo n.º 5
0
def SQP_MINLP(N, w_E, w_C, D):
    (Unused, Pmax, Pmin, a, b, c, alpha, beta, gamma, delta, eta, UR,
     DR) = load(N)
    B = loss(N)
    (Zones, Units) = zones(N)
    """Computing P0 without POZ"""
    bnds = np.transpose(np.vstack((Pmin, Pmax)))
    P0 = Pmin.copy()

    def objective(P):
        return (0)

    def Gradient(P):
        return (np.zeros(N))

    def Hessian(P):
        return (np.zeros([N, N]))

    def cons_f(P):
        PL = sum(
            sum(P[i] * P[j] * B[i, j] for j in range(N)) for i in range(N))
        sum_eq = sum(P) - PL - D
        return (sum_eq)

    def cons_J(P):
        Jac = np.ones(N) - 2 * P @ B
        return (Jac)

    if (N <= 10):
        const = [{'type': 'eq', 'fun': cons_f, 'jac': cons_J}]
        solution = minimize(objective,
                            P0,
                            method='SLSQP',
                            jac=Gradient,
                            bounds=bnds,
                            constraints=const)
    else:

        def cons_H(P, v):
            return (-2 * v * B)

        NL_const = NonlinearConstraint(cons_f, 0, 0, jac=cons_J, hess=cons_H)
        solution = minimize(objective,
                            P0,
                            method='trust-constr',
                            jac=Gradient,
                            hess=Hessian,
                            constraints=NL_const,
                            bounds=bnds)
    P0 = solution.x
    tol = 1e-2
    Maxiter = 100
    Obj = np.zeros(Maxiter)
    C = sum(a[k] + b[k] * P0[k] + c[k] * P0[k] * P0[k] for k in range(N))
    E = sum(alpha[k] + beta[k] * P0[k] + gamma[k] * P0[k] * P0[k] +
            eta[k] * np.exp(delta[k] * P0[k]) for k in range(N))
    Obj[0] = w_C * C + w_E * E
    Pk = P0.copy()
    Prev = P0.copy()
    it = 1
    stepsize = 1
    while (it < Maxiter and stepsize > tol):
        model = gp.Model('SQP Step, MIQP')
        model.setParam('OutputFlag', False)
        DeltaP = model.addVars(range(N), lb=Pmin - Pk, ub=Pmax - Pk)

        Surplus = sum(Pk) - Pk @ B @ Pk - D
        model.addConstr(Surplus + sum(DeltaP[k] * (1 - 2 * Pk @ B[k])
                                      for k in range(N)) >= 0)
        for i in range(N):  # POZ
            Zon_i = Zones[Units == i]
            n_i = len(Zon_i)
            if n_i >= 1:
                bb = model.addVars(range(n_i + 1), vtype=GRB.BINARY)
                model.addConstr(DeltaP[i] <= Zon_i[0, 0] * bb[0] +
                                (1 - bb[0]) * Pmax[i] - Pk[i])
                for j in np.arange(1, n_i):
                    model.addConstr(
                        DeltaP[i] >= Zon_i[j - 1, 1] * bb[j] - Pk[i])
                    model.addConstr(DeltaP[i] <= Zon_i[j, 0] * bb[j] +
                                    (1 - bb[j]) * Pmax[i] - Pk[i])
                model.addConstr(DeltaP[i] >= Zon_i[-1, 1] * bb[n_i] - Pk[i])
                model.addConstr(bb.sum() == 1)

        GradC = b + c * Pk * 2
        GradE = beta + gamma * Pk * 2 + delta * eta * np.exp(delta * Pk)
        Grad = w_C * GradC + w_E * GradE
        Hessian = w_C * 2 * c + w_E * (
            2 * gamma + delta * delta * eta * np.exp(delta * Pk))
        Lagr = sum(DeltaP[k] * DeltaP[k] * Hessian[k] for k in range(N))
        objec = sum(Grad[k] * DeltaP[k] for k in range(N)) + 0.5 * Lagr
        model.setObjective(objec)
        model.optimize()
        PPrev = Prev.copy()
        Prev = Pk.copy()
        for i in range(N):
            Pk[i] = Pk[i] + DeltaP[i].x

        stepsize = np.linalg.norm(Prev - Pk)

        if np.linalg.norm(PPrev -
                          Pk) < tol:  # The algorithm cycles between 2 zones
            res = sum(Pk) - Pk @ B @ Pk - D
            resPrev = sum(Prev) - Prev @ B @ Prev - D
            if (resPrev == max(res, resPrev) and res <= 0):
                Pk = Prev.copy()

            (opt, p) = Solve(N, w_E, w_C, D)
            stepsize = -1

        C = sum(a[k] + b[k] * Pk[k] + c[k] * Pk[k] * Pk[k] for k in range(N))
        E = sum(alpha[k] + beta[k] * Pk[k] + gamma[k] * Pk[k] * Pk[k] +
                eta[k] * np.exp(delta[k] * Pk[k]) for k in range(N))
        Obj[it] = w_C * C + w_E * E
        if ((it % 10) == 0):
            print(it, " of ", Maxiter)
        it = it + 1
    return (E, C, Pk)
Exemplo n.º 6
0
def eConstF_SQP(N, LimF, D):
    (Unused, Pmax, Pmin, a, b, c, alpha, beta, gamma, delta, eta, UR,
     DR) = load(N)
    B = loss(N)
    (Zones, Units) = zones(N)
    """Computing P0 without POZ"""
    bnds = np.transpose(np.vstack((Pmin, Pmax)))

    def P0_Obj(P):
        return (0)

    def P0_Grad(P):
        return (np.zeros(N))

    def Objective(P):
        Obj = sum(alpha[i] + beta[i] * P[i] + gamma[i] * P[i] * P[i] +
                  eta[i] * np.exp(P[i] * delta[i]) for i in range(N))
        return (Obj)

    def Gradient(P):
        Grad = beta + 2 * gamma * P + delta * eta * np.exp(delta * P)
        return (Grad)

    def cons_f(P):
        PL = sum(
            sum(P[i] * P[j] * B[i, j] for j in range(N)) for i in range(N))
        sum_eq = sum(P) - PL - D
        return (sum_eq)

    def cons_J(P):
        Jac = np.ones(N) - 2 * P @ B
        return (Jac)

    def cons_C(P):
        constraint = LimF - sum(a[k] + b[k] * P[k] + c[k] * P[k] * P[k]
                                for k in range(N))
        return (constraint)

    def cons_GradC(P):
        Grad = -b - 2 * c * P
        return (Grad)

    const = [{'type': 'eq', 'fun': cons_f}, {'type': 'ineq', 'fun': cons_C}]
    solution = minimize(P0_Obj,
                        Pmin,
                        method='SLSQP',
                        jac=P0_Grad,
                        bounds=bnds,
                        constraints=const)
    P0 = solution.x
    tol = 1e-2
    Maxiter = 100
    Obj = np.zeros(Maxiter)
    Obj[0] = sum(alpha[k] + beta[k] * P0[k] + gamma[k] * P0[k] * P0[k] +
                 eta[k] * np.exp(delta[k] * P0[k]) for k in range(N))

    Pk = P0.copy()
    Prev = P0.copy()
    it = 1
    stepsize = 1
    while (it < Maxiter and stepsize > tol):
        model = gp.Model('SQP Step, MILP')
        model.setParam('OutputFlag', False)
        DeltaP = model.addVars(range(N), lb=Pmin - Pk, ub=Pmax - Pk)
        Surplus = sum(Pk) - Pk @ B @ Pk - D
        model.addConstr(Surplus + sum(DeltaP[k] * (1 - 2 * Pk @ B[k])
                                      for k in range(N)) >= 0)

        model.addQConstr(LimF - sum(a[k] + b[k] * (Pk[k] + DeltaP[k]) + c[k] *
                                    (Pk[k] + DeltaP[k]) * (Pk[k] + DeltaP[k])
                                    for k in range(N)) >= 0)

        for i in range(N):  # POZ
            Zon_i = Zones[Units == i]
            n_i = len(Zon_i)
            if n_i >= 1:
                bb = model.addVars(range(n_i + 1), vtype=GRB.BINARY)
                model.addConstr(DeltaP[i] <= Zon_i[0, 0] * bb[0] +
                                (1 - bb[0]) * Pmax[i] - Pk[i])
                for j in np.arange(1, n_i):
                    model.addConstr(
                        DeltaP[i] >= Zon_i[j - 1, 1] * bb[j] - Pk[i])
                    model.addConstr(DeltaP[i] <= Zon_i[j, 0] * bb[j] +
                                    (1 - bb[j]) * Pmax[i] - Pk[i])
                model.addConstr(DeltaP[i] >= Zon_i[-1, 1] * bb[n_i] - Pk[i])
                model.addConstr(bb.sum() == 1)

        Grad = beta + gamma * Pk * 2 + delta * eta * np.exp(delta * Pk)
        Hessian = 2 * gamma + delta * delta * eta * np.exp(delta * Pk)
        Lagr = sum(DeltaP[k] * DeltaP[k] * Hessian[k] for k in range(N))
        objec = sum(Grad[k] * DeltaP[k] for k in range(N)) + 0.5 * Lagr
        model.setObjective(objec)
        model.optimize()
        PPrev = Prev.copy()
        Prev = Pk.copy()

        for i in range(N):
            Pk[i] = Pk[i] + DeltaP[i].x
        stepsize = np.linalg.norm(Prev - Pk)

        if np.linalg.norm(PPrev -
                          Pk) < tol:  # The algorithm cycles between 2 zones
            res = sum(Pk) - Pk @ B @ Pk - D
            resPrev = sum(Prev) - Prev @ B @ Prev - D
            if (abs(res) <= 1e-4 or abs(resPrev) <= 1e-4):
                if (resPrev == max(res, resPrev) and res <= 0):
                    Pk = Prev.copy()
                break
            # Compares the best solution of the 2 zones
            (LowerB, UpperB) = InZone(Pk, Pmin, Pmax, Zones,
                                      Units)  #Current zone
            Limits = np.transpose(np.vstack((LowerB, UpperB)))
            sol = minimize(Objective,
                           Pk,
                           method='SLSQP',
                           jac=Gradient,
                           bounds=Limits,
                           constraints=const)
            Pk = sol.x
            obj = sum(alpha[k] + beta[k] * Pk[k] + gamma[k] * Pk[k] * Pk[k] +
                      eta[k] * np.exp(delta[k] * Pk[k]) for k in range(N))

            (LowerB1, UpperB1) = InZone(Prev, Pmin, Pmax, Zones,
                                        Units)  #Previous zone
            obj1 = Obj[it - 1]
            if np.prod(LowerB == LowerB1) == 0:  #Different zone
                Limits = np.transpose(np.vstack((LowerB1, UpperB1)))
                sol1 = minimize(Objective,
                                Prev,
                                method='SLSQP',
                                jac=Gradient,
                                bounds=Limits,
                                constraints=const)
                Prev = sol1.x
                obj1 = sum(alpha[k] + beta[k] * Prev[k] +
                           gamma[k] * Prev[k] * Prev[k] +
                           eta[k] * np.exp(delta[k] * Prev[k])
                           for k in range(N))
                if obj1 < obj:
                    Pk = Prev.copy()
            stepsize = -1

        Obj[it] = sum(alpha[k] + beta[k] * Pk[k] + gamma[k] * Pk[k] * Pk[k] +
                      eta[k] * np.exp(delta[k] * Pk[k]) for k in range(N))
        if ((it % 10) == 0):
            print(it, " of ", Maxiter)
        it = it + 1
    return (Obj[it - 1], LimF - cons_C(Pk), Pk)