Skip to content

06 — Create a TN-Model

For an entire LV distribution-grid section — substation, KVS, many houses with their own foundation electrodes, PEN backbone — hand-rolling the world quickly becomes unwieldy. groundfield ships two factories:

Factory Use when
:class:TnNetworkGenerator Stochastic TN reference worlds, parameter sweeps, Monte Carlo
:class:OrtsnetzLayout A single deterministic network composed piece by piece from a real map

This example uses :class:TnNetworkGenerator for a synthetic parameter-sweep-friendly network. See the OSM-pipeline example for the :class:OrtsnetzLayout workflow on a real OSM extract.

Synthetic TN-Ortsnetz with stochastic axes

import groundfield as gf

cfg = gf.TnNetworkConfig(
    soil=gf.TwoLayerSoilSpec(rho_1=120.0, rho_2=30.0, h_1=3.0),
    building_counts={
        "residential": 30,
        "small_industry": gf.Discrete(values=[0, 1, 2], weights=[0.6, 0.3, 0.1]),
    },
    source_magnitude_A=1.0,
)
gen = gf.TnNetworkGenerator()
world = gen.build(cfg, rng=gf.np.random.default_rng(seed=42))

engine = gf.create_engine(
    backend="image",                       # auto-dispatch to image_2layer
    segment_length=0.5, frequencies=[50.0],
)
result = engine.solve(world)
print("substation cluster Z =",
      result.cluster_impedance("trafo_ring_0")[0])

A few things happen behind the scenes:

  • The substation grounding (ring + 4 driven rods) is built at the origin.
  • Buildings are placed on a Manhattan grid centred on the substation, with the configured count per type. Each building gets the per-type :class:GroundingSystemSpec (default residential = 1.0 m × 1.0 m foundation electrode).
  • Cable cabinets (KVS) are placed in a row along the substation axis at the configured quota.
  • The PEN backbone fans out from the substation to every KVS and from each KVS to its closest buildings.
  • A 1 A current source is attached to the substation cluster.

Picking the PEN backbone topology

TnNetworkConfig.pen_topology now also accepts the new :class:RadialTrunkTopology:

cfg = gf.TnNetworkConfig(
    soil=gf.TwoLayerSoilSpec(rho_1=120.0, rho_2=30.0, h_1=3.0),
    building_counts={"residential": 30},
    pen_topology=gf.RadialTrunkTopology(
        n_feeders=4,                 # north / east / south / west
        slots_per_substation=8,      # houses directly at the trafo
        slots_per_kvs=8,             # houses per inserted KVS
        kvs_spacing_m=60.0,
        max_feeder_length_m=400.0,
    ),
)
world = gen.build(cfg)

The substation now feeds four radial LV cables. Once a cable's slots_per_substation budget is exhausted, a new KVS is inserted along the cable axis. Buildings beyond max_feeder_length_m are dropped with a UserWarning.

Stochastic axes and reproducibility

Every numeric field accepts either a constant or a :class:Distribution:

Distribution Typical use
Constant(v) Placeholder
Uniform(low, high) Soil resistivities, geometry tolerances
Normal(...) Engineering tolerances
Discrete(values, weights=...) Categorical counts (n_efh in {5, 10, 30, 80, 200})

For bit-exact reproducibility, pass an np.random.default_rng(seed=...) to gen.build(cfg, rng=...). gen.sample_world(rng=...) returns both the world and the resolved config so the realisation can be persisted as JSON alongside the simulation output.

Where to go next