Reference

The energydatamodel package exposes a single Element root with three sibling subtrees β€” Node, Edge, and Collection β€” plus an Asset mixin and a small set of value types and helpers. System-structural classes live flat at edm.X; technology-specific equipment lives under sub-namespaces (edm.solar, edm.wind, edm.grid, …).

Core hierarchy

Element

Element β€” the root of the EDM type hierarchy.

Element is the shared base for everything in the model. It carries the fields that any persistable, named, geometry-bearing object needs:

  • id β€” a stable UUID7, generated at construction

  • name β€” human label (display / CLI navigation)

  • timeseries β€” metadata-only TimeSeries declarations attached to this element (df=None; the actual data is written via the energydb data-write path, not carried inline on the EDM tree)

  • geometry β€” optional shapely geometry (Point, Polygon, LineString, …)

  • extra β€” open dict of JSON-native scalars

Sibling subtrees specialize Element:

  • Node (in energydatamodel.node) β€” anything that exists as a β€œthing”: graph vertices, Areas, plus container markers. Adds members and tz.

  • Edge (in energydatamodel.edge) β€” edges between two Nodes. Adds from_element, to_element, directed.

  • Asset (in energydatamodel.asset) β€” mixin marking physical energy equipment. Mixed with Node or Edge via NodeAsset / EdgeAsset.

  • Collection (in energydatamodel.containers) β€” groupings that aren’t graph vertices (Portfolio, Site, Region, …).

Identity is a UUID7 assigned at construction. The same Element instance keeps its id across renames and across JSON round-trips.

energydatamodel.element.infra(*, default=None, default_factory=None, children=False)[source]
Overloads:
  • default (T), children (bool) β†’ T

  • default_factory (Callable[[], T]), children (bool) β†’ T

  • children (bool) β†’ Any

Build a dataclass field marked as framework infrastructure.

Use in place of dataclasses.field for any non-domain attribute declared on an Element subclass:

my_field: T = infra(default=None)
members: list[Element] = infra(default_factory=list, children=True)
Parameters:
energydatamodel.element.is_infra_field(f)[source]

True if a dataclass field is framework infrastructure (excluded from Element.to_properties()).

Return type:

bool

energydatamodel.element.is_children_field(f)[source]

True if a dataclass field holds child Elements (excluded from flat storage rows).

Return type:

bool

class energydatamodel.element.Element(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None)[source]

Bases: object

Common base for every persistable object in EDM.

Identity is a UUID7 generated at construction. name is a mutable human label; renames don’t change the id.

Subclasses are auto-registered for JSON dispatch via __init_subclass__ β€” defining class Foo(NodeAsset): ... is enough for round-trip serialization, no decorator required.

Parameters:
id: UUID
name: str | None = None
timeseries: list[TimeSeries]
geometry: BaseGeometry | None = None
extra: dict
lat: dataclasses.InitVar[float | None] = None
lon: dataclasses.InitVar[float | None] = None
property latitude: float | None

Latitude, if geometry is a shapely Point; else None.

property longitude: float | None

Longitude, if geometry is a shapely Point; else None.

property centroid: Point | None

Centroid of geometry, or None if no geometry.

children()[source]

Child elements for tree walking. Override in subclasses with children.

Return type:

list

add_child(obj)[source]

Attach a child. Override in subclasses that support children.

Return type:

None

to_tree()[source]

Return the hierarchy rendered as an indented tree string.

Use print(element.to_tree()) to display it. In a notebook, printing the element directly (element) also renders the tree via __repr__.

Return type:

str

index()[source]

Build a dict[UUID, Element] index of the subtree rooted at self.

Use to resolve Reference objects against this tree.

to_properties()[source]

Domain-specific fields as a dict (excludes infra + children fields).

Return type:

dict

to_json(*, exclude_fields=None)[source]

Serialize to a JSON-compatible dict.

Parameters:

exclude_fields (set | None)

Return type:

dict

classmethod from_json(data)[source]

Deserialize from a JSON-compatible dict.

Parameters:

data (dict)

Return type:

Element

geometry_to_geojson(geometry)[source]
to_geojson(exclude_none=True)[source]
Parameters:

exclude_none (bool)

to_dataframe()[source]

Node

Node β€” the β€œvertex” subtree of EDM.

A Node is anything that exists as a graph vertex in the model: a piece of equipment, an administrative area, a grid topology point, or a sensor. Adds two fields to Element:

  • members β€” child elements (used by WindFarm, Network, etc.)

  • tz β€” local timezone, where meaningful

Equipment-shaped vertices (WindTurbine, Battery, Sensor, GridNode, …) mix Asset via NodeAsset in energydatamodel.bases. Edges between nodes live in the sibling Edge subtree. Logical groupings (Portfolio, Site, …) live in Collection, which is a sibling of Node under Element β€” not a subclass of Node.

class energydatamodel.node.Node(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Element

An Element that exists as a graph vertex β€” can hold members and a timezone.

Subclassed by NodeAsset (equipment) and Area (administrative regions).

Parameters:
members: list[Element]
tz: tzinfo | None = None
children()[source]

Child elements for tree walking. Override in subclasses with children.

Return type:

list

add_child(obj)[source]

Attach a child. Override in subclasses that support children.

Parameters:

obj (Element)

Return type:

None

Edge

Edge β€” the β€œrelationship” subtree of EDM.

An Edge is an edge between two Node instances: a line between two buses, an interconnector between two bidding zones, a pipe between two delivery points. Edges sit sibling to Node under Element, not under Node β€” this keeps members and tz off Edges, where they don’t apply.

Concrete edge-equipment subclasses (Line, Link, Pipe, Interconnection) live in energydatamodel.grid under EdgeAsset. Note that Transformer is a node (NodeAsset), not an edge β€” it has HV and LV sides that lines connect to.

class energydatamodel.edge.Edge(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, from_element=None, to_element=None, directed=True)[source]

Bases: Element

An edge between two Nodes.

Edges are always directed by convention β€” flow in the opposite direction is expressed as a signed value on the timeseries. The directed flag is kept for explicit cases (e.g. pure bidirectional pipes).

Endpoints accept an Element, a UUID, or a Reference; __post_init__ normalizes all of these to Reference. The widened input type is a constructor convenience β€” once the edge is built, from_element and to_element always hold Reference | None.

Parameters:
from_element: Reference | Element | UUID | None = None
to_element: Reference | Element | UUID | None = None
directed: bool = True

Asset

Asset β€” mixin marking physical energy equipment.

Asset is the umbrella for anything the energy domain treats as a physical, commissioned piece of equipment: wind turbines, batteries, heat pumps, sensors, meters, power lines, transformers, pipes. It is a pure mixin β€” never instantiated directly and never used as a leaf type. Concrete equipment classes inherit from Asset together with either Node or Edge via the NodeAsset / EdgeAsset intermediates in energydatamodel.bases and energydatamodel.grid.

isinstance(x, Asset) answers β€œis this a piece of physical equipment?” uniformly across node- and edge-shaped classes.

class energydatamodel.asset.Asset(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None)[source]

Bases: Element

Marker mixin for physical energy equipment.

Carries fields genuinely shared across every piece of equipment β€” independent of whether the equipment is shaped like a graph vertex (WindTurbine) or a graph edge (Line).

Parameters:
commissioning_date: date | None = None

Bases (NodeAsset, GridNode, Sensor)

Node-side equipment intermediates.

  • NodeAsset β€” mixes Node and Asset. The single mixin point on the node side; everything physical and vertex-shaped lives below it with plain single inheritance. Subclassed directly by WindTurbine, Battery, HeatPump, etc.; and further by Sensor and GridNode for their role-specific fields.

  • Sensor β€” measurement instruments. Adds height (shared by every concrete sensor in the weather-sensor family).

  • GridNode β€” topological points in an electrical / grid network (bus, meter, delivery point). Adds carrier.

class energydatamodel.bases.NodeAsset(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None)[source]

Bases: Node, Asset

Mixin intermediate: a Node that is also an Asset.

Concrete equipment classes (WindTurbine, Battery, HeatPump, …) and the role-specific intermediates Sensor and GridNode all inherit from here. Single inheritance below this point.

Parameters:
class energydatamodel.bases.Sensor(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, height=None)[source]

Bases: NodeAsset

A measurement instrument that observes an environmental variable.

Concrete sensor subclasses (TemperatureSensor, WindSpeedSensor, …) inherit height from here and add no new fields.

Parameters:
height: float | None = None
class energydatamodel.bases.GridNode(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, carrier=None)[source]

Bases: NodeAsset

A topological point in a grid network β€” a bus, meter, or delivery point.

GridNodes are equipment too (they have manufacturers, commissioning dates, etc. via Asset). They’re distinguished from generation/consumption assets by carrying a carrier.

Parameters:
carrier: Carrier | None = None

Containers

Logical groupings (Portfolio, Site, Region, …) β€” Element subclasses that hold members but are not graph vertices.

Collection marker and container subclasses.

Collection is an Element whose primary purpose is grouping other elements. It is not a Node β€” collections aren’t graph vertices; they’re organizational/logical groupings. Collection shares the members and tz field shape with Node, but the semantics differ β€” isinstance(x, Node) on a Portfolio should return False.

Concrete subclasses carry no additional fields; they distinguish a Portfolio from a Site at the type level for serialization / introspection / UI.

Conventions:

  • Portfolio β€” trading/asset aggregate. Typically no geometry.

  • Site β€” a geographic site containing assets. Typically a Point geometry.

  • MultiSite β€” group of sites.

  • Region β€” a named geographic region with a Polygon / MultiPolygon geometry. (Distinct from Area: regions are not bound to a market / administrative scope.)

  • EnergyCommunity β€” members share resources/balance.

  • VirtualPowerPlant β€” traded flexibility aggregate.

class energydatamodel.containers.Collection(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Element

An Element whose primary purpose is grouping other Elements.

Not a Node β€” collections are organizational groupings, not graph vertices. Carries members and tz (same shape as Node, different semantics).

Parameters:
members: list[Element]
tz: tzinfo | None = None
children()[source]

Child elements for tree walking. Override in subclasses with children.

Return type:

list

add_child(obj)[source]

Attach a child. Override in subclasses that support children.

Parameters:

obj (Element)

Return type:

None

class energydatamodel.containers.Portfolio(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

A trading/asset portfolio aggregate.

Parameters:
class energydatamodel.containers.Site(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

A geographic site containing one or more assets.

Parameters:
class energydatamodel.containers.MultiSite(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

An aggregate of multiple sites.

Parameters:
class energydatamodel.containers.Region(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

A named geographic region β€” typically backed by a Polygon geometry.

Distinct from Area: a Region is not labeled by market or administrative scope; it’s a freeform geographic grouping.

Parameters:
class energydatamodel.containers.EnergyCommunity(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

An energy community β€” members share resources/balance.

Parameters:
class energydatamodel.containers.VirtualPowerPlant(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

A virtual power plant β€” traded flexibility aggregate.

Parameters:

Areas

Administrative or market-defined geographic regions (BiddingZone, Country, ControlArea, WeatherCell, SynchronousArea).

Area β€” administrative or market-defined geographic regions.

Each area type is a proper subclass of Area (no scope enum, no constructor functions). Type discrimination is via isinstance.

  • BiddingZone β€” electricity market bidding zone (e.g. SE-SE1, DE-LU)

  • Country β€” country-scoped area

  • ControlArea β€” TSO control area

  • WeatherCell β€” meteorological grid cell

  • SynchronousArea β€” AC-synchronous grid (zones sharing one frequency). Carries an extra nominal_frequency field (50 Hz in Europe / Nordic / GB / Ireland / Baltic / IPS-UPS; 60 Hz in North America).

The geometry (Polygon / MultiPolygon) lives on Element and is inherited; areas without a known polygon simply leave it None.

class energydatamodel.area.Area(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Node

An administrative or market-defined geographic region.

Parameters:
class energydatamodel.area.BiddingZone(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Area

An electricity market bidding zone (e.g. SE-SE1, DE-LU).

Parameters:
class energydatamodel.area.Country(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Area

A country-scoped area.

Parameters:
class energydatamodel.area.ControlArea(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Area

A TSO control area.

Parameters:
class energydatamodel.area.WeatherCell(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Area

A meteorological grid cell.

Parameters:
class energydatamodel.area.SynchronousArea(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None, nominal_frequency=50.0)[source]

Bases: Area

An AC-synchronous grid β€” zones that share a single operating frequency.

Examples: NSA (Nordic), CESA (Continental Europe), GBSA (Great Britain), ISA (Ireland), BSA (Baltic), IPSA (IPS/UPS). Default nominal_frequency is 50.0 Hz; set 60.0 for North American synchronous areas.

Parameters:
nominal_frequency: float = 50.0

β˜€οΈ Solar

Solar assets.

class energydatamodel.solar.FixedMount(surface_tilt=0.0, surface_azimuth=0.0)[source]

Bases: object

Parameters:
surface_tilt: float = 0.0
surface_azimuth: float = 0.0
class energydatamodel.solar.SingleAxisTrackerMount(axis_tilt=0.0, axis_azimuth=0.0, max_angle=90.0, backtrack=True, gcr=0.2857142857142857, cross_axis_tilt=0.0, racking_model=None, module_height=None)[source]

Bases: object

Parameters:
axis_tilt: float = 0.0
axis_azimuth: float = 0.0
max_angle: float | tuple = 90.0
backtrack: bool = True
gcr: float = 0.2857142857142857
cross_axis_tilt: float = 0.0
racking_model: str | None = None
module_height: float | None = None
class energydatamodel.solar.PVArray(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, surface_azimuth=None, surface_tilt=None, surface_area=None, efficiency=None, module=None, module_type='glass_polymer', module_parameters=None, temperature_model_parameters=None)[source]

Bases: NodeAsset

Parameters:
capacity: float | None = None
surface_azimuth: float | None = None
surface_tilt: float | None = None
surface_area: float | None = None
efficiency: float | None = None
module: str | None = None
module_type: str = 'glass_polymer'
module_parameters: dict | Series | None = None
temperature_model_parameters: dict | Series | None = None
class energydatamodel.solar.PVSystem(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, surface_azimuth=None, surface_tilt=None, albedo=None, surface_type=None, module_parameters=None, inverter_parameters=None, module_type='glass_polymer', racking_model='open_rack')[source]

Bases: NodeAsset

A PV system β€” an Asset that contains PVArray members.

Stored in the inherited members list. Attach arrays explicitly with pv_system.members.append(PVArray(...)) or via add_child(...) β€” no auto-creation.

Parameters:
capacity: float | None = None
surface_azimuth: float | None = None
surface_tilt: float | None = None
albedo: float | None = None
surface_type: str | None = None
module_parameters: dict | None = None
inverter_parameters: dict | None = None
module_type: str = 'glass_polymer'
racking_model: str = 'open_rack'
to_pvlib(**kwargs)[source]
class energydatamodel.solar.SolarPowerArea(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None)[source]

Bases: NodeAsset

A solar-power-potential area.

The area’s polygon lives in the inherited geometry field.

Parameters:
capacity: float | DataFrame | None = None
to_geojson(exclude_none=True)[source]
Parameters:

exclude_none (bool)

property geojson

🌬️ Wind

Wind assets.

class energydatamodel.wind.WindTurbine(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, hub_height=None, rotor_diameter=None, turbine_model=None, power_curve=None, power_coefficient_curve=None)[source]

Bases: NodeAsset

Parameters:
capacity: float | DataFrame | None = None
hub_height: float | None = None
rotor_diameter: float | None = None
turbine_model: str | None = None
power_curve: DataFrame | dict | None = None
power_coefficient_curve: DataFrame | dict | None = None
class energydatamodel.wind.WindFarm(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, farm_efficiency=None)[source]

Bases: NodeAsset

A wind farm β€” an Asset that contains WindTurbine members.

Members are stored in the inherited members list. Real wind farms can also contain met masts, transformers and substations, so children aren’t restricted to WindTurbine β€” any Element is accepted.

Parameters:
capacity: float | DataFrame | None = None
farm_efficiency: DataFrame | None = None
class energydatamodel.wind.WindPowerArea(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, area=None, farm_efficiency=None)[source]

Bases: NodeAsset

A wind-power-potential area (e.g. offshore zone).

The area’s polygon lives in the inherited geometry field. Constituent turbines or farms (if any) live in the inherited members list.

Parameters:
capacity: float | DataFrame | None = None
area: float | None = None
farm_efficiency: DataFrame | None = None

πŸ”‹ Battery

Battery asset.

class energydatamodel.battery.Battery(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, storage_capacity=None, min_soc=None, max_charge=None, max_discharge=None, charge_efficiency=None, discharge_efficiency=None)[source]

Bases: NodeAsset

Parameters:
storage_capacity: float | None = None
min_soc: float | None = None
max_charge: float | None = None
max_discharge: float | None = None
charge_efficiency: float | None = None
discharge_efficiency: float | None = None

πŸ’¦ Hydro

Hydro assets.

class energydatamodel.hydro.Reservoir(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, surface_area=None, average_depth=None)[source]

Bases: NodeAsset

Reservoir used in a hydroelectric power plant for storing water.

Parameters:
capacity: float | None = None

Water capacity in cubic meters.

surface_area: float | None = None

Surface area in square kilometers.

average_depth: float | None = None

Average depth in meters.

class energydatamodel.hydro.HydroTurbine(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, turbine_type=None, capacity=None, efficiency=None)[source]

Bases: NodeAsset

Individual hydro turbine in a hydroelectric plant.

Parameters:
turbine_type: str | None = None

e.g. Francis, Kaplan.

capacity: float | None = None

Max power output in MW.

efficiency: float | None = None

Efficiency percentage.

class energydatamodel.hydro.HydroPowerPlant(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, river=None, annual_output=None, turbine_type=None, reservoir_capacity=None, environmental_impact=None, maintenance_schedule=None)[source]

Bases: NodeAsset

Hydro power plant.

Parameters:
capacity: float | None = None

in MW.

river: str | None = None
annual_output: float | None = None

annual energy output in MWh.

turbine_type: str | None = None
reservoir_capacity: float | None = None
environmental_impact: str | None = None
maintenance_schedule: DataFrame | dict | None = None

♻️ Heat pumps

Heat pump asset.

class energydatamodel.heatpump.HeatPump(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, capacity=None, cop=None, energy_source=None)[source]

Bases: NodeAsset

A heat pump in an energy system.

Parameters:
capacity: float | None = None

heating/cooling capacity in kW.

cop: float | None = None

coefficient of performance.

energy_source: str | None = None

e.g. β€˜electricity’, β€˜geothermal’.

🏠 Buildings

Building and House β€” Assets that also contain other Assets via inherited members.

class energydatamodel.building.Building(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, type=None)[source]

Bases: NodeAsset

A building. A physical asset that also contains child Elements via the inherited members list.

Parameters:
type: str | None = None
class energydatamodel.building.House(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, type=None)[source]

Bases: NodeAsset

A house. Same structure as Building with a few convenience accessors.

Parameters:
type: str | None = None
has_demand()[source]
Return type:

bool

has_pvsystem()[source]
Return type:

bool

has_battery()[source]
Return type:

bool

get_pvsystems()[source]
Return type:

list

get_batteries()[source]
Return type:

list

🌑️ Weather sensors

Weather sensors β€” concrete Sensor subclasses observing environmental variables. height is inherited from Sensor.

class energydatamodel.weather.TemperatureSensor(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, height=None)[source]

Bases: Sensor

Parameters:
class energydatamodel.weather.WindSpeedSensor(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, height=None)[source]

Bases: Sensor

Parameters:
class energydatamodel.weather.RadiationSensor(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, height=None)[source]

Bases: Sensor

Parameters:
class energydatamodel.weather.RainSensor(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, height=None)[source]

Bases: Sensor

Parameters:
class energydatamodel.weather.HumiditySensor(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, height=None)[source]

Bases: Sensor

Parameters:

⚑ Power grid

Grid-topology classes β€” edge-equipment subclasses of EdgeAsset (Line, Link, Pipe, Interconnection), GridNode subclasses (JunctionPoint, Meter, DeliveryPoint, Transformer), Collection subclasses (SubNetwork, Network), and the plain Carrier value type.

Power-grid concrete classes.

  • EdgeAsset is the single (Edge, Asset) mixin point on the edge side. Concrete edge-equipment classes (Line, Link, Pipe, Interconnection) single-inherit from here.

  • GridNode subclasses (JunctionPoint, Meter, DeliveryPoint) live here as concrete topological points. The GridNode base lives in energydatamodel.bases. Transformer is also a GridNode (a vertex with HV and LV sides on the electricity carrier).

  • SubNetwork and Network are Collection subclasses used to group buses + lines.

  • Carrier is a plain value type (not an Element).

class energydatamodel.grid.Carrier(name, type)[source]

Bases: object

Energy carrier (electricity, gas, …). Plain value type.

Parameters:
name: str
type: str
class energydatamodel.grid.EdgeAsset(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, from_element=None, to_element=None, directed=True)[source]

Bases: Edge, Asset

Mixin intermediate: an Edge that is also an Asset.

Single mixin point on the edge side. Concrete edge equipment classes (Line, Link, Pipe, Interconnection) single-inherit from here.

Parameters:
class energydatamodel.grid.JunctionPoint(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, carrier=None)[source]

Bases: GridNode

A bus / junction in an electrical network.

Parameters:
class energydatamodel.grid.Meter(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, carrier=None)[source]

Bases: GridNode

A metering point.

Parameters:
class energydatamodel.grid.DeliveryPoint(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, carrier=None)[source]

Bases: GridNode

A delivery point (end of a feeder).

Parameters:
class energydatamodel.grid.Transformer(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, members=<factory>, tz=None, carrier=None, capacity=None, voltage_hv=None, voltage_lv=None)[source]

Bases: GridNode

Transformer joining HV and LV sides of an electrical network.

Modeled as a topological grid node, not an edge β€” matches pandapower / PyPSA topology where a transformer is a vertex with two voltage sides and edges (Lines) attach to each side. Inherits carrier from GridNode (always electricity for a transformer).

Parameters:
capacity: float | None = None

Apparent-power rating in MVA.

voltage_hv: float | None = None

HV-side nominal voltage in kV.

voltage_lv: float | None = None

LV-side nominal voltage in kV.

class energydatamodel.grid.Line(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, from_element=None, to_element=None, directed=True, capacity=None)[source]

Bases: EdgeAsset

Transmission or distribution line.

Parameters:
capacity: float | None = None

Bases: EdgeAsset

DC link or similar two-node power link.

Parameters:
capacity: float | None = None
class energydatamodel.grid.Pipe(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, from_element=None, to_element=None, directed=True, capacity=None, medium='gas')[source]

Bases: EdgeAsset

Gas / heat pipe.

Parameters:
capacity: float | None = None
medium: str = 'gas'
class energydatamodel.grid.Interconnection(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, commissioning_date=None, from_element=None, to_element=None, directed=True, capacity_forward=None, capacity_backward=None)[source]

Bases: EdgeAsset

Cross-border / cross-area interconnection between two Area nodes.

The only Edge that carries paired forward/backward capacities β€” TSO data typically reports them separately.

Parameters:
capacity_forward: float | None = None
capacity_backward: float | None = None
class energydatamodel.grid.SubNetwork(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

Subnetwork grouping buses + lines.

Parameters:
class energydatamodel.grid.Network(*, id=<factory>, name=None, timeseries=<factory>, geometry=None, extra=<factory>, lat=None, lon=None, members=<factory>, tz=None)[source]

Bases: Collection

Network grouping subnetworks + transformers + links.

Parameters:

Energy vocabulary

Quantity / Kind / Scope enums and build_metric() for assembling dotted metric strings like electricity.demand.area.

Energy vocabulary β€” Quantity / Kind / Scope enums + build_metric().

Replaces the old ElectricityDemand(TimeSeries) subclass pattern: a TimeSeries carries a string name field whose value is a dotted metric string built from (Quantity, Kind, Scope) via build_metric().

class energydatamodel.quantities.Quantity(*values)[source]

Bases: StrEnum

ELECTRICITY = 'electricity'
HEATING = 'heating'
COOLING = 'cooling'
GAS = 'gas'
TEMPERATURE = 'temperature'
PRICE = 'price'
FREQUENCY = 'frequency'
class energydatamodel.quantities.Kind(*values)[source]

Bases: StrEnum

DEMAND = 'demand'
SUPPLY = 'supply'
BALANCE = 'balance'
STATE = 'state'
SPOT = 'spot'
FLOW = 'flow'
class energydatamodel.quantities.Scope(*values)[source]

Bases: StrEnum

POINT = 'point'
AREA = 'area'
energydatamodel.quantities.build_metric(quantity, kind, scope=Scope.POINT, *extras)[source]

Build a dotted metric string, e.g. electricity.demand / electricity.demand.area.

Parameters:
Return type:

str

Convenience constructors that build metadata-only TimeSeries instances with pre-filled metric strings:

Convenience constructors that build metadata-only TimeSeries instances with pre-filled metric strings for common energy quantities.

Each constructor returns a fresh TimeSeries with df=None β€” suitable for declaring a series structure on an EDM element before any data exists.

energydatamodel.constructors.electricity_supply(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.electricity_demand(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.electricity_supply_area(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.electricity_demand_area(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.spot_price(unit='EUR / MWh', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.cross_border_flow(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.temperature(unit='degC', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.gas_supply(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.gas_demand(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.heating_demand(unit='MW', data_type=DataType.ACTUAL, frequency=None, timezone='UTC', description=None)[source]
Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

energydatamodel.constructors.grid_frequency(unit='Hz', data_type=DataType.OBSERVATION, frequency=Frequency.PT1S, timezone='UTC', description=None)[source]

Grid frequency (Hz) β€” a per-synchronous-area observation.

Frequency is shared across all zones in an AC-synchronous grid (NSA, CESA, GBSA, ISA, BSA, IPSA), so this constructor uses Scope.AREA. Default sample interval is one second; nominal value (50 / 60 Hz) lives on the SynchronousArea itself, not on the series declaration.

Parameters:
  • unit (str)

  • data_type (DataType | None)

  • frequency (Frequency | None)

  • timezone (str)

  • description (str | None)

Return type:

TimeSeries

References

Cross-tree references β€” Reference, Index, and build_index() β€” let one Element point at another by uuid without holding a hard Python reference. Useful for grid topology (an Edge referencing endpoints in a different subtree) and for round-tripping JSON without duplicating nested objects.

UUID-based cross-tree references and the Index lookup primitive.

A Reference[T] points to another Element by its stable UUID identity. Resolution against a tree builds an Index (dict[UUID, Element] produced by DFS) and uses it for O(1) lookup. References are valid the moment they’re constructed β€” no two-pass deserialize.

Path-shaped operations (Reference.path(root)) are still available for human display and debug, but are not part of the wire format.

exception energydatamodel.reference.UnresolvedReferenceError[source]

Bases: LookupError

Raised when a Reference can’t be resolved against a tree.

class energydatamodel.reference.Index(by_id=None)[source]

Bases: object

dict[UUID, Element] lookup, built once via DFS.

The Index is not live-tracked: mutate the tree after building, and the Index goes stale. Rebuild via build_index() when needed.

Parameters:

by_id (dict[UUID, Element] | None)

get(key, default=None)[source]
Parameters:

key (UUID)

add(element)[source]
Parameters:

element (Element)

Return type:

None

energydatamodel.reference.build_index(root)[source]

Walk root (DFS via children()) and collect every Element by id.

Detects cycles: a node visited twice via the same id() raises ValueError. Duplicate UUIDs (same id on two distinct objects) raise ValueError β€” UUIDs are supposed to be unique.

Parameters:

root (Element)

Return type:

Index

class energydatamodel.reference.Reference(target)[source]

Bases: Generic

A reference to another Element by its UUID.

Holds either:

  • a UUID (canonical, on the wire)

  • an Element (resolved cache)

Usage:

Reference(other_element)        # captures other_element.id
Reference(uuid_obj)             # by id directly
ref.resolve(root)               # builds Index, looks up
ref.get()                       # raises if not yet resolved
Parameters:

target (Union[UUID, str, TypeVar(T, bound= Element)])

property id: UUID

The UUID this reference points at.

is_resolved()[source]
Return type:

bool

get()[source]

Return the resolved Element. Raises if not resolved yet.

Use resolve() to resolve against a tree root first.

Return type:

Element

resolve(root_or_index)[source]

Resolve against a tree root or a pre-built Index.

Idempotent β€” once resolved, subsequent calls return the cached Element without re-walking. Pass an Index directly when resolving many References against the same tree.

Parameters:

root_or_index (Element | Index)

Return type:

Element

path(root)[source]

Best-effort name path from root to the target.

Walks root.children() looking for the target object. Used for human-readable display only β€” the wire format records UUID, not path. Names containing / are preserved as separate tuple elements.

Parameters:

root (Element)

Return type:

tuple[str, ...]

JSON I/O

Lossless JSON round-trip for any registered Element subclass. Element.__init_subclass__ auto-registers subclasses, so user-defined node/edge types serialize without any explicit decorator. Plain value dataclasses (non-Element) must register themselves via register_value_type().

JSON serialization for Element trees.

Wire format: each element β†’ {"__type__": "ClassName", "id": "<uuid>", ...fields}. Lists of Elements become nested arrays of such dicts. Reference fields become {"__ref__": "<uuid>"}. Enums become their string values. Value-type dataclasses (Carrier, …) use the same __type__ tag.

Identity is a UUID7 carried on every Element. Refs hold UUIDs directly, so element_from_json() is single-pass: there is no separate β€œresolve references” walk. Refs are valid the moment they’re constructed; Reference.resolve(root) is on-demand and idempotent.

The reserved __type__ / __ref__ / __tuple__ / __geometry__ / __tz__ keys (double-underscore prefix) avoid collisions with dataclass fields β€” classes like Building and House have a type field of their own, which must survive round-trip.

energydatamodel.json_io.register_element(cls)[source]

Register an Element subclass under its class name for JSON dispatch.

Parameters:

cls (type[Element])

Return type:

type[Element]

energydatamodel.json_io.register_value_type(cls)[source]

Register a non-Element value dataclass (Carrier, …) for JSON dispatch.

Value types carry a __type__ tag on the wire and are instantiated by class-name lookup on load. Analogous to register_element but without the Element inheritance requirement.

Parameters:

cls (type)

Return type:

type

energydatamodel.json_io.get_registry()[source]
Return type:

dict[str, type[Element]]

energydatamodel.json_io.element_to_json(element, *, exclude_fields=None)[source]

Public: serialize an Element (and its subtree) to a JSON-compatible dict.

Every Element emits its id (UUID7) so round-trip preserves identity. Refs emit {"__ref__": "<uuid>"} regardless of whether they were constructed from a UUID or a resolved Element.

Parameters:
  • element (Element) – The Element to serialize.

  • exclude_fields (set | None) – Set of field names to skip when serializing. Applied recursively to nested Elements (e.g. passing {"members"} produces a flat, children-free dict). See element_to_storage_dict() for the canonical flat-row form.

Return type:

dict

energydatamodel.json_io.to_json_str(element, *, indent=None, exclude_fields=None)[source]

Convenience: return a JSON string instead of a dict.

Parameters:
Return type:

str

energydatamodel.json_io.element_to_storage_dict(element, *, extra_excludes=None)[source]

Flat-row serialization: element’s own fields only, children excluded.

Suitable for persistence layers that store tree structure separately (e.g. via parent_uuid columns rather than nested JSON). Children fields (those marked children=True in their infra metadata) are excluded automatically; add more via extra_excludes (e.g. {"from_element", "to_element"} for edges whose endpoints are stored as FK columns).

Parameters:
Return type:

dict

energydatamodel.json_io.element_from_json(data, *, expected_type=None)[source]

Public: deserialize a JSON-compatible dict into an Element tree.

Single-pass: refs become Reference(uuid) immediately and are valid at construction time. Resolution against the tree is on-demand via Reference.resolve().

Parameters:
Return type:

Element

energydatamodel.json_io.from_json_str(text, *, expected_type=None)[source]
Parameters:
Return type:

Element

energydatamodel.json_io.register_builtin_elements()[source]

Register all Element subclasses reachable via __subclasses__ at call time.

Use as a fallback so callers don’t have to decorate every class manually β€” the explicit @register_element decorator remains the canonical path. Walks the whole Element subtree (Node, Edge, Asset, Collection, and all their descendants).

Return type:

None