diff --git a/CHANGELOG.md b/CHANGELOG.md index ab795a91..9f920cdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## Unreleased + +#### Adds + +- Adds support for unconnected (dangling) ports by setting `all_dangling_port` to True. + +#### Changes + +- Prevents warnings for unconnected (dangling) ports on EVs. + + ## Releases ### v2.2.6 (2026-08-10) diff --git a/src/echo/models/base.py b/src/echo/models/base.py index 0f15b0cb..305e920a 100644 --- a/src/echo/models/base.py +++ b/src/echo/models/base.py @@ -67,6 +67,7 @@ class Port(BaseModel): active_periods: dict[tuple[int, int], Any] | None = None slack: bool = False objective: en.numeric_expr.NumericExpression | float = 0 # this will eventually be a pyomo expression + allow_dangling_port: bool = False # Validators for import/export constraint values import_con_sign = validator("import_constraint_value", allow_reuse=True)(import_cons_check) @@ -1435,11 +1436,12 @@ def print_port_names(self) -> None: for pn, p in n.ports.items(): print(pn, ", ", p.port_name) - def get_port_names_from_nodes(self) -> set[str]: + def get_port_names_from_nodes(self, skip_dangling_ports: bool = False) -> set[str]: output = set() for n in self.node_obj.values(): for p in n.ports.values(): - output.add(p.port_name) + if skip_dangling_ports and not p.allow_dangling_port: + output.add(p.port_name) return output def get_port_names_from_edges(self) -> set[str]: @@ -1454,7 +1456,7 @@ def verify_graph(self) -> None: are unconnected ports""" validate(nx.is_connected(self.convert_to_nx()) is True, "Graph is not connected.") # Check graph for ports that are not connected - ports_on_edges = self.get_port_names_from_nodes() + ports_on_edges = self.get_port_names_from_nodes(skip_dangling_ports=True) ports_on_nodes = self.get_port_names_from_edges() diff = ports_on_edges - ports_on_nodes # check overlap if len(diff) != 0: diff --git a/src/echo/models/electrical.py b/src/echo/models/electrical.py index a9cbc584..bc318a3c 100644 --- a/src/echo/models/electrical.py +++ b/src/echo/models/electrical.py @@ -272,7 +272,8 @@ def _create_usage_port(self) -> None: """ # Create the usage port and assign it to the EV object - self.ports["usage"] = ElectricalDemand() + # Usage ports are not connected to other ports via edges so we set `allow_dangling_port` to True + self.ports["usage"] = ElectricalDemand(allow_dangling_port=True) # TODO: Set demand here if set_stateful_attrs_at_init is True @@ -303,6 +304,7 @@ def _create_vehicle_port(self) -> None: enable_trip_slack=self.enable_trip_slack, soc_conserv=self.soc_conserv, soc_conserv_cost=self.soc_conserv_cost, + allow_dangling_port=True, # vehicle port is not connect to another port ) def _create_connection_point_port(self) -> None: