66from __future__ import annotations
77
88import logging
9- from collections import abc
109
1110from ....microgrid import connection_manager
1211from ....microgrid .component import ComponentCategory , ComponentMetricId
@@ -33,14 +32,20 @@ def generate(self) -> FormulaEngine[Power]:
3332 "pv-power" , ComponentMetricId .ACTIVE_POWER , Power .from_watts
3433 )
3534
36- pv_components = self ._get_pv_power_components ()
35+ component_graph = connection_manager .get ().component_graph
36+ pv_components = component_graph .dfs (
37+ self ._get_grid_component (),
38+ set (),
39+ component_graph .is_pv_chain ,
40+ )
41+
3742 if not pv_components :
3843 _logger .warning (
39- "Unable to find any PV inverters in the component graph. "
44+ "Unable to find any PV components in the component graph. "
4045 "Subscribing to the resampling actor with a non-existing "
4146 "component id, so that `0` values are sent from the formula."
4247 )
43- # If there are no PV inverters , we have to send 0 values at the same
48+ # If there are no PV components , we have to send 0 values at the same
4449 # frequency as the other streams. So we subscribe with a non-existing
4550 # component id, just to get a `None` message at the resampling interval.
4651 builder .push_component_metric (
@@ -50,11 +55,15 @@ def generate(self) -> FormulaEngine[Power]:
5055
5156 builder .push_oper ("(" )
5257 builder .push_oper ("(" )
53- for idx , comp_id in enumerate (pv_components ):
58+ for idx , component in enumerate (pv_components ):
5459 if idx > 0 :
5560 builder .push_oper ("+" )
5661
57- builder .push_component_metric (comp_id , nones_are_zeros = True )
62+ # should only be the case if the component is not a meter
63+ builder .push_component_metric (
64+ component .component_id ,
65+ nones_are_zeros = component .category != ComponentCategory .METER ,
66+ )
5867 builder .push_oper (")" )
5968 if self ._config .formula_type == FormulaType .PRODUCTION :
6069 builder .push_oper ("*" )
@@ -65,31 +74,3 @@ def generate(self) -> FormulaEngine[Power]:
6574 builder .push_clipper (0.0 , None )
6675
6776 return builder .build ()
68-
69- def _get_pv_power_components (self ) -> abc .Set [int ]:
70- """Get the component ids of the PV inverters or meters in the component graph.
71-
72- Returns:
73- A set of component ids of the PV inverters or meters in the component graph.
74-
75- Raises:
76- RuntimeError: if the grid component has no PV inverters or meters as successors.
77- """
78- component_graph = connection_manager .get ().component_graph
79- grid_successors = self ._get_grid_component_successors ()
80-
81- if len (grid_successors ) == 1 :
82- successor = next (iter (grid_successors ))
83- if successor .category != ComponentCategory .METER :
84- raise RuntimeError (
85- "Only grid successor in the component graph is not a meter."
86- )
87- grid_successors = component_graph .successors (successor .component_id )
88-
89- pv_meters_or_inverters : set [int ] = set ()
90-
91- for successor in grid_successors :
92- if component_graph .is_pv_chain (successor ):
93- pv_meters_or_inverters .add (successor .component_id )
94-
95- return pv_meters_or_inverters
0 commit comments