el1xr_opt.Modules.oM_ACOPF#

el1xr_opt.Modules.oM_ACOPF.build_branches(network_df)[source]#

Turn an el1xr ElectricityNetwork DataFrame into a list of branch dicts.

Expects the (InitialNode, FinalNode, Circuit) multi-index (the unnamed index columns) and Reactance / optional Resistance columns. Per-unit values are used as given. A missing/zero reactance branch is skipped (not a real series element).

el1xr_opt.Modules.oM_ACOPF.solve_acopf_nlp(branches, Pd, Qd, slack, v0=1.0, vmin=0.9, vmax=1.1, qlim=3.0, plim=10.0, solver='ipopt', init_v=None, init_th=None)[source]#

Exact polar-form AC OPF. Pd/Qd: dict bus->net load (p.u.). Returns a result dict (objective = total slack-bus injection ~ losses + net import).

init_v / init_th give a warm start (bus -> value); on a stressed radial feeder a flat start often fails, so passing the SOC relaxation’s voltages is the reliable way to converge.

el1xr_opt.Modules.oM_ACOPF.solve_acopf_socp(branches, Pd, Qd, slack, v0=1.0, vmin=0.9, vmax=1.1, solver='gurobi')[source]#

Branch-flow (DistFlow) SOC relaxation on a radial network. Returns a result dict including the per-branch relaxation gap l*v - (P^2+Q^2) (0 = exact).

el1xr_opt.Modules.oM_ACOPF.solve_acopf(network_df, Pd, Qd, slack, formulation='socp', warm_start=True, **kw)[source]#

Dispatch by formulation. Pd/Qd are dicts bus -> net load in per unit.

For formulation='nlp' on a radial network the SOC relaxation is solved first (cheap, convex) and its voltages are used to warm-start the non-convex NLP, which otherwise often fails from a flat start on a stressed feeder.

el1xr_opt.Modules.oM_ACOPF.run_acopf_sweep(network_df, snapshots, slack, formulation='socp', vmin_check=0.95, vmax_check=1.05, vmin_solve=0.0, vmax_solve=1.5, **kw)[source]#

Run AC OPF over many snapshots and summarise voltage/loss violations.

snapshots is a list of (label, Pd, Qd) (per-unit nodal loads). Each is solved with permissive voltage bounds (vmin_solve/vmax_solve) so the actual power-flow voltages are found, then checked against the nominal limits vmin_check/vmax_check to count violations. This is the Phase-5b sweep: one AC OPF per representative period, with a year/horizon violation summary.

Returns a list of per-snapshot dicts: label, loss, vmin, vmax, violations, status. A snapshot that fails to solve (e.g. voltage collapse at high load) is recorded with status ‘infeasible/error’ rather than aborting the sweep.

el1xr_opt.Modules.oM_ACOPF.scaled_snapshots(Pd, Qd, factors)[source]#

Build snapshots by scaling a base load by each factor in factors (e.g. a daily/seasonal profile). factors is a dict label -> multiplier.

el1xr_opt.Modules.oM_ACOPF.snapshots_from_case(dir_name, case_name, load_levels=None)[source]#

Build AC OPF snapshots from a case’s demand data: per-node net load at each requested load level. Reads the case through the standard input source, maps demands to their nodes, and sums per node. load_levels defaults to all.

This is the interface for running the sweep on a real case once it has a multi-bus network; on the current single-zone sample cases it returns one bus of load, so it is mainly the wiring for multi-bus distribution cases.

el1xr_opt.Modules.oM_ACOPF.write_acopf_sweep(db_path, case, rows)[source]#

Write the per-snapshot sweep summary to a DuckDB table.

el1xr_opt.Modules.oM_ACOPF.write_acopf_results(db_path, case, result)[source]#

Append AC OPF results (per-bus voltages + summary) to a DuckDB file.