Skip to content

Commit 752707d

Browse files
authored
[DEV-6953] Reordered the feeder equipment and direction assignment on database read (#214)
Signed-off-by: Anthony Charlton <anthony.charlton@zepben.com>
1 parent f50d908 commit 752707d

5 files changed

Lines changed: 44 additions & 15 deletions

File tree

changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* None.
1111

1212
### Fixes
13-
* None.
13+
* Reordered the feeder equipment and direction assignment on database read to prevent parallel feeders from tracing back into the zone substation.
1414

1515
### Notes
1616
* None.

src/zepben/ewb/database/sqlite/network/network_database_reader.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@ def __init__(
7575
async def _post_load(self) -> bool:
7676
status = await super()._post_load()
7777

78+
#
79+
# NOTE: We need to have the feeder head equipment assigned before we can set the feeder directions to prevent
80+
# tracing back into the zone substation in parallel feeders. Rather than splitting the feeder assignment
81+
# into two passes, we can just assign the equipment to feeders before we set the directions.
82+
#
83+
self._logger.info("Assigning equipment to feeders...")
84+
await self.assign_to_feeders.run(self.service, network_state_operators=NetworkStateOperators.NORMAL)
85+
await self.assign_to_feeders.run(self.service, network_state_operators=NetworkStateOperators.CURRENT)
86+
self._logger.info("Equipment assigned to feeders.")
87+
88+
self._logger.info("Assigning equipment to LV feeders...")
89+
await self.assign_to_lv_feeders.run(self.service, network_state_operators=NetworkStateOperators.NORMAL)
90+
await self.assign_to_lv_feeders.run(self.service, network_state_operators=NetworkStateOperators.CURRENT)
91+
self._logger.info("Equipment assigned to LV feeders.")
92+
7893
self._logger.info("Applying feeder direction to network...")
7994
await self.set_feeder_direction.run(self.service, network_state_operators=NetworkStateOperators.NORMAL)
8095
await self.set_feeder_direction.run(self.service, network_state_operators=NetworkStateOperators.CURRENT)
@@ -91,16 +106,6 @@ async def _post_load(self) -> bool:
91106

92107
self._logger.info("Phasing applied to network.")
93108

94-
self._logger.info("Assigning equipment to feeders...")
95-
await self.assign_to_feeders.run(self.service, network_state_operators=NetworkStateOperators.NORMAL)
96-
await self.assign_to_feeders.run(self.service, network_state_operators=NetworkStateOperators.CURRENT)
97-
self._logger.info("Equipment assigned to feeders.")
98-
99-
self._logger.info("Assigning equipment to LV feeders...")
100-
await self.assign_to_lv_feeders.run(self.service, network_state_operators=NetworkStateOperators.NORMAL)
101-
await self.assign_to_lv_feeders.run(self.service, network_state_operators=NetworkStateOperators.CURRENT)
102-
self._logger.info("Equipment assigned to LV feeders.")
103-
104109
self._logger.info("Validating that each equipment is assigned to a container...")
105110
self._validate_equipment_containers()
106111
self._logger.info("Equipment containers validated.")

src/zepben/ewb/services/network/tracing/feeder/set_direction.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ class SetDirection:
3333
"""
3434
Convenience class that provides methods for setting feeder direction on a [NetworkService]
3535
This class is backed by a [BranchRecursiveTraversal].
36+
37+
NOTE: The feeder head equipment must be assigned to its [Feeder] before this is run. If you don't,
38+
the feeder direction will be assigned back through feeder heads when they are run in parallel.
39+
40+
:param debug_logger: An optional `Logger` that can be used to log debug messages on what the underlying trace is doing. This
41+
should only ever be used in a debug cycle, and should always be `None` in production code.
3642
"""
3743

3844
def __init__(self, debug_logger: Logger = None):

test/database/sqlite/network/test_network_database_reader.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ async def test_calls_expected_processors_including_post_processes(self):
111111
call.service.unresolved_references(),
112112
call.service.unresolved_references().__iter__,
113113

114+
call.assign_to_feeders.run(self.service),
115+
call.assign_to_lv_feeders.run(self.service),
114116
call.set_direction.run(self.service),
115117
call.set_phases.run(self.service),
116118
call.phase_inferrer.run(self.service),
117-
call.assign_to_feeders.run(self.service),
118-
call.assign_to_lv_feeders.run(self.service),
119119

120120
# calls for _validate_equipment_containers()
121121
call.service.objects(Equipment),

test/database/sqlite/network/test_network_database_schema.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
PotentialTransformer, SwitchInfo, RelayInfo, CurrentRelay, EvChargingUnit, TapChangerControl, DistanceRelay, VoltageRelay, ProtectionRelayScheme, \
4242
ProtectionRelaySystem, Ground, GroundDisconnector, SeriesCompensator, NetworkService, GroundingImpedance, \
4343
PetersenCoil, ReactiveCapabilityCurve, SynchronousMachine, PanDemandResponseFunction, BatteryControl, StaticVarCompensator, Tracing, NetworkStateOperators, \
44-
NetworkTraceStep
44+
NetworkTraceStep, TestNetworkBuilder
4545
from zepben.ewb.model.cim.iec61968.assetinfo.cable_info import CableInfo
4646
from zepben.ewb.model.cim.iec61968.assetinfo.overhead_wire_info import OverheadWireInfo
4747
from zepben.ewb.model.cim.iec61968.assets.asset_owner import AssetOwner
@@ -66,13 +66,13 @@
6666
from zepben.ewb.model.cim.iec61970.base.wires.ratio_tap_changer import RatioTapChanger
6767
from zepben.ewb.services.common import resolver
6868

69-
7069
hypothesis_settings = dict(
7170
deadline=2000,
7271
suppress_health_check=[HealthCheck.function_scoped_fixture, HealthCheck.too_slow],
7372
max_examples=4
7473
)
7574

75+
7676
# FIXME: see Line [305]
7777
class PatchedNetworkTraceStepPath(NetworkTraceStep.Path):
7878
@property
@@ -702,6 +702,24 @@ def add_deferred_reference(service: NetworkService):
702702

703703
await self._validate_unresolved_failure(str(pec), "RegulatingControl tcc", add_deferred_reference)
704704

705+
async def test_assigns_feeders_in_parallel_correctly(self):
706+
# This test is to ensure parallel feeders don't assign directions back through the feeder heads. This was seen in the wild when
707+
# the feeder directions were set before the equipment was assigned, meaning no feeder heads were detected in the tracing.
708+
ns = await (
709+
TestNetworkBuilder()
710+
.from_source() # s0
711+
.to_breaker() # b1
712+
.to_acls() # c2
713+
.to_breaker() # b3
714+
.to_source() # s4
715+
.add_feeder("b1", 2)
716+
.add_feeder("b3", 1)
717+
.build(apply_directions_from_sources=False)
718+
)
719+
720+
# If the read from the database matches the test network we built, then the equipment is correctly assigned.
721+
await self._validate_schema(ns)
722+
705723
async def test_only_loads_street_address_fields_if_required(self):
706724
# This test is here to make sure the database reading correctly removes the parts of loaded street addresses that are not filled out.
707725
write_service = NetworkService()

0 commit comments

Comments
 (0)