Full Optimization¶
Run a comprehensive optimization job with custom bounds, constraints, and iteration control. Returns a job ID for async polling.
Endpoint¶
Request¶
{
"site": {
"latitude": 35.0,
"longitude": -110.0,
"capacity_kw": 1000,
"land_area_ha": 10
},
"objective": "npv",
"max_iterations": 50,
"bounds": {
"tilt_min": 15,
"tilt_max": 45,
"azimuth_min": 160,
"azimuth_max": 200,
"dc_ac_ratio_min": 1.1,
"dc_ac_ratio_max": 1.4,
"gcr_min": 0.3,
"gcr_max": 0.5
},
"constraints": {
"max_budget": 1000000,
"min_annual_energy_kwh": 1500000,
"min_capacity_factor": 0.18
}
}
Parameters¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
site.latitude |
float | Yes | - | Site latitude |
site.longitude |
float | Yes | - | Site longitude |
site.capacity_kw |
float | Yes | - | DC capacity in kW |
site.land_area_ha |
float | No | - | Available land (hectares) |
objective |
string | No | energy |
Optimization objective |
max_iterations |
int | No | 50 | Maximum optimization iterations |
bounds |
object | No | defaults | Parameter bounds |
constraints |
object | No | none | Hard constraints |
Bounds¶
| Field | Default Min | Default Max | Description |
|---|---|---|---|
tilt_min/max |
0 | 60 | Tilt angle (degrees) |
azimuth_min/max |
90 | 270 | Azimuth angle (degrees) |
dc_ac_ratio_min/max |
1.0 | 1.6 | DC/AC ratio |
gcr_min/max |
0.2 | 0.6 | Ground coverage ratio |
Constraints¶
| Field | Description |
|---|---|
max_budget |
Maximum CAPEX in USD |
min_annual_energy_kwh |
Minimum annual energy |
min_capacity_factor |
Minimum capacity factor |
Response (Job Created)¶
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"message": "Optimization job submitted",
"poll_url": "/solar/optimization/550e8400-e29b-41d4-a716-446655440000"
}
Polling for Results¶
Pending Response¶
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "running",
"progress": 45,
"stage": "Bayesian optimization iteration 23/50"
}
Completed Response¶
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"progress": 100,
"optimal_parameters": {
"tilt": 32.5,
"azimuth": 182.3,
"dc_ac_ratio": 1.28,
"gcr": 0.38
},
"energy_metrics": {
"annual_energy_mwh": 1850.5,
"capacity_factor": 0.211,
"specific_yield": 1850.5,
"performance_ratio": 0.82
},
"financial_metrics": {
"lcoe_cents_per_kwh": 3.45,
"npv_dollars": 1250000,
"irr_percent": 14.5,
"payback_years": 6.2
},
"optimization_time_seconds": 12.5,
"iterations_completed": 50
}
Code Examples¶
import requests
import time
# Submit job
response = requests.post(
"https://api.tessellaterenewables.com/solar/optimization/run",
json={
"site": {
"latitude": 35.0,
"longitude": -110.0,
"capacity_kw": 1000
},
"objective": "npv",
"max_iterations": 50,
"bounds": {
"tilt_min": 20,
"tilt_max": 40
}
}
)
job = response.json()
job_id = job["job_id"]
print(f"Job submitted: {job_id}")
# Poll for results
while True:
status_response = requests.get(
f"https://api.tessellaterenewables.com/solar/optimization/{job_id}"
)
result = status_response.json()
print(f"Status: {result['status']} ({result.get('progress', 0)}%)")
if result["status"] == "completed":
print(f"\nOptimal tilt: {result['optimal_parameters']['tilt']}°")
print(f"NPV: ${result['financial_metrics']['npv_dollars']:,.0f}")
break
elif result["status"] == "failed":
print(f"Error: {result.get('error_message')}")
break
time.sleep(2)
async function runFullOptimization(site, objective, bounds) {
// Submit job
const submitResponse = await fetch(
'https://api.tessellaterenewables.com/solar/optimization/run',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ site, objective, bounds })
}
);
const { job_id } = await submitResponse.json();
console.log(`Job submitted: ${job_id}`);
// Poll for results
while (true) {
const statusResponse = await fetch(
`https://api.tessellaterenewables.com/solar/optimization/${job_id}`
);
const result = await statusResponse.json();
console.log(`Status: ${result.status} (${result.progress || 0}%)`);
if (result.status === 'completed') {
return result;
} else if (result.status === 'failed') {
throw new Error(result.error_message);
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
# Submit job
JOB_RESPONSE=$(curl -s -X POST \
https://api.tessellaterenewables.com/solar/optimization/run \
-H "Content-Type: application/json" \
-d '{
"site": {"latitude": 35.0, "longitude": -110.0, "capacity_kw": 1000},
"objective": "npv"
}')
JOB_ID=$(echo $JOB_RESPONSE | jq -r '.job_id')
echo "Job ID: $JOB_ID"
# Poll for results
while true; do
RESULT=$(curl -s "https://api.tessellaterenewables.com/solar/optimization/$JOB_ID")
STATUS=$(echo $RESULT | jq -r '.status')
echo "Status: $STATUS"
if [ "$STATUS" = "completed" ]; then
echo $RESULT | jq '.optimal_parameters'
break
fi
sleep 2
done
Optimization Algorithm¶
The full optimization uses Bayesian Optimization with a Gaussian Process surrogate model:
- Initial sampling of parameter space
- Surrogate model fitting
- Acquisition function optimization (Expected Improvement)
- Iterative refinement until convergence or max iterations
This approach is sample-efficient and works well for expensive objective functions.
Job Status Values¶
| Status | Description |
|---|---|
pending |
Job queued, waiting to start |
running |
Optimization in progress |
completed |
Successfully completed |
failed |
Error occurred |
Tips¶
Choosing Iterations
- 20-30 iterations: Quick results, may not be globally optimal
- 50 iterations: Good balance (default)
- 100+ iterations: More thorough, diminishing returns