Optimizing Offshore Wind Siting in California

Led a five-person team that built a Python optimization model to site offshore wind turbines off California, balancing wind output against ecological impacts, shipping congestion, and grid constraints.

Project lead, with Sophie Castillo, Gabe Hiestand, Paola Lorusso, and Whitley Rummel · CE 295 class project, UC Berkeley, 2024

At a glance

Role Project lead: proposed and scoped the project; wrote the motivation, methodology, and policy sections
Methods Constrained optimization with penalty functions, weight optimization, geospatial analysis
Tools Python (pandas, GeoPandas, SciPy), ArcGIS
Skills Renewable resource planning, optimization, geospatial data, policy translation
Available on request Full notebook and final report

The question

California plans 25 GW of offshore wind by 2045. The state’s siting work relied on overlaying map layers in GIS and screened sites mainly on technical criteria, leaving ecological and economic conflicts largely unresolved. We asked where turbines should go once those conflicts are counted.

What I did

  1. Led the project. Proposed the idea, assembled the team, and scoped the problem against the California Energy Commission’s siting approach.
  2. Designed the approach. Framed siting as an optimization over 2.75 km grid cells: maximize wind output, with penalties for shipping lanes, marine habitat, whale migration, and distance from existing grid infrastructure.
  3. Supported the modeling. Sourced and processed geospatial data and helped teammates build and run the model.
  4. Translated results for policymakers. Wrote the background, methodology, and policy implications, including how regulators can adjust the weights to reflect their priorities.
How the model works: screen the sea space, score every 2.75 km cell as wind output minus weighted penalties, then compare equal and optimized weights.
Top-scoring cells (score ≥ 0.8) from the team's optimization, compared with the California Energy Commission's candidate areas.

What it shows

  • A sharper map. Results match most of the Commission’s priority areas in Northern California, but screen out Monterey because of whale activity that the map-overlay approach missed.
  • Real trade-offs. Few sites combine strong wind with low conflict, so meeting the 2045 goal will require accepting some.
  • From model to policy. A technical tool framed so regulators can use it.

Code highlights

Excerpts from the team’s Python notebook, lightly edited for readability. The full notebook is available on request.

Wind power in each grid cell, from annual average wind speed and a 17 MW-class floating turbine:

def power_output(air_density, swept_area, wind_speed, power_coefficient):
    return 0.5 * air_density * swept_area * wind_speed**3 * power_coefficient

data["power_output_MW"] = power_output(
    air_density=1.225,               # kg/m^3
    swept_area=3.14 * 120**2,        # m^2, ~240 m rotor
    wind_speed=data["Annual_A_1"],   # m/s, Data Basin offshore wind aliquots
    power_coefficient=16 / 27,       # Betz limit, used as a relative metric
) / 1e6

Scoring each cell: normalized output minus weighted, normalized penalties:

penalties = ["Normalized_Penalty",          # shipping lanes
             "normalized_power_plant_Pen",  # distance from existing coastal plants
             "Marine_Penalty",              # whale and sea turtle critical habitat
             "P_TW"]                        # toothed whale migration density

def score(data, w):
    return data["normalized_power_output_MW"] - data[penalties].values @ w

data["score_equal"] = score(data, np.full(4, 0.25))

Choosing the weights with SLSQP, so the result shows which constraints matter most:

from scipy.optimize import minimize

res = minimize(lambda w: -score(data, w).mean(),
               x0=np.array([0.5, 1, 1, 1]) / 3.5,
               bounds=[(0, 1)] * 4, method="SLSQP")
optimal_w = res.x / res.x.sum()
data["score_optimized"] = score(data, optimal_w)

The report and code are available to employers on request. Contact me.