Comparison#
- spec_to_keyed_dict(spec, source='')#
Convert PfNetworkSpec to diff-friendly dict keyed by canonical IDs.
- Parameters:
spec -- Normalized power flow spec.
source -- Source file name for metadata.
- Returns:
Dict with meta + per-model dicts keyed by canonical identifiers.
- export_spec_json(spec, source='', *, indent=2, sort_keys=True)#
Export PfNetworkSpec to JSON string.
- Parameters:
spec -- Normalized power flow spec.
source -- Source file name for metadata.
indent -- JSON indentation level.
sort_keys -- Sort keys for deterministic output.
- Returns:
JSON string.
- export_spec_file(spec, path, source='')#
Export PfNetworkSpec to JSON file.
- Parameters:
spec -- Normalized power flow spec.
path -- Output file path.
source -- Source file name for metadata.
- diff_specs(spec_a, spec_b, source_a='A', source_b='B', *, tol=1e-06)#
Compare two normalized solver networks.
This comparison can show whether cases from different source formats represent the same network. An empty result means that all differences are within
tol.- Parameters:
spec_a -- First finalized
PfNetworkSpec.spec_b -- Second finalized
PfNetworkSpec.source_a -- Display name for the first network.
source_b -- Display name for the second network.
tol -- Relative numeric tolerance. The comparison ignores smaller differences.
- Returns:
A
CaseDiffgrouped by normalized network family and equipment identity. Added, removed, and changed values retain both source names.
- diff_cases(case_a, case_b, source_a='A', source_b='B', *, tol=0.0)#
Compare the equipment records and headers of two related cases.
The comparison matches equipment by its stable key, such as a bus number or branch terminal pair. Use
diff_specs()when two file formats should be compared after solver normalization.- Parameters:
case_a -- Source case.
case_b -- Target case.
source_a -- Display name for the source case.
source_b -- Display name for the target case.
tol -- Absolute tolerance for numeric field differences. Zero requires exact equality.
- Returns:
Added, removed, and changed records from
case_atocase_b.
- case_to_keyed_dict(case)#
Convert a case to records indexed by their stable equipment keys.
- Parameters:
case -- Case to convert.
- Returns:
The keyed record families and any duplicate-key warnings. The first record wins when a family contains a duplicate key.
- case_to_snapshot(case)#
Convert a case to a canonical JSON-compatible snapshot.
The snapshot contains every header field and equipment family. It can be restored with
case_from_snapshot().- Parameters:
case -- Case to serialize.
- Returns:
A snapshot that standard JSON encoders can serialize.
- case_from_snapshot(doc, *, allow_skew=False)#
Restore and validate a case from a canonical snapshot.
Older snapshots receive current field defaults. Unknown fields raise an error by default because they can contain data from a newer version.
- Parameters:
doc -- Snapshot created by
case_to_snapshot().allow_skew -- Drop unknown fields and add one finding for each drop.
- Returns:
The restored case.
- Raises:
SchemaSkewError -- If the snapshot has unknown fields and
allow_skewis false.
- class CaseDiff(source_a, source_b, tol, counts, added, removed, changed, warnings=<factory>)#
Record-level delta from
source_atosource_b.added/removedmapfamily -> {key: record_dump};changedmapsfamily -> {key: {field: (before, after)}}.countsis per-family(n_a, n_b)over every family. Empty inner dicts are omitted.- classmethod from_entries(entries)#
Build an exact record delta from authored before and after values.
- property is_empty#
Return true when the cases have no recorded differences.
- filtered(families)#
A copy restricted to
families(any iterable of family names).is_empty/ totals then reflect only the kept families.
- summary()#
Return a one-line difference summary.
- invert()#
The reverse diff (
source_b->source_a): a pure swap, sodiff(b, a) == diff(a, b).invert().
- to_dict()#
Return a JSON-compatible representation of the case difference.
- to_json(indent=2)#
Return the case difference as JSON.
- query(sql)#
Query diff entries with read-only SQL.
- Parameters:
sql -- One SQLite
SELECTorWITHstatement.- Returns:
Query rows as dictionaries. Use
schema()to list columns.
Examples
>>> d.query("SELECT family, count(*) FROM entries GROUP BY family") >>> d.query("SELECT key_str, before, after FROM entries " ... "WHERE family='branches' AND field='rate1'")
- schema()#
Return query table names and their columns.
- classmethod from_dict(doc)#
Rebuild a
CaseDifffrom theto_dict()wire form.This inverse lets a stored or transmitted diff be applied. Pure regrouping: the flat
entrieslist folds back into the nested added/removed/changed maps, and an array key becomes a tuple (a spec string key stays a string). No value coercion occurs. The JSON-shaped values match the JSON-shaped snapshotapply_diff()compares against and assigns through pydantic, soapply_diff(a, CaseDiff.from_dict( diff_cases(a, b).to_dict()))re-keys identically tob.
- to_markdown(*, limit=20)#
Return the case difference as Markdown.
- apply_diff(case, diff, *, on_conflict='raise', allow_skew=False, identity_changes=None)#
Apply
diffto a copy ofcaseand return the patched case.The input remains unchanged through copy-on-write edits. Changed and removed entries verify prior values, and added entries verify absence.
on_conflictcan raise, skip, or force these base-state mismatches. Current record classes normalize older patches. Unknown newer fields raiseSchemaSkewErrorbefore application unlessallow_skew=Truerecords and skips them. Schema skew is independent of base-state conflict handling. If supplied, identity_changes receives applied renames and removals after the full patch succeeds.
- class DiffConflictError#
apply_difffound the base case does not match the diff's recordedbeforestate (a drifted base). Raised unlesson_conflictrelaxes it.
- class SchemaSkewError#
Report fields that the installed gpf schema does not recognize.
A different gpf version can create these fields. Use
allow_skew=Trueto omit them and record a finding on the returned case.
- sol_to_keyed_dict(sol)#
Convert a solved operating point to keyed, readable values.
- Parameters:
sol -- Solved case to project.
- Returns:
A mapping with
bus,gen, andbranchfamilies. Each family maps stable equipment identities to solved fields. Bus angles use degrees. Power values use MW and Mvar. Equipment identities match those used bydiff_cases.
- diff_solutions(sol_a, sol_b, source_a='A', source_b='B', *, tol=1e-06)#
Compare bus voltages, generation, and branch flows in two solutions.
- Parameters:
sol_a -- Source solution.
sol_b -- Target solution.
source_a -- Display name for the source solution.
source_b -- Display name for the target solution.
tol -- Relative tolerance used to ignore numerical solve noise.
- Returns:
The changed operating-point values.
- merge_cases(base, *overlays, on_conflict='error')#
Merge related cases into a new case without changing the inputs.
Records are keyed by natural identity across every source, family by family plus the
"case"header pseudo-family (sbase/rev/basfrq/titles/...). header fields follow the same rule as device fields: any disagreement is a conflict). A key in exactly one source is carried through; a key in several sources with identical values merges silently; differing values are a conflict, resolved byon_conflict:"error": collect every conflict, then raiseMergeConflictError."overlay_wins": the later source wins. Overlays apply in argument order, so the last overlay naming a key wins."base_wins": the earlier source wins. Base wins over any overlay, and an earlier overlay over a later one for keys the base lacks.
All sources must use the same bus numbers and equipment keys.
- Parameters:
base -- Initial case and first source in conflict precedence.
overlays -- Additional cases in precedence order.
on_conflict -- Use
"error","overlay_wins", or"base_wins".
- Returns:
The merged case and a merge report.
- Raises:
MergeConflictError -- If conflicts exist and
on_conflictis"error".
- class MergeReport(sources, added, conflicts, warnings=<factory>)#
Summarize merged sources, added records, warnings, and conflicts.
- summary()#
Return a one-line merge summary.
- to_dict()#
Return a JSON-compatible merge report.
- class MergeConflictError(conflicts)#
Report all same-key records that have conflicting values during a merge.
- impact(before, after, *, solve=True, band=None, rating_set=1, top=10, provenance=None, before_label='before', after_label='after', backend=None)#
Measure the network and operating-point effects of case changes.
- Parameters:
before -- Case before the change.
after -- Case after the change.
solve -- Solve both cases and compare operating points.
band -- Global voltage band as
(low_pu, high_pu).Noneuses each bus limit.rating_set -- Branch rating column from 1 through 12.
top -- Maximum number of entries in each ranked list.
provenance -- Ledger operation labels that describe the change.
before_label -- Display name for the first case.
after_label -- Display name for the second case.
backend -- Backend name or
Nonefor automatic selection.
- Returns:
A structured impact report. If either solve fails to converge, the voltage and thermal sections are
None.
- class ImpactReport(before_label, after_label, solved, converged, rating_set, band, topology, dispatch, voltage, thermal, health, provenance=None, notes=<factory>, sources=<factory>)#
Structured delta between two solved operating points. Sections keyed off a failed or skipped solve are
Noneand named innotes; the record-derived sections (topology, load delta, islands) are always present.- to_dict()#
Return a JSON-compatible impact report.
- to_json(indent=2)#
Return the impact report as JSON.
- headline()#
The single most important grounded fact, one sentence's worth.