ADR-0008: groundinsight bridge — BusType export from a rho-f fit¶
| Status | Accepted |
| Date | 2026-05-08 |
| Deciders | Project maintainers |
| Scope | groundfield.io.groundinsight; bridge to the sister project groundinsight |
Context¶
groundfield is the field-grade reference. groundinsight is the
reduced equivalent network model that runs the actual planning and
fault-current studies. The reduction pipeline
requires a precise, regression-tested handover between
groundfield and groundinsight. The rho-f fit is now in place
in two flavours:
groundfield.postprocess.vector_fitting— a Gustavsen/Semlyen rational fit \(Z(s)\) in the Laplace variable \(s = j\,2\pi f\) at fixed soil (output of one parametric run).groundfield.postprocess.rho_f_standard— the physically-motivated 5-coefficient form \(Z(\rho, f) = k_1\rho + (k_2 + j k_3)f + (k_4 + j k_5)f\rho\) fitted across a soil-resistivity sweep.
Both produce a SymPy expression. groundinsight.BusType consumes
exactly such an expression as its impedance_formula. What is
missing is the actual transport: a documented file format, a
Python helper that builds a BusType and (optionally) writes it
to the groundinsight SQLite store, and a regression test that
proves the formula round-trips through groundinsight's own
parser and produces the same numbers.
Decision¶
Symbol convention¶
groundinsight.BusType.impedance_formula is parsed with two free
symbols that the compute_impedance evaluator binds at run time:
f— frequency in Hzrho—Bus.specific_earth_resistance, in \(\Omega\,\mathrm{m}\)
and the imaginary unit j (mapped to sympy.I by the validator).
Therefore:
- A
RhoFStandardFitexports natively: its expression is already in(rho, f). - A
VectorFitResultexports via the substitution \(s \to j\,2\pi f\) insidefit_to_sympy(...). The exported formula then depends onfonly and is independent ofrho. This is correct: a vector fit is bound to one specific soil configuration, and itsBusTypeis meant to be paired with aBuswhosespecific_earth_resistancematches that soil. Discrepancies are flagged at export time but not enforced.
Transport: JSON + Python API, both first-class¶
The user has two equally supported paths:
-
to_bustype_dict(fit, ...)returns a JSON-ready Pythondict;save_bustype_json(fit, path, ...)writes the neutral schema below to disk. This is the canonical, persistent exchange. The schema is versioned (schema_version), andgroundfieldwill honour older versions through dedicated loaders. The JSON file is independent of thegroundinsightPython package — anyone can produce or consume it. -
to_bustype(fit, ...)returns a livegroundinsight.BusTypePydantic instance via a lazy import (no top-level dependency ongroundinsight). For users running in a notebook with both packages installed this is the one-liner that closes the family pipeline. Ifgroundinsightis not installed the function raises a clearImportErrorpointing at the JSON path or at the optional installpip install groundfield[groundinsight].
JSON schema (v1)¶
Single document, parseable in seconds, no MIME-type tricks. Layout
is intentionally close to the groundinsight.BusType Pydantic
schema so a programme that only knows the groundinsight shape
can still read the file by ignoring the metadata block.
{
"schema": "groundfield.bustype",
"schema_version": 1,
"name": "TN_house_connection_5EFH",
"description": "...",
"system_type": "LV",
"voltage_level": 0.4,
"impedance_formula": "0.123*rho + 0.000456*f + 0.0*j*f + 1.2e-7*f*rho + 3.4e-8*j*f*rho",
"samples": {
"frequency_Hz": [0.1, 1.0, 10.0, 50.0, 100.0, 1000.0],
"rho_Ohm_m": [100.0, 100.0, 100.0, 100.0, 100.0, 100.0],
"Z_real_Ohm": [...],
"Z_imag_Ohm": [...]
},
"metadata": {
"fit_method": "rho_f_standard",
"fit_quality": {"rms_error_Ohm": 0.012, "rms_relative": 0.004},
"coefficients": {"k1": 0.123, "k2": 4.56e-4, "k3": 0.0,
"k4": 1.2e-7, "k5": 3.4e-8},
"source": "groundfield 0.1.0",
"created_at_utc": "2026-05-08T14:32:11Z",
"electrode_name": "trafo_ring",
"soil_summary": "TwoLayerSoil(rho_1 sweep [50, 100, 300, 1000], rho_2=20, h_1=2.0)"
}
}
For vector_fit the metadata block carries n_poles, the pole
list and the residue list; coefficients is replaced by
{"R_inf": ..., "L_inf": ...}. For rho_f_standard the
samples.rho_Ohm_m array spans all sampled rhos; for
vector_fit it is constant at the soil under which the fit was
done.
Coupling¶
groundinsight becomes an optional dependency declared as the
extras group [groundinsight] in pyproject.toml. The library
imports groundinsight lazily inside the few functions that
return BusType instances or talk to the database, so
pip install groundfieldworks as before;pip install groundfield[groundinsight]enables the Python-API path;- the JSON path needs neither extra.
Validation programme¶
- Symbol round-trip — every formula produced by
to_bustype_*is fed back throughgroundinsight.utils.validations.validate_impedance_formula_valueand throughgroundinsight.utils.impedance_calculator.compute_impedance, and the resulting per-frequency complex values must matchfit.evaluate(...)to \(10^{-9}\) relative. - JSON round-trip —
save_bustype_jsonfollowed byload_bustype_jsonreproduces every numerical field bit-exact and the formula string verbatim. - End-to-end — a transformer-station notebook
(the internal groundinsight-export harness) sweeps
\(\rho_1 \in \{50, 100, 300, 1000\}\,\Omega\,\mathrm{m}\) on a
2-layer soil, fits the standard form, exports a
BusType, loads it back into agroundinsight.Network, and reproduces the per-frequency \(|Z|\) and \(\arg Z\) within the fit RMS. - Optional-dependency hygiene — a test that monkey-patches
groundinsightto be unimportable and verifies theto_bustype/save_bustype_to_dbfunctions raise a clearImportError, whileto_bustype_dict/save_bustype_jsonkeep working.
Consequences¶
- The
rho-ffamily is now closed-loop:groundfieldproduces a fit, exports it, andgroundinsightconsumes it without any manual stringification. - The neutral JSON makes both packages forward-compatible: tabular
ingestion on the
groundinsightside will read thesamplesblock; the formula stays the canonical artifact in v1. BranchTypeis out of scope for this ADR. The mutual coupling between two grounding clusters is not yet arho-fproduct ofgroundfield; it is a follow-up oncecompute_mutual_impedanceproduces a calibrated formula in the same(f, rho, l)symbol set thatBranchTypeexpects.
References¶
- ADR-0001, ADR-0007 — engine family and cross-layer support that produced the underlying physics.
- Vector fitting: Gustavsen & Semlyen, IEEE T-PWRD 14(3), 1052–1061 (1999).
- Standard
rho-fform: defined in :mod:groundfield.postprocess.rho_f_standard. groundinsight.models.core_models.BusType— consumer of the exported formula.