Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
8 changes: 5 additions & 3 deletions src/echo/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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]:
Expand All @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion src/echo/models/electrical.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down
Loading