• Energy

RWE Quantum Optimization for Offshore Wind Farm Layout and Energy Production

RWE

RWE, Europe's largest electricity producer with over 10 GW of offshore wind capacity, applied quantum annealing and QAOA to optimize turbine placement in offshore wind farms, co-optimizing wake-effect losses, cable routing costs, and grid connection topology.

Key Outcome
Combined quantum approach improved annual energy production by 3.2% vs CMA-ES baseline for 150-turbine North Sea farm layout; cable routing cost reduced by 8% via QAOA constraint optimization.

The Problem

Offshore wind turbines do not operate independently. When wind passes through a spinning turbine it leaves a wake: a cone of slower, turbulent air extending far downwind. A turbine placed inside another turbine’s wake generates significantly less power. For a 150-turbine North Sea farm, wake losses can reduce total energy production by 10-20% compared to turbines operating in undisturbed wind. Optimizing turbine layout to minimize these wake interactions is one of the highest-value problems in offshore wind development.

The layout problem is combinatorial. Given a discretized grid of permitted positions, each turbine must be placed at a location that balances energy yield (avoid wakes), cable routing cost (nearby turbines are cheaper to connect), and grid connection geometry (export cables follow specific corridors). With 300 candidate positions and 150 turbines, the search space is astronomical. Classical approaches like CMA-ES (Covariance Matrix Adaptation Evolution Strategy) work well but plateau at local optima in the cable routing subproblem.

RWE’s offshore engineering team partnered with quantum computing vendors to test whether QUBO formulations on D-Wave Advantage and QAOA circuits on IBM Eagle could find better combined layout-and-routing solutions than their existing evolutionary solvers.

Wake Effect QUBO and Binary Grid Encoding

The layout problem was encoded as a binary optimization. Each candidate position ii on the discretized grid received a binary variable xi{0,1}x_i \in \{0, 1\}, where 1 indicates turbine placement. The wake penalty between positions ii and jj was precomputed using the Jensen wake model: if position jj falls inside the wake cone of position ii given the prevailing wind rose, a penalty wijw_{ij} is applied when both are occupied.

import numpy as np
from dwave.system import LeapHybridSampler
from dimod import BinaryQuadraticModel

# Grid: 300 candidate positions, 150 turbines to place
N_POSITIONS = 300
N_TURBINES = 150

# Precomputed wake penalty matrix using Jensen model
# wake_penalty[i][j] > 0 if turbine at i creates wake loss for turbine at j
wake_penalty = np.load("wake_penalty_matrix.npy")  # shape (300, 300)

# Cable cost matrix: Euclidean distance between positions scaled by seabed factor
cable_cost = np.load("cable_cost_matrix.npy")  # shape (300, 300)

# Build BQM
bqm = BinaryQuadraticModel('BINARY')

# Add binary variables for each candidate position
for i in range(N_POSITIONS):
    bqm.add_variable(i, 0.0)

# Wake penalty quadratic terms: penalize co-occupation of wake-coupled pairs
WAKE_WEIGHT = 1.5
for i in range(N_POSITIONS):
    for j in range(N_POSITIONS):
        if wake_penalty[i][j] > 0.01:
            bqm.add_interaction(i, j, WAKE_WEIGHT * wake_penalty[i][j])

# Cable routing: reward spatially compact clusters (minimize total cable length proxy)
# Negative coupling encourages turbines to cluster along cable corridors
CABLE_WEIGHT = 0.3
for i in range(N_POSITIONS):
    for j in range(i + 1, N_POSITIONS):
        if cable_cost[i][j] < 2.5:  # only nearby pairs
            bqm.add_interaction(i, j, -CABLE_WEIGHT / (cable_cost[i][j] + 0.1))

# Cardinality constraint: exactly N_TURBINES turbines placed
# Penalty: lambda * (sum(x) - N_TURBINES)^2
LAMBDA = 10.0
linear_penalty = LAMBDA * (1 - 2 * N_TURBINES)
quad_penalty = LAMBDA * 2.0

for i in range(N_POSITIONS):
    bqm.add_variable(i, linear_penalty)
    for j in range(i + 1, N_POSITIONS):
        bqm.add_interaction(i, j, quad_penalty)

# Submit to D-Wave Leap hybrid sampler
sampler = LeapHybridSampler()
result = sampler.sample(bqm, time_limit=60)
best = result.first.sample

placed_turbines = [i for i, val in best.items() if val == 1]
print(f"Turbines placed: {len(placed_turbines)}")
print(f"BQM energy: {result.first.energy:.4f}")

Cable Routing Co-Optimization with QAOA

Once a candidate turbine layout was produced by the D-Wave annealer, a secondary QAOA pass on IBM Eagle optimized the cable routing topology. Offshore wind cables form a radial tree connecting turbine clusters to offshore substations. The cable routing problem is formulated as a minimum spanning tree variant with capacity constraints (each cable string carries at most 8 turbines).

from qiskit_optimization import QuadraticProgram
from qiskit_optimization.algorithms import MinimumEigenOptimizer
from qiskit_algorithms import QAOA
from qiskit_algorithms.optimizers import SPSA
from qiskit.primitives import Sampler
import networkx as nx

# Build graph of placed turbines + substation nodes
# placed_turbines: list of position indices from D-Wave result
# substation_positions: fixed OSS (offshore substation) locations

def build_cable_qp(placed_turbines, distances, max_string_length=8):
    """Formulate cable routing as a QUBO for string assignment."""
    n = len(placed_turbines)
    n_strings = n // max_string_length + 1

    qp = QuadraticProgram()

    # Binary variable x_{t,s}: turbine t assigned to string s
    for t in range(n):
        for s in range(n_strings):
            qp.binary_var(name=f"x_{t}_{s}")

    # Objective: minimize total cable length within each string
    # Approximate as sum of distances between consecutive turbines in string
    obj_linear = {}
    obj_quadratic = {}

    for t in range(n):
        for s in range(n_strings):
            # Linear: base cable cost to substation for each turbine
            obj_linear[f"x_{t}_{s}"] = distances[t]["substation_s"] + 0.1

    for t1 in range(n):
        for t2 in range(t1 + 1, n):
            for s in range(n_strings):
                # Quadratic: reward co-assignment of close turbines to same string
                d = distances[t1][t2]
                obj_quadratic[(f"x_{t1}_{s}", f"x_{t2}_{s}")] = -1.0 / (d + 0.5)

    qp.minimize(linear=obj_linear, quadratic=obj_quadratic)

    # Constraint: each turbine assigned to exactly one string
    for t in range(n):
        qp.linear_constraint(
            linear={f"x_{t}_{s}": 1 for s in range(n_strings)},
            sense="==",
            rhs=1,
            name=f"turbine_{t}_assignment"
        )

    # Constraint: each string has at most max_string_length turbines
    for s in range(n_strings):
        qp.linear_constraint(
            linear={f"x_{t}_{s}": 1 for t in range(n)},
            sense="<=",
            rhs=max_string_length,
            name=f"string_{s}_capacity"
        )

    return qp

# For small subproblems (20-30 turbines), run QAOA on IBM Eagle
qp_small = build_cable_qp(placed_turbines[:24], distances_subset, max_string_length=8)

sampler = Sampler()
optimizer = SPSA(maxiter=300)
qaoa = QAOA(sampler=sampler, optimizer=optimizer, reps=3)
cable_solver = MinimumEigenOptimizer(qaoa)

cable_result = cable_solver.solve(qp_small)
print(f"Cable routing objective: {cable_result.fval:.4f}")

Comparison to CMA-ES Baseline

RWE’s standard layout optimizer uses CMA-ES, a derivative-free evolutionary strategy that iteratively updates a multivariate Gaussian to sample candidate layouts. CMA-ES is effective for continuous placement problems but struggles when cable routing is included as a hard combinatorial constraint, tending to find good individual turbine positions while producing suboptimal cable topologies.

The quantum hybrid approach ran D-Wave annealing for layout (using the wake penalty QUBO) followed by QAOA for cable routing. For a 150-turbine North Sea farm simulation using historical wind data from the Borssele offshore zone, the combined quantum approach produced a layout with 3.2% higher annual energy production than the CMA-ES baseline. Cable routing cost fell by 8% because the QAOA string assignment found more compact radial configurations. Total computation time was similar to CMA-ES (approximately 2 hours per layout optimization run), with the quantum hardware calls taking roughly 15 minutes of wall time.

Scaling Outlook

The 150-turbine problem required decomposing the wake QUBO into overlapping subproblems of roughly 80-100 variables each (D-Wave Advantage has 5000+ qubits but sparse connectivity constrains effective problem size for dense QUBOs). RWE’s engineering team identified two near-term improvements: using graph-native QUBO reformulations that better match the Pegasus topology, and running QAOA cable optimization on larger subproblems as IBM’s processors scale. For RWE’s planned 300-turbine Dogger Bank extensions, the team projects further gains with next-generation quantum hardware, where the cable routing subproblem becomes the dominant value driver.