Skip to content

Commit dad5efa

Browse files
committed
ignore optics if no platform
1 parent eb59367 commit dad5efa

File tree

5 files changed

+1794
-18
lines changed

5 files changed

+1794
-18
lines changed

ngraph/explorer.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,14 @@ def set_node_counts(n: TreeNode):
270270

271271
# 2) Accumulate node capex/power and validate hardware capacity vs attached links
272272
# Also validate that sum of endpoint optics usage does not exceed node port count
273+
# Track which nodes actually have chassis/hardware assigned; optics at a link
274+
# endpoint should contribute cost/power only when the endpoint node has
275+
# hardware. Without node hardware, optics cannot be installed and should be
276+
# ignored in aggregation and capacity validation.
277+
node_has_hw: Dict[str, bool] = {}
273278
for nd in self.network.nodes.values():
274279
comp, hw_count = resolve_node_hardware(nd.attrs, self.components_library)
280+
node_has_hw[nd.name] = comp is not None
275281
if nd.attrs.get("hardware") and comp is None:
276282
logger.warning(
277283
"Node '%s' references unknown node hardware component '%s'.",
@@ -427,7 +433,9 @@ def set_node_counts(n: TreeNode):
427433
dst_name,
428434
)
429435

430-
if src_comp is not None:
436+
# Optics contribute only if the endpoint node has hardware
437+
src_endpoint_has_hw = node_has_hw.get(src, False)
438+
if src_comp is not None and src_endpoint_has_hw:
431439
# For BOM, apply ceiling for exclusive use
432440
src_cnt_bom = float(int(src_cnt) if src_exclusive else src_cnt)
433441
src_cost, src_power, src_cap = totals_with_multiplier(
@@ -436,15 +444,21 @@ def set_node_counts(n: TreeNode):
436444
else:
437445
src_cost, src_power, src_cap = 0.0, 0.0, 0.0
438446
src_cnt_bom = 0.0
447+
# Prevent BOM accumulation below
448+
if not src_endpoint_has_hw:
449+
src_comp = None
439450

440-
if dst_comp is not None:
451+
dst_endpoint_has_hw = node_has_hw.get(dst, False)
452+
if dst_comp is not None and dst_endpoint_has_hw:
441453
dst_cnt_bom = float(int(dst_cnt) if dst_exclusive else dst_cnt)
442454
dst_cost, dst_power, dst_cap = totals_with_multiplier(
443455
dst_comp, dst_cnt
444456
)
445457
else:
446458
dst_cost, dst_power, dst_cap = 0.0, 0.0, 0.0
447459
dst_cnt_bom = 0.0
460+
if not dst_endpoint_has_hw:
461+
dst_comp = None
448462

449463
link_cost = src_cost + dst_cost
450464
link_power = src_power + dst_power

ngraph/workflow/cost_power_efficiency.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ def _link_enabled(link_obj: Any) -> bool:
263263
# Reuse the same selection as links_for_sum to ensure endpoint-enabled check
264264
links_iter = links_for_sum
265265

266+
# Precompute which nodes have chassis/hardware; optics are ignored when absent
267+
node_has_hw: Dict[str, bool] = {}
268+
for nd in network.nodes.values():
269+
nd_comp, _nd_cnt = resolve_node_hardware(nd.attrs, library)
270+
node_has_hw[nd.name] = nd_comp is not None
271+
266272
for lk in links_iter:
267273
(src_end, dst_end, per_end) = resolve_link_end_components(
268274
lk.attrs, library
@@ -278,14 +284,20 @@ def _totals_with_max(c, n) -> tuple[float, float, float, float]:
278284
power_max = float(c.total_power_max() * n)
279285
return capex, power, cap, power_max
280286

281-
# Compute endpoints
282-
src_capex, src_power, src_cap, src_power_max = _totals_with_max(
283-
src_comp, src_cnt
284-
)
287+
# Compute endpoints; ignore optics if the endpoint node has no hardware
288+
if src_comp is not None and node_has_hw.get(lk.source, False):
289+
_, src_power, src_cap, src_power_max = _totals_with_max(
290+
src_comp, src_cnt
291+
)
292+
else:
293+
src_power, src_cap, src_power_max = 0.0, 0.0, 0.0
285294

286-
dst_capex, dst_power, dst_cap, dst_power_max = _totals_with_max(
287-
dst_comp, dst_cnt
288-
)
295+
if dst_comp is not None and node_has_hw.get(lk.target, False):
296+
_, dst_power, dst_cap, dst_power_max = _totals_with_max(
297+
dst_comp, dst_cnt
298+
)
299+
else:
300+
dst_power, dst_cap, dst_power_max = 0.0, 0.0, 0.0
289301

290302
# Aggregate per-link
291303
power_watts = float(src_power + dst_power)
@@ -305,12 +317,14 @@ def _totals_with_max(c, n) -> tuple[float, float, float, float]:
305317
"source": {
306318
"component": src_comp.name
307319
if src_comp is not None
320+
and node_has_hw.get(lk.source, False)
308321
else None,
309322
"count": float(src_cnt),
310323
},
311324
"target": {
312325
"component": dst_comp.name
313326
if dst_comp is not None
327+
and node_has_hw.get(lk.target, False)
314328
else None,
315329
"count": float(dst_cnt),
316330
},

0 commit comments

Comments
 (0)