55
66from __future__ import annotations
77
8+ import logging
9+
810from ....microgrid import connection_manager
911from ....microgrid .component import ComponentCategory , ComponentMetricId
1012from ..._quantities import Power
1113from .._formula_engine import FormulaEngine
1214from ._formula_generator import NON_EXISTING_COMPONENT_ID , FormulaGenerator
1315
16+ _logger = logging .getLogger (__name__ )
17+
1418
1519class ProducerPowerFormula (FormulaGenerator [Power ]):
1620 """Formula generator from component graph for calculating the Producer Power.
@@ -34,36 +38,37 @@ def generate(self) -> FormulaEngine[Power]:
3438 builder = self ._get_builder (
3539 "producer_power" , ComponentMetricId .ACTIVE_POWER , Power .from_watts
3640 )
41+
3742 component_graph = connection_manager .get ().component_graph
38- grid_successors = self ._get_grid_component_successors ()
39-
40- if len (grid_successors ) == 1 :
41- grid_meter = next (iter (grid_successors ))
42- if grid_meter .category != ComponentCategory .METER :
43- raise RuntimeError (
44- "Only grid successor in the component graph is not a meter."
45- )
46- grid_successors = component_graph .successors (grid_meter .component_id )
47-
48- first_iteration = True
49- for successor in iter (grid_successors ):
50- # if in the future we support additional producers, we need to add them here
51- if component_graph .is_chp_chain (successor ) or component_graph .is_pv_chain (
52- successor
53- ):
54- if not first_iteration :
55- builder .push_oper ("+" )
56-
57- first_iteration = False
58-
59- builder .push_component_metric (
60- successor .component_id ,
61- nones_are_zeros = successor .category != ComponentCategory .METER ,
62- )
63-
64- if first_iteration :
43+ # if in the future we support additional producers, we need to add them to the lambda
44+ producer_components = component_graph .dfs (
45+ self ._get_grid_component (),
46+ set (),
47+ lambda component : component_graph .is_pv_chain (component )
48+ or component_graph .is_chp_chain (component ),
49+ )
50+
51+ if not producer_components :
52+ _logger .warning (
53+ "Unable to find any producer components in the component graph. "
54+ "Subscribing to the resampling actor with a non-existing "
55+ "component id, so that `0` values are sent from the formula."
56+ )
57+ # If there are no producer components, we have to send 0 values at the same
58+ # frequency as the other streams. So we subscribe with a non-existing
59+ # component id, just to get a `None` message at the resampling interval.
6560 builder .push_component_metric (
6661 NON_EXISTING_COMPONENT_ID , nones_are_zeros = True
6762 )
63+ return builder .build ()
64+
65+ for idx , component in enumerate (producer_components ):
66+ if idx > 0 :
67+ builder .push_oper ("+" )
68+
69+ builder .push_component_metric (
70+ component .component_id ,
71+ nones_are_zeros = component .category != ComponentCategory .METER ,
72+ )
6873
6974 return builder .build ()
0 commit comments