Skip to content

mambo_power.io.psse_raw

PSS/E RAW v33 importer. See File formats for the record map, derived ids, conversions, report codes and limitations.

mambo_power.io.psse_raw

PSS/E RAW version 33 importer (wave M8, W4).

A record parser for the v33 layout only (REV must be 33). It reads the case identification (SBASE), bus, load, fixed shunt, generator, non-transformer branch, two-winding transformer and zone sections and ignores every other record — area records (only the bus AREA labels survive, as Bus.area), three-winding transformers, switched shunts, owners, DC lines, FACTS, ... — with one report entry per ignored record. Fields are comma-separated; single-quoted strings may contain commas and slashes; / outside quotes starts a comment; blank lines are skipped; each section ends with a line whose first field is 0; Q (or the end of the text) after the zone section ends the file. Field order and units follow grg-pssedata's struct.py and the conversions follow MATPOWER's psse_convert.m / psse_convert_xfmr.m (both BSD-3; record/m8-research.md §3).

Ids: bus-<I>; load-<I>-<ID>, shunt-<I>-<ID>, gen-<I>-<ID> (ID stripped); branches and transformers branch-<I>-<J>-<CKT>; folded shunts shunt-branch-<I>-<J>-<CKT>-i / -j and shunt-xfmr-<I>-<J>-<CKT>. Every transformer record yields a Branch with kind="transformer" (set from the record type, not inferred from the tap); branch records yield kind="line".

Conversions (MATPOWER's rules):

  • load P = PL + IP·VM + YP·VM² (same for Q) at the bus's VM when any of IP IQ YP YQ is non-zero — reported RAW_LOAD_ZIP_FOLDED;
  • branch end shunts GI BI / GJ BJ (pu on SBASE) become Shunt entries — reported RAW_BRANCH_END_SHUNT_FOLDED;
  • transformer impedance per CZ: 1 = pu on SBASE as is; 2 = pu on SBASE1-2 and NOMV1 (0 = the from bus's base kV), scaled by (NOMV1/BASKV_I)² · SBASE/SBASE1-2; 3 = load loss in W and |Z| pu on the winding base, R = R/(1e6·SBASE1-2), X = sqrt(|Z|² − R²), then scaled as for 2;
  • tap per CW: tap = t1/t2 with t = WINDV (1, pu of bus base), WINDV/BASKV (2, kV) or WINDV·NOMV/BASKV (3, pu of nominal); shift = ANG1; rating = RATA1; b = 0;
  • magnetising admittance per CM becomes a shunt at the from bus: 1 = MAG1 + j·MAG2 pu on SBASE; 2 = MAG1 no-load loss in W and MAG2 exciting current pu on the winding base, G = MAG1/(1e6·SBASE1-2), B = −sqrt(MAG2² − G²), both scaled to the system base — reported RAW_XFMR_MAGNETISING_FOLDED.

RAW carries no economic data at all (no cost section exists in the format), so every generator imports with cost=None and the report says so once (RAW_NO_COSTS; spec A3). BASKV <= 0 is repaired to 1.0 (BASE_KV_REPLACED) and islands are switched off before validation (ISLAND_DEACTIVATED), exactly as mambo_power.io.matpower does. Defects in the file raise RawImportError; defects in the network are left to Network validation.

CODES module-attribute

CODES: tuple[str, ...] = (
    "BASE_KV_REPLACED",
    "ISLAND_DEACTIVATED",
    "RAW_NO_COSTS",
    "RAW_LOAD_ZIP_FOLDED",
    "RAW_BRANCH_END_SHUNT_FOLDED",
    "RAW_XFMR_MAGNETISING_FOLDED",
    "RAW_THREE_WINDING_IGNORED",
    "RAW_SWITCHED_SHUNT_IGNORED",
    "RAW_SECTION_IGNORED",
)

Every report code this importer can emit (its documented limitations).

RawImportCode module-attribute

RawImportCode = Literal[
    "BAD_HEADER",
    "UNSUPPORTED_VERSION",
    "BAD_NUMBER",
    "BAD_RECORD",
    "UNTERMINATED_SECTION",
    "UNKNOWN_BUS",
]

The closed set of importer error codes.

DEFAULT_BASE_KV module-attribute

DEFAULT_BASE_KV = 1.0

Substituted for BASKV <= 0 (the io.matpower convention); each substitution is warned.

ImportReport dataclass

ImportReport(
    warnings: list[ConversionIssue] = list(),
    errors: list[ConversionIssue] = list(),
)

Bases: _Report

Every repair an importer performed, in the order it happened (empty = lossless).

RawImportError

RawImportError(
    code: RawImportCode,
    message: str,
    line: int | None = None,
)

Bases: Exception

A defect in the RAW file; code is stable, line is 1-based when known.

Source code in src/mambo_power/io/psse_raw.py
def __init__(self, code: RawImportCode, message: str, line: int | None = None) -> None:
    self.code = code
    self.line = line
    super().__init__(message)

load

load(source: str | PathLike[str]) -> Network

Parse the RAW v33 file at source; the report is discarded.

Source code in src/mambo_power/io/psse_raw.py
def load(source: str | PathLike[str]) -> Network:
    """Parse the RAW v33 file at ``source``; the report is discarded."""
    return load_with_report(source)[0]

loads

loads(text: str) -> Network

Parse RAW v33 text; the report is discarded.

Source code in src/mambo_power/io/psse_raw.py
def loads(text: str) -> Network:
    """Parse RAW v33 text; the report is discarded."""
    return loads_with_report(text)[0]

load_with_report

load_with_report(
    source: str | PathLike[str],
) -> tuple[Network, ImportReport]

Parse the file at source and return (network, report).

Source code in src/mambo_power/io/psse_raw.py
def load_with_report(source: str | PathLike[str]) -> tuple[Network, ImportReport]:
    """Parse the file at ``source`` and return ``(network, report)``."""
    text = Path(source).read_text(encoding="utf-8-sig", errors="replace")
    return loads_with_report(text)

loads_with_report

loads_with_report(
    text: str,
) -> tuple[Network, ImportReport]

Parse RAW v33 text and return (network, report); see the module docstring.

Source code in src/mambo_power/io/psse_raw.py
def loads_with_report(text: str) -> tuple[Network, ImportReport]:
    """Parse RAW v33 text and return ``(network, report)``; see the module docstring."""
    case = _scan(text.lstrip(chr(0xFEFF)))
    net, warnings = _build(case)
    return net, ImportReport(warnings=warnings)