formats: carry the HVDC and setpoint fields the readers already read - #322
Draft
samtalki wants to merge 3 commits into
Draft
formats: carry the HVDC and setpoint fields the readers already read#322samtalki wants to merge 3 commits into
samtalki wants to merge 3 commits into
Conversation
Contributor
Conversion MatrixLegendCells show
Transmission7 cases.
Distribution7 cases.
Full warning details: download |
samtalki
marked this pull request as draft
August 15, 2026 15:37
samtalki
force-pushed
the
claude/pr-conversion-matrix-improve-crn6i0
branch
2 times, most recently
from
August 15, 2026 15:55
b3eeafb to
18564a8
Compare
Four writers dropped, or warned about, data the matching reader was already prepared to take back. Each gap showed up in the conversion matrix as a warning that named a loss the format did not actually have to take. - PSLF. A generator voltage setpoint is EPC's `reg_kv`, in kV, so a bus stating no nominal kV lost it. The bus `vsched` column is the scheduled magnitude in per unit and needs no base, so the setpoint rides there for those buses and the reader prefers it over the solved voltage. Where the bus does state a base kV, `reg_kv` still carries it per generator and `vsched` stays the bus voltage: routing a setpoint through `vg * base_kv` and back is not exact in binary, and a re-serialize would differ in the last digit. - egret. The reader read `dc_branch` and the writer emitted none, so every conversion into egret dropped its dclines. The writer now states the same power, voltage, and loss fields the reader takes; only a dcline cost curve, which egret has no slot for, is warned. - Surge. The reader reads a converter terminal's AC voltage setpoint, reactive limits, and loss model, and the writer stated none of them: the sending end's terminal voltage came back as 1.0 and the loss model as zero, silently. The writer now states all three. `pt` is derived from the setpoint and the loss model rather than negated, which is the sign every other reader here stores, and the writer reports a line whose received power the loss model cannot reproduce. The reader's blanket "converter detail mapped best effort" warning becomes a count of the links that state detail differing from the neutral converter, the shape the load/branch/generator warnings beside it already had. - PowerModels. The dcline warning named no loss: every `Hvdc` field has a slot, including the aggregate bounds on `mp_pmin`/`mp_pmax` and the cost curve, and reads back exactly. Dropped. Together: 21 green conversion matrix cells to 27, and 727 warnings to 689. The `egret JSON` and `Surge JSON` source rows pay part of it back — dclines that reach the next hop now report what each target does with them, where before those rows had none to carry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NoWFTq3ofuu1SZ7aWUiVGf
…ment Follow-ups from a review of the stack. - `synthesize_rate_a` read only the two voltage ceilings, but the phasor difference is convex in the terminal voltages, so its largest value over the band box is at a corner — and below roughly 10° that corner is one terminal high and the other low. On r=0, x=0.01, a ±2° window and a 0.9/1.1 band it returned 4.2 pu against 22.3 pu attainable, and `synthesize_unrated_limits` handed that to the OPF as a limit. It now takes both bands and maxes over the four corners. - The series admittance formed `r² + x²` directly, which overflows past an impedance magnitude of about 1e154 whose admittance is perfectly representable. The quotient then read as an exact zero and the branch left the DC network silently, while `build_ybus` errored on the same one. `MIN_DIVISIBLE_MAGNITUDE` documents that the bound is on the magnitude and never on the square; the computation now holds to that, in one place both the DC conventions and the guarded entry point use. Bit-identical below the overflow, so no case moves. - A `.dss` `Clear` resets the findings along with the objects, so a case that spent the include budget and then cleared lost the refusal. The counters live on the executor and kept refusing, so the reader returned a truncated network with an empty `warnings`, nothing for `powerio package` to lift, and exit 0. The refusal is restated. - The published package schema did not require `powerio_version`: schemars reads the `serde` default as optional and `schemars(required)` does not override it. A producer that validated against the `$id` and omitted it passed there and was refused by `from_json`. - `Error::Multiconductor` flattened to `Parse`, so a missing `.dss` reached through a package raised a parse error where the direct path raised `FileNotFoundError` with `filename` set. Both paths now agree. - `set_operating_points_json` reported the caller's JSON through the blanket `From`, which names every failure a serialization step: the message blamed our own writer for the caller's document. Same fix the stack already made at the two powerio-pkg sites. - `parse_convention` lost `"pure"`, the third 0.8 spelling, so that caller got the generic unknown-value error instead of the migration message warning that `series` is a different formula. - LODF, iterative path: a bridge redistributes nothing, so its column is zero and the conjugate-gradient solve behind it went unused. On a radial feeder that was every solve. - The bundle doc still promised `p_shift` is zero without `Matpower`, named a manifest `schema_version` this stack deleted, and called `ReactanceOnly` deprecated where the code and `matrices.md` say it stays; the geo doc still showed the sidecar's retired `version` key. A point sidecar states no polylines, so `powerio geo` reported every branch as unplaced on a run that placed everything it could. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NoWFTq3ofuu1SZ7aWUiVGf
Cleanup pass over the two commits below. The `.dss` include-budget fix was patched at the wrong depth. `Clear` wiped `warnings` and `diagnostics` along with the circuit, and the answer was to have the budget re-check whether its own finding survived and restate it. That covered one of the two `Error` codes: an include refused for escaping the case directory has no surviving counter to restate it from, so it was lost outright. `Clear` resets the circuit, not the record of how the script was read — the record now rides through it, which covers both codes and drops the re-check. The re-check also scanned `diagnostics` on every refused include, so a case that emitted many findings before spending the budget turned the refusal path quadratic, in the one place built to bound hostile input. The MATPOWER dcline loss model was written out three times: as an expression in the pandapower reader (with the hub's formula in a comment beside it), as `pf * efficiency` in the PyPSA reader, and as a new helper in the Surge one. `Pf`, `Pt`, `loss0` and `loss1` are one relation on a hub type, so it lives on `Hvdc` now, with the "does this line satisfy its own loss model" test a writer needs beside it. Also: the LODF bridge skip reshaped a loop that has a dense twin, so it no longer read like it — restored, and it now skips the m-entry scan as well as the solve; the Surge converter-detail warning hand-rolled the count-by-predicate helper the three warnings above it use, and its field test re-implemented `num_not_default` in a form that missed string-encoded numbers; the PSLF writer kept a second set to answer a question its map already knew, and only reported a dropped setpoint where one was really dropped; `read_generator` collapsed a nested chain and two warnings differing by three words into one; the schema generator cloned every property name to satisfy the borrow checker; the package field doc, which schemars copies into the published schema, sent an external validator author to a path in this repo; `dc_branch` was the one element map egret inserted conditionally; and the law of cosines was transcribed twice in tests beside the implementation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NoWFTq3ofuu1SZ7aWUiVGf
samtalki
force-pushed
the
claude/pr-conversion-matrix-improve-crn6i0
branch
from
August 15, 2026 15:57
18564a8 to
479354a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Top of the v0.9.0 stack, on top of #323.
Four writers dropped, or warned about, data the matching reader was already prepared to take back. Each gap showed up in the conversion matrix as a warning naming a loss the format did not have to take. Green cells go from 21 to 27; total warnings from 727 to 689.
reg_kv, in kV, so a bus stating no nominal kV lost it. The busvschedcolumn is the scheduled magnitude in per unit and needs no base, so the setpoint rides there for those buses. Where the bus does state a base kV,reg_kvstill carries it andvschedstays the bus voltage: routing a setpoint throughvg * base_kvand back is not exact in binary, and a re-serialize would differ in the last digit.dc_branchand the writer emitted none, so every conversion into egret dropped its dclines. The writer now states the same power, voltage, and loss fields the reader takes; only a dcline cost curve, which egret has no slot for, is warned.ptis now derived from the setpoint and the loss model rather than negated, which is the sign every other reader here stores. The reader's blanket "converter detail mapped best effort" warning becomes a count of the links that state detail differing from the neutral converter.Hvdcfield has a slot, including the aggregate bounds onmp_pmin/mp_pmaxand the cost curve, and reads back exactly. Dropped.The
egret JSONandSurge JSONsource rows pay part of it back — dclines that reach the next hop now report what each target does with them, where before those rows had none to carry.Then a review pass over the stack, and the fixes it produced
synthesize_rate_aread only the two voltage ceilings, but the phasor difference is convex in the terminal voltages, so its largest value over the band box is at a corner — below roughly 10° the mixed one. Onr=0, x=0.01, a ±2° window and a 0.9/1.1 band it returned 4.2 pu against 22.3 pu attainable, andsynthesize_unrated_limitshanded that to the OPF as a limit. It now takes both bands and maxes over the four corners.r² + x²directly, which overflows past an impedance magnitude of about 1e154 whose admittance is representable. The quotient then read as an exact zero and the branch left the DC network silently, whilebuild_ybuserrored on the same one.MIN_DIVISIBLE_MAGNITUDEdocuments that the bound is on the magnitude and never on the square; the computation now holds to that, in one place both the DC conventions and the guarded entry point use. Bit-identical below the overflow, so no case moves..dssClearreset the parse record along with the circuit, so a case that spent the include budget, or refused an include for escaping the case directory, and then cleared returned a truncated network with an emptywarnings, nothing forpowerio packageto lift, and exit 0.Clearresets the circuit only.powerio_version: schemars reads theserdedefault as optional andschemars(required)does not override it. A producer that validated against the$idand omitted it passed there and was refused byfrom_json.Error::Multiconductorflattened toParse, so a missing.dssreached through a package raised a parse error where the direct path raisedFileNotFoundErrorwithfilenameset. Both paths now agree.set_operating_points_jsonreported the caller's JSON through the blanketFrom, which names every failure a serialization step — the same defect v0.9.0: the fixes the review of the stack below produced #316 fixed at the twopowerio-pkgsites, missed at the pyo3 boundary.parse_conventionalso lost"pure", the third 0.8 spelling.p_shiftis not zero under the new default; the bundle manifestschema_versionthis stack deleted; the geo sidecar's retiredversionkey. A point sidecar states no polylines, sopowerio georeported every branch as unplaced on a run that placed everything it could.Verified
cargo fmt --all --check,cargo clippy --workspace --all-targetsat zero warnings,cargo test --workspaceat 52 binaries with zero failures, andruff checkover the Python layer. The conversion matrix baseline inpowerio-cli/tests/conversion_matrix_report.rsis updated in the same commit as the fidelity changes, with the reasoning for each moved cell.No API, ABI, or schema version change, so PowerIO.jl needs nothing.