Scipy 中的优化

Optimization in Scipy

我想在下面的代码中添加一些约束,我想在其中使用 scipy 优化输出。

    """
References:
    https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html
    https://github.com/DTUWindEnergy/PyWake
"""


import time

from py_wake.examples.data.hornsrev1 import V80 
from py_wake.examples.data.hornsrev1 import Hornsrev1Site # We work with the Horns Rev 1 site, which comes already set up with PyWake.
from py_wake import BastankhahGaussian

from scipy.optimize import minimize
import numpy as np


def funC(x, y, c):
    """
    Turns on/off the use of wind turbine depending on the value of c.
    scipy generates c real values in the range [0, 1] as specified by the bounds including 0.2 etc.
    If c is 0.5 or more turbine will be used otherwise turbine will not be used.
    """
    x_selected = x[c >= 0.5]
    y_selected = y[c >= 0.5]
    
    return (x_selected, y_selected)


def wt_simulation(c):
    """
    This is our objective function. It will return the aep=annual energy production in GWh.
    We will maximize aep.
    """
    site = Hornsrev1Site()
    x, y = site.initial_position.T
    windTurbines = V80()
    
    wf_model = BastankhahGaussian(site, windTurbines)
    x_new, y_new = funC(x, y, c)

    # run wind farm simulation
    sim_res = wf_model(
        x_new, y_new, # wind turbine positions
        h=None, # wind turbine heights (defaults to the heights defined in windTurbines)
        type=0, # Wind turbine types
        wd=None, # Wind direction (defaults to site.default_wd (0,1,...,360 if not overriden))
        ws=None, # Wind speed (defaults to site.default_ws (3,4,...,25m/s if not overriden))
    )
    
    aep_output = sim_res.aep().sum()  # we maximize aep
    
    return -float(aep_output)  # negate because of scipy minimize


def solve():
    t0 = time.perf_counter()
    
    wt = 80  # for V80

    x0 = np.ones(wt)  # initial value
    bounds = [(0, 1) for _ in range(wt)]

    res = minimize(wt_simulation, x0=x0, bounds=bounds)
    
    print(f'success status: {res.success}')
    print(f'aep: {-res.fun}')  # negate to get the true maximum aep
    print(f'c values: {res.x}\n')

    print(f'elapse: {round(time.perf_counter() - t0)}s')  


# start
solve()

现在我想添加一个约束,其中湍流强度:sim_res_TI_eff 每个风力涡轮机 (wt) 对于每个风速 (was) 和每个风向 (wd) 必须低于某个值(例如 0.2)。我必须补充一点,例如 sim_res.TI_eff.sel(wt=1) 给出了每个 wd 的 TI,并且是风力涡轮机 #1。问题是我需要使用函数 wt_simulation,其中我有另一个必须优化的 return,所以我不知道如何 return TI 不受优化的影响。

这是处理 ti_eff 的一种方法。

"""
References:
    https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html
    https://github.com/DTUWindEnergy/PyWake
"""


import time

from py_wake.examples.data.hornsrev1 import V80 
from py_wake.examples.data.hornsrev1 import Hornsrev1Site # We work with the Horns Rev 1 site, which comes already set up with PyWake.
from py_wake import BastankhahGaussian

from scipy.optimize import minimize
import numpy as np


TIEFF_THRESHOLD = 0.2


def ok_tieff_constraint(tieff):
    """
    Returns True if tieff is below threshold otherwise False.
    """
    if np.any(tieff >= TIEFF_THRESHOLD):
        return False
    return True


def funC(x, y, c):
    """
    Turns on/off the use of wind turbine depending on the value of c.
    scipy generates c real values in the range [0, 1] as specified by the bounds including 0.2 etc.
    If c is 0.5 or more turbine will be used otherwise turbine will not be used.
    """
    x_selected = x[c >= 0.5]
    y_selected = y[c >= 0.5]
    
    return (x_selected, y_selected)


def wt_simulation(c):
    """
    This is our objective function. It will return the aep=annual energy production in GWh.
    We will maximize aep.
    """
    islogging = True
    site = Hornsrev1Site()
    x, y = site.initial_position.T
    windTurbines = V80()
    
    wf_model = BastankhahGaussian(site, windTurbines)
    x_new, y_new = funC(x, y, c)

    # run wind farm simulation
    sim_res = wf_model(
        x_new, y_new, # wind turbine positions
        h=None, # wind turbine heights (defaults to the heights defined in windTurbines)
        type=0, # Wind turbine types
        wd=None, # Wind direction (defaults to site.default_wd (0,1,...,360 if not overriden))
        ws=None, # Wind speed (defaults to site.default_ws (3,4,...,25m/s if not overriden))
    )
    
    if islogging:
        print(sim_res)
    
    aep_output = float(sim_res.aep().sum())  # we maximize aep
    
    # Constraint on ti_eff, if constraint is violated we set aep to zero.
    if not ok_tieff_constraint(sim_res.TI_eff):
        aep_output = 0
    
    return -aep_output  # negate because of scipy minimize


def solve():
    t0 = time.perf_counter()
    
    wt = 80  # for V80

    x0 = np.ones(wt)  # initial value
    bounds = [(0, 1) for _ in range(wt)]

    res = minimize(wt_simulation, x0=x0, bounds=bounds)
    
    print(f'success status: {res.success}')
    print(f'aep: {-res.fun}')  # negate to get the true maximum aep
    print(f'c values: {res.x}\n')

    print(f'elapse: {round(time.perf_counter() - t0)}s')  


# start
solve()

输出:

...

<xarray.SimulationResult>
Dimensions:           (wt: 80, wd: 360, ws: 23)
Coordinates:
  * wt                (wt) int32 0 1 2 3 4 5 6 7 8 ... 72 73 74 75 76 77 78 79
  * wd                (wd) int32 0 1 2 3 4 5 6 7 ... 353 354 355 356 357 358 359
  * ws                (ws) int32 3 4 5 6 7 8 9 10 11 ... 18 19 20 21 22 23 24 25
    x                 (wt) float64 4.24e+05 4.24e+05 ... 4.294e+05 4.295e+05
    y                 (wt) float64 6.151e+06 6.151e+06 ... 6.148e+06 6.148e+06
    h                 (wt) float64 70.0 70.0 70.0 70.0 ... 70.0 70.0 70.0 70.0
    type              (wt) int32 0 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0 0
Data variables: (12/15)
    WS_eff            (wt, wd, ws) float64 3.0 4.0 5.0 6.0 ... 22.87 23.88 24.89
    TI_eff            (wt, wd, ws) float64 0.1 0.1 0.1 0.1 ... 0.1 0.1 0.1 0.1
    Power             (wt, wd, ws) float64 0.0 6.66e+04 1.54e+05 ... 2e+06 2e+06
    CT                (wt, wd, ws) float64 0.0 0.818 0.806 ... 0.06084 0.05377
    WS                (ws) int32 3 4 5 6 7 8 9 10 11 ... 18 19 20 21 22 23 24 25
    WD                (wd) int32 0 1 2 3 4 5 6 7 ... 353 354 355 356 357 358 359
    ...                ...
    Weibull_A         (wd) float64 9.177 9.177 9.177 9.177 ... 9.177 9.177 9.177
    Weibull_k         (wd) float64 2.393 2.393 2.393 2.393 ... 2.393 2.393 2.393
    Sector_frequency  (wd) float64 0.001199 0.001199 ... 0.001199 0.001199
    P                 (wd, ws) float64 6.147e-05 8.559e-05 ... 2.193e-08
    tilt              (wt, wd, ws) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
    yaw               (wt, wd, ws) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
Attributes:
    wd_bin_size:  1
success status: True
aep: 682.0407252944838
c values: [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1.]

elapse: 273s