Multi-Objective Optimization¶
Generate Pareto-optimal solutions that show tradeoffs between competing objectives using the NSGA-II evolutionary algorithm.
Endpoint¶
Request¶
{
"site": {
"latitude": 35.0,
"longitude": -110.0,
"capacity_kw": 1000
},
"objectives": ["energy", "lcoe"],
"generations": 100,
"population_size": 50
}
Parameters¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
site |
object | Yes | - | Site configuration |
objectives |
array | Yes | - | 2-3 objectives to optimize |
generations |
int | No | 100 | Number of NSGA-II generations |
population_size |
int | No | 50 | Population size per generation |
Available Objectives¶
| Objective | Direction | Description |
|---|---|---|
energy |
Maximize | Annual energy (MWh) |
lcoe |
Minimize | Levelized cost (¢/kWh) |
land_use |
Minimize | Land area required (ha) |
Response¶
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"pareto_front": [
{
"tilt": 28.5,
"azimuth": 180.0,
"dc_ac_ratio": 1.20,
"gcr": 0.45,
"objectives": {
"energy": 1920.5,
"lcoe": 3.85
}
},
{
"tilt": 32.0,
"azimuth": 180.0,
"dc_ac_ratio": 1.25,
"gcr": 0.38,
"objectives": {
"energy": 1850.2,
"lcoe": 3.45
}
},
{
"tilt": 35.5,
"azimuth": 180.0,
"dc_ac_ratio": 1.30,
"gcr": 0.32,
"objectives": {
"energy": 1780.8,
"lcoe": 3.25
}
}
],
"num_solutions": 25,
"optimization_time_seconds": 45.2
}
Understanding Pareto Fronts¶
A Pareto front contains solutions where improving one objective requires sacrificing another.
Energy (MWh)
^
| * High energy, high cost
| *
| * <- Pareto Front (all optimal)
| *
|* Low energy, low cost
+-----------------------> LCOE (¢/kWh)
No solution on the Pareto front dominates another - they represent different tradeoffs.
Code Examples¶
import requests
import time
# Submit multi-objective job
response = requests.post(
"https://api.tessellaterenewables.com/solar/optimization/multi",
json={
"site": {
"latitude": 35.0,
"longitude": -110.0,
"capacity_kw": 1000
},
"objectives": ["energy", "lcoe"],
"generations": 100,
"population_size": 50
}
)
job_id = response.json()["job_id"]
# Poll for results
while True:
result = requests.get(
f"https://api.tessellaterenewables.com/solar/optimization/{job_id}"
).json()
if result["status"] == "completed":
break
time.sleep(2)
# Analyze Pareto front
pareto = result["pareto_front"]
print(f"Found {len(pareto)} Pareto-optimal solutions:\n")
for i, sol in enumerate(pareto):
print(f"Solution {i+1}:")
print(f" Tilt: {sol['tilt']:.1f}°, GCR: {sol['gcr']:.2f}")
print(f" Energy: {sol['objectives']['energy']:.0f} MWh")
print(f" LCOE: {sol['objectives']['lcoe']:.2f} ¢/kWh")
print()
import requests
import matplotlib.pyplot as plt
# ... (get results as above) ...
# Plot Pareto front
energies = [s['objectives']['energy'] for s in pareto]
lcoes = [s['objectives']['lcoe'] for s in pareto]
plt.figure(figsize=(10, 6))
plt.scatter(lcoes, energies, s=100, c='orange', edgecolors='black')
plt.xlabel('LCOE (¢/kWh)')
plt.ylabel('Annual Energy (MWh)')
plt.title('Pareto Front: Energy vs LCOE')
plt.grid(True, alpha=0.3)
# Annotate some points
for i in [0, len(pareto)//2, -1]:
sol = pareto[i]
plt.annotate(
f"Tilt={sol['tilt']:.0f}°",
(sol['objectives']['lcoe'], sol['objectives']['energy']),
textcoords="offset points", xytext=(10,5)
)
plt.tight_layout()
plt.savefig('pareto_front.png')
Choosing a Solution¶
The Pareto front gives you options. Choose based on priorities:
| Priority | Select Solution With |
|---|---|
| Maximum energy | Highest energy value |
| Minimum cost | Lowest lcoe value |
| Balanced | Middle of Pareto front |
| Budget-constrained | Lowest lcoe meeting energy target |
# Example: Find solution closest to target
target_energy = 1850 # MWh
target_lcoe = 3.5 # ¢/kWh
best = min(pareto, key=lambda s: (
(s['objectives']['energy'] - target_energy)**2 +
(s['objectives']['lcoe'] - target_lcoe)**2 * 10000 # Scale LCOE
))
print(f"Best balanced solution: Tilt={best['tilt']:.1f}°")
Three-Objective Optimization¶
You can optimize three objectives simultaneously:
This creates a 3D Pareto surface, useful when land constraints matter.
Performance Tips¶
| Setting | Faster | More Thorough |
|---|---|---|
generations |
50 | 200 |
population_size |
30 | 100 |
| Expected time | ~15s | ~120s |
| Solutions found | 10-20 | 50-100 |