Skip to content

Lines.R1()/X1()/C1() silently return stale defaults for matrix-defined lines #137

Description

@Houmgaor

Summary

Lines.R1(), Lines.X1(), and Lines.C1() (and the equivalent LineCodes.* properties) are symmetric-component fields. They only reflect reality when a line/LineCode was defined via r1=/x1=/c1=. Once a line/LineCode is switched to a matrix definition (rmatrix=/xmatrix=/cmatrix=), those fields are never cleared or recomputed -- they silently hold whatever they were constructed with (R1 := 0.0580, X1 := 0.1206, per TLineObj/TLineCodeObj construction in the original Pascal source), and the direct numeric getters return that stale value with no indication anything is wrong.

This is distinct from #36 (which is about a scaling inconsistency between the RMatrix/XMatrix getter and setter) -- this is about R1/X1/C1 becoming meaningless, not mis-scaled, once matrix mode is active.

Reproduction

New Circuit.test basekv=0.4 pu=1.0 phases=3
New LineCode.lc1 nphases=3 baseFreq=50 units=km
~ rmatrix=[0.868 | 0.1 0.868 | 0.1 0.1 0.868]
~ xmatrix=[0.077 | 0.01 0.077 | 0.01 0.01 0.077]
New Line.l1 bus1=a.1.2.3 bus2=b.1.2.3 phases=3 linecode=lc1 length=1 units=km
import opendssdirect as dss
dss.Command("...redirect the above...")
dss.Lines.Name("l1")
dss.Lines.R1(), dss.Lines.X1()
# -> (0.058, 0.1206) -- the hard-coded construction default, not 0.868/0.077 -- or
# anything derivable from the declared matrix.

Confirmed via the Pascal source that the text-based property interface handles this correctly -- querying the R1 property by name returns '----' once SymComponentsModel is False (see LineCode.pas: If SymComponentsModel Then Result := Format(...) else Result := '----'). The direct numeric getter used by the C-API/OpenDSSDirect.py doesn't perform the same check, so there is no way to tell, from the numeric API alone, that the returned value is meaningless.

Impact

Any matrix-defined line, any conductor count -- not neutral- or phase-count-specific. We hit this while validating a pandapower OpenDSS importer against a real utility network (an explicit-neutral 4-conductor European LineCode looked like a Kron-reduction issue at first; a plain 3-conductor matrix LineCode with no neutral at all reproduced the identical stale value), which is what led us to check the Pascal source. Any tool that reads Lines.R1()/X1()/C1() directly (rather than going through the text/property-name interface, or manually deriving from RMatrix()/XMatrix()/CMatrix()) on a matrix-defined line will silently get wrong data with no error, warning, or way to detect it via the numeric API.

Suggested fix

Given #36 was closed as not-planned (presumably to avoid changing numeric behavior that might already be relied upon / for EPRI-COM-compatibility reasons), I'd guess changing what R1()/X1()/C1() themselves return is a similarly hard sell. Two lower-risk options that don't touch existing behavior:

  1. Document it on the Lines.R1/X1/C1 (and LineCode.R1/X1/C1) properties: "meaningless once the line/LineCode has been defined via a matrix; check SymComponentsModel" (or equivalent) -- currently there's no hint of this anywhere a numeric-API user would see it.
  2. Expose SymComponentsModel as a new read-only boolean getter (e.g. Lines.SymComponentsModel() / LineCodes.SymComponentsModel()). Purely additive, no behavior change, and it would let API consumers detect the unsafe case themselves and fall back to RMatrix()/XMatrix()/CMatrix().

Happy to help test either, or just to have this documented if that's the preferred resolution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions