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
- Led the project. Proposed the idea, assembled the team, and scoped the problem against the California Energy Commission’s siting approach.
- 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.
- Supported the modeling. Sourced and processed geospatial data and helped teammates build and run the model.
- Translated results for policymakers. Wrote the background, methodology, and policy implications, including how regulators can adjust the weights to reflect their priorities.
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.