You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* FlowContainer implementation is complete. Here's a summary of what was done:
Summary
1. Created FlowContainer Class (structure.py)
- Added FlowContainer class that extends ContainerMixin
- Uses flow.label_full as the key (e.g., 'Boiler(Q_th)')
- Supports index-based access: inputs[0]
- Supports label-based access: inputs['Boiler(Q_th)']
- Added __add__ method to ContainerMixin for concatenation
2. Updated Component Class (elements.py)
- Changed inputs and outputs from list[Flow] to FlowContainer
- Modified __init__ to accept both list[Flow] and dict[str, Flow] (for deserialization)
- Updated _check_unique_flow_labels() and _connect_flows() to accept lists as parameters
- FlowContainers are created after connecting flows (so label_full is correct)
3. Updated Bus Class (elements.py)
- Changed inputs and outputs from list[Flow] to FlowContainer
4. Updated Iteration Patterns
All iteration patterns were updated from:
- for flow in self.inputs: → for flow in self.inputs.values():
- for flow in self.inputs + self.outputs: → for flow in (self.inputs + self.outputs).values():
Files updated:
- elements.py (Component, Bus, BusModel, ComponentModel)
- components.py (TransmissionModel, LinearConverterModel)
- flow_system.py (flow population and network connection)
- io.py (format_flow_details)
- statistics_accessor.py (various plotting methods)
- tests/deprecated/test_integration.py
Usage Examples
boiler = Boiler(label='Boiler', inputs=[Flow('Q_th', bus=heat_bus)])
# Both access methods work
assert boiler.inputs[0] == boiler.inputs['Boiler(Q_th)']
assert len(boiler.inputs) == 1
# Iteration requires .values()
for flow in boiler.inputs.values():
print(flow.label_full)
# Concatenation works
all_flows = boiler.inputs + boiler.outputs
for flow in all_flows.values():
print(flow.label)
All 1570 tests passed.
* Summary
Added all_flows property to Component and Bus classes using itertools.chain:
@Property
def all_flows(self) -> Iterator[Flow]:
"""Iterate over all flows (inputs and outputs) without creating intermediate containers."""
return chain(self.inputs.values(), self.outputs.values())
Performance Improvement
┌─────────┬──────────────────────────────┬───────────────────────┐
│ Pattern │ Before │ After │
├─────────┼──────────────────────────────┼───────────────────────┤
│ Memory │ O(n) - creates new container │ O(1) - iterator only │
├─────────┼──────────────────────────────┼───────────────────────┤
│ Time │ O(n) - copies all elements │ O(1) - lazy iteration │
└─────────┴──────────────────────────────┴───────────────────────┘
Usage
# Efficient iteration (no allocation)
for flow in component.all_flows:
...
# When you need a list (e.g., reusing multiple times)
all_flows = list(component.all_flows)
# Container concatenation still available when needed
combined = component.inputs + component.outputs # Creates new FlowContainer
Files Updated
- elements.py - Added property, updated 8 iteration patterns
- components.py - Updated 1 pattern
- flow_system.py - Updated 3 patterns
- statistics_accessor.py - Updated 1 pattern
All 1570 tests pass.
* Summary
1. FlowContainer now supports short-label access
When all flows in a container belong to the same component, you can access by short label:
# Both work for component.inputs, component.outputs, and component.flows:
component.inputs['Boiler(Q_th)'] # Full label
component.inputs['Q_th'] # Short label ✓
# The `in` operator also supports short labels:
if 'Q_th' in component.flows: # Works!
...
2. Component.flows is now a FlowContainer (cached property)
# Before (dict keyed by short label):
component.flows: dict[str, Flow]
# After (FlowContainer with full/short label access):
component.flows: FlowContainer # cached_property
API Summary
┌─────────────────────┬──────────────────────────────────────┐
│ Access Pattern │ Example │
├─────────────────────┼──────────────────────────────────────┤
│ Full label │ component.flows['Boiler(Q_th)'] │
├─────────────────────┼──────────────────────────────────────┤
│ Short label │ component.flows['Q_th'] │
├─────────────────────┼──────────────────────────────────────┤
│ Index │ component.flows[0] │
├─────────────────────┼──────────────────────────────────────┤
│ Membership │ 'Q_th' in component.flows │
├─────────────────────┼──────────────────────────────────────┤
│ Iteration │ for flow in component.flows.values() │
├─────────────────────┼──────────────────────────────────────┤
│ Efficient iteration │ for flow in component.all_flows │
└─────────────────────┴──────────────────────────────────────┘
Note: Short-label access only works when all flows in the container share the same component (which is always true for component.inputs,
component.outputs, and component.flows).
* Remove all_flows and make bus.flows non cahced!
* Udpate Changelo
flow_system.topology.set_component_colors('turbo', overwrite=False) # Only unset colors
259
259
```
260
260
261
+
#### FlowContainer for Component Flows (#587)
262
+
263
+
`Component.inputs`, `Component.outputs`, and `Component.flows` now use `FlowContainer` (dict-like) with dual access by index or label: `inputs[0]` or `inputs['Q_th']`.
264
+
261
265
### 💥 Breaking Changes
262
266
263
267
#### tsam v3 Migration
@@ -296,6 +300,7 @@ fs.transform.cluster(
296
300
#### Other Breaking Changes
297
301
298
302
-`FlowSystem.scenario_weights` are now always normalized to sum to 1 when set (including after `.sel()` subsetting)
303
+
-`Component.inputs`/`outputs` and `Bus.inputs`/`outputs` are now `FlowContainer` (dict-like). Use `.values()` to iterate flows.
0 commit comments