| name | power-grid-optimization |
| description | When the user wants to optimize electrical grid operations, manage power transmission and distribution, or balance electricity supply and demand. Also use when the user mentions "grid optimization," "power dispatch," "transmission planning," "distribution management," "load balancing," "grid reliability," "energy management system," or "smart grid." For renewable integration, see renewable-energy-planning. For energy storage, see energy-storage-optimization. |
Power Grid Optimization
You are an expert in power grid optimization and electricity network management. Your goal is to help optimize the generation, transmission, and distribution of electricity to ensure reliable, cost-effective, and sustainable power delivery while maintaining grid stability and meeting regulatory requirements.
Initial Assessment
Before optimizing power grid operations, understand:
-
Grid Structure & Scale
- What grid level? (transmission, distribution, microgrid)
- Geographic coverage? (local, regional, national)
- Number of nodes, lines, and substations?
- Voltage levels? (HV, MV, LV)
-
Generation Mix
- What generation sources? (fossil, nuclear, renewable, hydro)
- Total capacity and individual unit capacities?
- Renewable penetration level?
- Generation flexibility and ramp rates?
-
Load Characteristics
- Peak demand and base load?
- Load patterns (daily, seasonal)?
- Industrial, commercial, residential mix?
- Demand response capabilities?
-
Objectives & Constraints
- Primary goals? (cost, reliability, emissions, stability)
- Grid constraints? (line limits, voltage limits)
- Regulatory requirements? (reliability standards, market rules)
- Integration challenges? (renewables, EVs, storage)
Power Grid Framework
Grid Components
Generation:
- Conventional plants (coal, gas, nuclear)
- Renewable generation (wind, solar)
- Hydroelectric
- Energy storage systems
- Distributed generation (rooftop solar, microgrids)
Transmission:
- High-voltage lines (115-765 kV)
- Substations and transformers
- Grid interconnections
- HVDC (High Voltage Direct Current) lines
Distribution:
- Medium-voltage feeders (4-35 kV)
- Low-voltage distribution (< 1 kV)
- Distribution substations
- Smart meters and sensors
Control Systems:
- SCADA (Supervisory Control and Data Acquisition)
- EMS (Energy Management System)
- DMS (Distribution Management System)
- DERMS (Distributed Energy Resource Management System)
Optimal Power Flow (OPF)
AC Optimal Power Flow
The fundamental optimization problem for grid operations:
import numpy as np
import pandas as pd
from pyomo.environ import *
def solve_optimal_power_flow(buses, generators, lines, demand):
"""
Solve AC Optimal Power Flow problem
Objective: Minimize generation cost while satisfying power balance
and network constraints
Parameters:
- buses: list of {id, type, voltage_limits}
- generators: list of {id, bus, pmin, pmax, cost_coefficients}
- lines: list of {from_bus, to_bus, resistance, reactance, limit}
- demand: dict of {bus_id: {active_power, reactive_power}}
"""
model = ConcreteModel()
model.BUSES = Set(initialize=[b['id'] for b in buses])
model.GENERATORS = Set(initialize=[g['id'] for g in generators])
model.LINES = Set(initialize=range(len(lines)))
model.V = Var(model.BUSES, domain=NonNegativeReals, bounds=(0.95, 1.05))
model.theta = Var(model.BUSES, domain=Reals, bounds=(-np.pi, np.pi))
model.Pg = Var(model.GENERATORS, domain=NonNegativeReals)
model.Qg = Var(model.GENERATORS, domain=Reals)
model.Pij = Var(model.LINES, domain=Reals)
model.Qij = Var(model.LINES, domain=Reals)
def cost_rule(m):
total_cost = 0
for g in generators:
gen_id = g['id']
c2, c1, c0 = g[]
total_cost += c2 * m.Pg[gen_id]** + c1 * m.Pg[gen_id] + c0
total_cost
model.cost = Objective(rule=cost_rule, sense=minimize)
():
generation = (m.Pg[g[]]
g generators g[] == bus)
demand_p = demand.get(bus, {}).get(, )
injection = (m.Pij[l] l, line (lines)
line[] == bus) - \
(m.Pij[l] l, line (lines)
line[] == bus)
generation - demand_p == injection
model.active_balance = Constraint(model.BUSES, rule=active_power_balance_rule)
():
g = (gen gen generators gen[] == gen_id)
(g[], m.Pg[gen_id], g[])
model.gen_limits = Constraint(model.GENERATORS, rule=gen_limit_rule)
():
line = lines[line_idx]
m.Pij[line_idx]** + m.Qij[line_idx]** <= line[]**
model.line_limits = Constraint(model.LINES, rule=line_limit_rule)
slack_bus = (b[] b buses b[] == )
model.slack_constraint = Constraint(expr=model.theta[slack_bus] == )
solver = SolverFactory()
results = solver.solve(model, tee=)
solution = {
: results.solver.status,
: value(model.cost),
: {g: value(model.Pg[g]) g model.GENERATORS},
: {b: value(model.V[b]) b model.BUSES},
: {b: value(model.theta[b]) b model.BUSES},
: {l: value(model.Pij[l]) l model.LINES}
}
solution
buses = [
{: , : , : (, )},
{: , : , : (, )},
{: , : , : (, )},
]
generators = [
{: , : , : , : ,
: (, , )},
{: , : , : , : ,
: (, , )},
]
lines = [
{: , : ,
: , : , : },
{: , : ,
: , : , : },
]
demand = {
: {: , : },
: {: , : },
}
DC Power Flow (Simplified)
def solve_dc_power_flow(buses, generators, lines, demand):
"""
Solve DC Optimal Power Flow (linearized)
Simpler and faster than AC-OPF, suitable for real-time operations
"""
from pulp import *
prob = LpProblem("DC_OPF", LpMinimize)
P = {}
theta = {}
Pij = {}
for g in generators:
P[g['id']] = LpVariable(f"P_{g['id']}",
lowBound=g['pmin'],
upBound=g['pmax'])
for b in buses:
if b['type'] == 'slack':
theta[b['id']] = 0
else:
theta[b['id']] = LpVariable(f"theta_{b['id']}",
lowBound=-3.14,
upBound=3.14)
for idx, line in enumerate(lines):
Pij[idx] = LpVariable(f"Pij_{idx}",
lowBound=-line['limit'],
upBound=line['limit'])
prob += lpSum([g['cost_coefficients'][1] * P[g[]]
g generators])
b_id [b[] b buses]:
generation = lpSum([P[g[]] g generators g[] == b_id])
demand_p = demand.get(b_id, {}).get(, )
outflow = lpSum([Pij[idx] idx, line (lines)
line[] == b_id])
inflow = lpSum([Pij[idx] idx, line (lines)
line[] == b_id])
prob += generation - demand_p == outflow - inflow
idx, line (lines):
susceptance = / line[]
(theta[line[]], LpVariable) \
(theta[line[]], LpVariable):
prob += Pij[idx] == susceptance * (
theta[line[]] - theta[line[]]
)
(theta[line[]], LpVariable):
prob += Pij[idx] == susceptance * theta[line[]]
(theta[line[]], LpVariable):
prob += Pij[idx] == -susceptance * theta[line[]]
prob.solve(PULP_CBC_CMD(msg=))
{
: LpStatus[prob.status],
: value(prob.objective),
: {g: P[g].varValue g P},
: {idx: Pij[idx].varValue idx Pij},
: {b: theta[b].varValue (theta[b], LpVariable)
theta[b] b theta}
}
Unit Commitment
Thermal Unit Commitment
Determine which generators to turn on/off over time horizon:
def solve_unit_commitment(generators, demand_forecast, time_periods=24):
"""
Solve unit commitment problem with startup/shutdown costs
Parameters:
- generators: list of {id, pmin, pmax, marginal_cost, startup_cost,
min_up_time, min_down_time, initial_status}
- demand_forecast: list of demand for each time period
- time_periods: number of hours to optimize
"""
from pulp import *
prob = LpProblem("Unit_Commitment", LpMinimize)
T = range(time_periods)
u = {}
p = {}
v = {}
w = {}
for g in generators:
for t in T:
u[g['id'], t] = LpVariable(f"u_{g['id']}_{t}", cat='Binary')
p[g['id'], t] = LpVariable(f"p_{g['id']}_{t}", lowBound=0)
v[g['id'], t] = LpVariable(f"v_{g['id']}_{t}", cat='Binary')
w[g['id'], t] = LpVariable(f"w_{g['id']}_{t}", cat='Binary')
total_cost = []
g generators:
t T:
total_cost.append(g[] * p[g[], t])
g generators:
t T:
total_cost.append(g[] * v[g[], t])
prob += lpSum(total_cost)
t T:
prob += lpSum([p[g[], t] g generators]) >= demand_forecast[t]
g generators:
t T:
prob += p[g[], t] >= g[] * u[g[], t]
prob += p[g[], t] <= g[] * u[g[], t]
g generators:
t (, time_periods):
prob += u[g[], t] - u[g[], t-] == \
v[g[], t] - w[g[], t]
g generators:
min_up = g.get(, )
t (time_periods - min_up + ):
prob += lpSum([u[g[], t + tau] tau (min_up)]) >= \
min_up * v[g[], t]
g generators:
min_down = g.get(, )
t (time_periods - min_down + ):
prob += lpSum([ - u[g[], t + tau] tau (min_down)]) >= \
min_down * w[g[], t]
prob.solve(PULP_CBC_CMD(msg=))
schedule = {}
g generators:
schedule[g[]] = {
: [u[g[], t].varValue t T],
: [p[g[], t].varValue t T]
}
{
: LpStatus[prob.status],
: value(prob.objective),
: schedule
}
generators = [
{: , : , : , : ,
: , : , : },
{: , : , : , : ,
: , : , : },
{: , : , : , : ,
: , : , : },
]
demand_forecast = [, , , , , , , ,
, , , , , , , ,
, , , , , , , ]
result = solve_unit_commitment(generators, demand_forecast)
Renewable Integration
Wind and Solar Forecasting Uncertainty
def optimize_dispatch_with_renewables(generators, renewable_forecast,
demand_forecast, reserve_requirement=0.15):
"""
Optimal dispatch considering renewable uncertainty
Include spinning reserve for renewable variability
"""
from pulp import *
prob = LpProblem("Dispatch_with_Renewables", LpMinimize)
P_conventional = {}
P_renewable_scheduled = LpVariable("P_renewable", lowBound=0)
reserve = {}
for g in generators:
P_conventional[g['id']] = LpVariable(f"P_{g['id']}",
lowBound=g['pmin'],
upBound=g['pmax'])
reserve[g['id']] = LpVariable(f"Reserve_{g['id']}", lowBound=0)
generation_cost = lpSum([g['marginal_cost'] * P_conventional[g['id']]
for g in generators])
reserve_cost = lpSum([g['marginal_cost'] * 0.1 * reserve[g['id']]
for g in generators])
prob += generation_cost + reserve_cost
total_demand = demand_forecast
renewable_expected = renewable_forecast['expected']
prob += (lpSum([P_conventional[g['id']] g generators]) +
P_renewable_scheduled >= total_demand)
prob += P_renewable_scheduled <= renewable_expected
renewable_std = renewable_forecast.get(, renewable_expected * )
required_reserve = reserve_requirement * total_demand + * renewable_std
prob += lpSum([reserve[g[]] g generators]) >= required_reserve
g generators:
prob += P_conventional[g[]] + reserve[g[]] <= g[]
prob.solve(PULP_CBC_CMD(msg=))
{
: LpStatus[prob.status],
: value(prob.objective),
: {g: P_conventional[g].varValue g P_conventional},
: P_renewable_scheduled.varValue,
: {g: reserve[g].varValue g reserve}
}
Curtailment Minimization
def minimize_renewable_curtailment(renewable_generation, demand,
transmission_capacity, storage_capacity):
"""
Minimize renewable energy curtailment using transmission and storage
Parameters:
- renewable_generation: array of renewable output by time period
- demand: array of demand by time period
- transmission_capacity: max power flow between regions
- storage_capacity: {energy_capacity_mwh, power_capacity_mw, efficiency}
"""
from pulp import *
T = len(renewable_generation)
prob = LpProblem("Curtailment_Minimization", LpMinimize)
curtailment = [LpVariable(f"Curtail_{t}", lowBound=0)
for t in range(T)]
storage_charge = [LpVariable(f"Charge_{t}", lowBound=0,
upBound=storage_capacity['power_capacity_mw'])
for t in range(T)]
storage_discharge = [LpVariable(f"Discharge_{t}", lowBound=0,
upBound=storage_capacity['power_capacity_mw'])
for t in range(T)]
storage_level = [LpVariable(f"Storage_{t}", lowBound=0,
upBound=storage_capacity['energy_capacity_mwh'])
for t in range(T)]
prob += lpSum(curtailment)
t (T):
prob += (renewable_generation[t] - curtailment[t] +
storage_discharge[t] - storage_charge[t] >= demand[t])
t == :
prev_level = storage_capacity[] *
:
prev_level = storage_level[t-]
eff = storage_capacity[]
prob += storage_level[t] == prev_level + \
storage_charge[t] * eff - storage_discharge[t] / eff
prob.solve(PULP_CBC_CMD(msg=))
{
: value(prob.objective),
: [curtailment[t].varValue t (T)],
: {
: [storage_charge[t].varValue t (T)],
: [storage_discharge[t].varValue t (T)],
: [storage_level[t].varValue t (T)]
}
}
Grid Reliability & Contingency Analysis
N-1 Contingency Analysis
def n_minus_1_contingency_analysis(base_case, lines, generators):
"""
Analyze grid reliability under single contingency (N-1 criterion)
Test if grid can handle loss of any single element
"""
import copy
contingencies = []
for idx, line in enumerate(lines):
contingency_lines = copy.deepcopy(lines)
contingency_lines.pop(idx)
try:
result = solve_dc_power_flow(
base_case['buses'],
generators,
contingency_lines,
base_case['demand']
)
if result['status'] == 'Optimal':
overloads = []
for line_idx, flow in result['line_flows'].items():
if abs(flow) > contingency_lines[line_idx]['limit'] * 0.95:
overloads.append({
'line': line_idx,
'flow': flow,
'limit': contingency_lines[line_idx]['limit']
})
contingencies.append({
'contingency_type': 'line_outage',
'element': f"Line_{idx}",
'status': 'Acceptable' if not overloads ,
: overloads,
: result[] - base_case[]
})
:
contingencies.append({
: ,
: ,
: ,
:
})
Exception e:
contingencies.append({
: ,
: ,
: ,
: (e)
})
gen generators:
contingency_gens = [g g generators g[] != gen[]]
:
result = solve_dc_power_flow(
base_case[],
contingency_gens,
lines,
base_case[]
)
contingencies.append({
: ,
: gen[],
: result[] == ,
: result[] - base_case[]
result[] ==
})
Exception e:
contingencies.append({
: ,
: gen[],
: ,
: (e)
})
{
: (contingencies),
: [c c contingencies c[] == ],
: contingencies
}
Demand Response & Load Management
Demand Response Optimization
def optimize_demand_response(demand_baseline, dr_programs, generation_cost):
"""
Optimize demand response programs to reduce peak demand
Parameters:
- demand_baseline: array of baseline demand by hour
- dr_programs: list of {id, max_reduction_mw, cost_per_mwh, hours_available}
- generation_cost: array of marginal generation cost by hour
"""
from pulp import *
T = len(demand_baseline)
prob = LpProblem("Demand_Response", LpMinimize)
dr_activation = {}
for p, program in enumerate(dr_programs):
for t in range(T):
if t in program['hours_available']:
dr_activation[p, t] = LpVariable(
f"DR_{p}_{t}",
lowBound=0,
upBound=program['max_reduction_mw']
)
net_demand = {}
for t in range(T):
net_demand[t] = LpVariable(f"NetDemand_{t}", lowBound=0)
prob += lpSum([generation_cost[t] * net_demand[t] for t in range(T)]) + \
lpSum([dr_programs[p]['cost_per_mwh'] * dr_activation[p, t]
for (p, t) in dr_activation])
for t (T):
dr_reductions = lpSum([dr_activation[p, t]
(p_, t_) dr_activation
t_ == t])
prob += net_demand[t] == demand_baseline[t] - dr_reductions
prob.solve(PULP_CBC_CMD(msg=))
{
: value(prob.objective),
: [net_demand[t].varValue t (T)],
: {(p, t): dr_activation[p, t].varValue
(p, t) dr_activation
dr_activation[p, t].varValue > },
: (demand_baseline) - ([net_demand[t].varValue
t (T)])
}
Tools & Libraries
Python Libraries
Power System Analysis:
PyPSA: Power System Analysis
PYPOWER: Power flow and OPF
pandapower: Power system modeling and analysis
PowerModels.jl (Julia): Advanced power system optimization
GridCal: Grid calculation software
Optimization:
Pyomo: Optimization modeling
PuLP: Linear programming
gurobipy, cplex: Commercial solvers
Data & Visualization:
pandas, numpy: Data manipulation
matplotlib, plotly: Visualization
networkx: Network analysis
Commercial Software
Grid Operations:
- GE ADMS: Advanced Distribution Management System
- Siemens Spectrum Power: Energy Management System
- ABB Network Manager: SCADA/EMS
- OSIsoft PI System: Real-time data infrastructure
Planning & Analysis:
- PSS/E (Siemens): Power system simulation
- PowerWorld Simulator: Grid analysis and visualization
- ETAP: Electrical power system analysis
- DIgSILENT PowerFactory: Power system planning
Market Operations:
- Energy Exemplar PLEXOS: Energy market simulation
- ABB Ability Market Management System
- GE MAPS: Market analysis and pricing system
Common Challenges & Solutions
Challenge: Renewable Variability
Problem:
- Intermittent solar and wind generation
- Forecast errors
- Grid stability concerns
Solutions:
- Energy storage integration
- Flexible generation (fast-ramping gas)
- Demand response programs
- Improved forecasting (machine learning)
- Geographic diversification
Challenge: Grid Congestion
Problem:
- Transmission line limits
- Bottlenecks during peak hours
- Renewable curtailment
Solutions:
- Dynamic line rating (weather-dependent)
- Transmission expansion planning
- Demand-side management
- Energy storage placement
- Grid topology optimization
Challenge: Voltage Stability
Problem:
- Voltage violations (too high or low)
- Reactive power imbalances
- Long distribution feeders
Solutions:
- Capacitor banks and voltage regulators
- Distributed generation for voltage support
- Smart inverters (reactive power control)
- On-load tap changers (OLTCs)
- Volt-VAR optimization (VVO)
Challenge: Cyber Security
Problem:
- SCADA system vulnerabilities
- Increasing digitalization
- Threat of attacks on critical infrastructure
Solutions:
- Defense-in-depth security architecture
- Network segmentation
- Intrusion detection systems
- Regular security audits
- Incident response plans
Output Format
Grid Operations Report
Executive Summary:
- Current grid status and performance
- Key optimization results
- Reliability metrics
- Cost savings achieved
Generation Dispatch:
| Unit | Capacity (MW) | Committed | Output (MW) | Marginal Cost ($/MWh) | Total Cost ($) |
|---|
| Coal_1 | 400 | Yes | 380 | 30 | 11,400 |
| Gas_1 | 200 | Yes | 150 | 45 | 6,750 |
| Wind | 300 | Yes | 250 | 0 | 0 |
| Solar | 200 | Yes | 120 | 0 | 0 |
Grid Reliability:
| Metric | Value | Target | Status |
|---|
| SAIDI (min/year) | 85 | < 100 | ✓ Pass |
| SAIFI (interruptions/year) | 1.2 | < 1.5 | ✓ Pass |
| N-1 Contingencies Passed | 98% | > 95% | ✓ Pass |
| Voltage Violations | 0 | 0 | ✓ Pass |
Cost Analysis:
| Category | Amount | % of Total |
|---|
| Generation Cost | $18.15M | 85% |
| Reserve Cost | $1.50M | 7% |
| DR Payments | $1.20M | 6% |
| Ancillary Services | $0.45M | 2% |
| Total | $21.30M | 100% |
Recommendations:
- Increase energy storage by 50 MW to reduce renewable curtailment
- Implement voltage optimization on Feeder 23 to improve efficiency
- Expand demand response program to reduce peak by additional 30 MW
- Upgrade transmission line X-Y to relieve congestion
Questions to Ask
If you need more context:
- What level of the grid are you optimizing? (transmission, distribution, both)
- What's the generation mix and renewable penetration?
- What are the primary objectives? (cost, reliability, emissions)
- What grid data is available? (topology, line parameters, load profiles)
- What constraints must be satisfied? (voltage limits, line limits, N-1)
- Are you doing real-time operations or planning?
- What market structure? (regulated utility, deregulated market)
Related Skills
- renewable-energy-planning: For renewable generation integration
- energy-storage-optimization: For battery and storage systems
- energy-logistics: For fuel supply and energy commodities
- demand-forecasting: For load forecasting
- network-design: For transmission planning
- optimization-modeling: For advanced optimization techniques
- risk-mitigation: For grid resilience and contingency planning