"""Collection marker and container subclasses.
:class:`Collection` is an :class:`Element` whose primary purpose is grouping
other elements. It is **not** a :class:`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 :class:`Area`: regions are not bound to a market /
administrative scope.)
* ``EnergyCommunity`` β members share resources/balance.
* ``VirtualPowerPlant`` β traded flexibility aggregate.
"""
import datetime
from dataclasses import dataclass
from energydatamodel.element import Element, infra
[docs]
@dataclass(repr=False, kw_only=True)
class Collection(Element):
"""An Element whose primary purpose is grouping other Elements.
Not a :class:`Node` β collections are organizational groupings, not graph
vertices. Carries ``members`` and ``tz`` (same shape as Node, different
semantics).
"""
members: list[Element] = infra(default_factory=list, children=True)
tz: datetime.tzinfo | None = infra(default=None)
[docs]
def children(self) -> list:
return list(self.members)
[docs]
def add_child(self, obj: Element) -> None:
if not isinstance(obj, Element):
raise TypeError(f"{type(self).__name__} only accepts Element children, got {type(obj).__name__}")
self.members.append(obj)
[docs]
@dataclass(repr=False, kw_only=True)
class Portfolio(Collection):
"""A trading/asset portfolio aggregate."""
[docs]
@dataclass(repr=False, kw_only=True)
class Site(Collection):
"""A geographic site containing one or more assets."""
@dataclass(repr=False, kw_only=True)
class MultiSite(Collection):
"""An aggregate of multiple sites."""
@dataclass(repr=False, kw_only=True)
class Region(Collection):
"""A named geographic region β typically backed by a Polygon geometry.
Distinct from :class:`Area`: a Region is not labeled by market or
administrative scope; it's a freeform geographic grouping.
"""
@dataclass(repr=False, kw_only=True)
class VirtualPowerPlant(Collection):
"""A virtual power plant β traded flexibility aggregate."""