Skip to content

Commit 3edf6a5

Browse files
authored
Update generated formulas to follow the new naming scheme (#350)
**New power streaming methods** - _public api_ - `BatteryPool.{production_power, consumption_power}` - `EVChargerPool.{production_power, consumption_power}` - LogicalMeter: - `consumer_power` - `grid_production_power` - `grid_consumption_power` - `chp_power` - `chp_production_power` - `chp_consumption_power` (probably not necessary, but having just a production method was a bit weird) **New FormulaEngine steps** - _internal_ - `ConstantValue` - for multiplying formula outputs with `-1` to get production power. - `Clipper` - for clipping formula outputs to 0.0 in production/consumption power formulas. **New component graph methods** - _internal_ - `is_pv_inverter`, `is_pv_meter`, `is_pv_chain` - `is_battery_inverter`, `is_battery_meter`, `is_battery_chain` - `is_ev_charger`, `is_ev_charger_meter`, `is_ev_charger_chain`, - `is_chp`, `is_chp_meter`, `is_chp_chain` These methods were particularly useful in the creation of the `consumer_power` formula. The `*chain` methods return true if either of the other corresponding methods return true. Maybe there's a better name, but it is for internal use.
2 parents 8cc06a4 + d3d6b31 commit 3edf6a5

File tree

20 files changed

+1590
-109
lines changed

20 files changed

+1590
-109
lines changed

src/frequenz/sdk/microgrid/_graph.py

Lines changed: 338 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import networkx as nx
3131

3232
from .client import Connection, MicrogridApiClient
33-
from .component import Component, ComponentCategory
33+
from .component import Component, ComponentCategory, InverterType
3434

3535
_logger = logging.getLogger(__name__)
3636

@@ -113,6 +113,159 @@ def successors(self, component_id: int) -> Set[Component]:
113113
KeyError: if the specified `component_id` is not in the graph
114114
"""
115115

116+
@abstractmethod
117+
def is_pv_inverter(self, component: Component) -> bool:
118+
"""Check if the specified component is a PV inverter.
119+
120+
Args:
121+
component: component to check.
122+
123+
Returns:
124+
Whether the specified component is a PV inverter.
125+
"""
126+
127+
@abstractmethod
128+
def is_pv_meter(self, component: Component) -> bool:
129+
"""Check if the specified component is a PV meter.
130+
131+
This is done by checking if the component has only PV inverters as its
132+
successors.
133+
134+
Args:
135+
component: component to check.
136+
137+
Returns:
138+
Whether the specified component is a PV meter.
139+
"""
140+
141+
@abstractmethod
142+
def is_pv_chain(self, component: Component) -> bool:
143+
"""Check if the specified component is part of a PV chain.
144+
145+
A component is part of a PV chain if it is a PV meter or a PV inverter.
146+
147+
Args:
148+
component: component to check.
149+
150+
Returns:
151+
Whether the specified component is part of a PV chain.
152+
"""
153+
154+
@abstractmethod
155+
def is_battery_inverter(self, component: Component) -> bool:
156+
"""Check if the specified component is a battery inverter.
157+
158+
Args:
159+
component: component to check.
160+
161+
Returns:
162+
Whether the specified component is a battery inverter.
163+
"""
164+
165+
@abstractmethod
166+
def is_battery_meter(self, component: Component) -> bool:
167+
"""Check if the specified component is a battery meter.
168+
169+
This is done by checking if the component has only battery inverters as its
170+
predecessors.
171+
172+
Args:
173+
component: component to check.
174+
175+
Returns:
176+
Whether the specified component is a battery meter.
177+
"""
178+
179+
@abstractmethod
180+
def is_battery_chain(self, component: Component) -> bool:
181+
"""Check if the specified component is part of a battery chain.
182+
183+
A component is part of a battery chain if it is a battery meter or a battery
184+
inverter.
185+
186+
Args:
187+
component: component to check.
188+
189+
Returns:
190+
Whether the specified component is part of a battery chain.
191+
"""
192+
193+
@abstractmethod
194+
def is_ev_charger(self, component: Component) -> bool:
195+
"""Check if the specified component is an EV charger.
196+
197+
Args:
198+
component: component to check.
199+
200+
Returns:
201+
Whether the specified component is an EV charger.
202+
"""
203+
204+
@abstractmethod
205+
def is_ev_charger_meter(self, component: Component) -> bool:
206+
"""Check if the specified component is an EV charger meter.
207+
208+
This is done by checking if the component has only EV chargers as its
209+
successors.
210+
211+
Args:
212+
component: component to check.
213+
214+
Returns:
215+
Whether the specified component is an EV charger meter.
216+
"""
217+
218+
@abstractmethod
219+
def is_ev_charger_chain(self, component: Component) -> bool:
220+
"""Check if the specified component is part of an EV charger chain.
221+
222+
A component is part of an EV charger chain if it is an EV charger meter or an
223+
EV charger.
224+
225+
Args:
226+
component: component to check.
227+
228+
Returns:
229+
Whether the specified component is part of an EV charger chain.
230+
"""
231+
232+
@abstractmethod
233+
def is_chp(self, component: Component) -> bool:
234+
"""Check if the specified component is a CHP.
235+
236+
Args:
237+
component: component to check.
238+
239+
Returns:
240+
Whether the specified component is a CHP.
241+
"""
242+
243+
@abstractmethod
244+
def is_chp_meter(self, component: Component) -> bool:
245+
"""Check if the specified component is a CHP meter.
246+
247+
This is done by checking if the component has only CHPs as its successors.
248+
249+
Args:
250+
component: component to check.
251+
252+
Returns:
253+
Whether the specified component is a CHP meter.
254+
"""
255+
256+
@abstractmethod
257+
def is_chp_chain(self, component: Component) -> bool:
258+
"""Check if the specified component is part of a CHP chain.
259+
260+
A component is part of a CHP chain if it is a CHP meter or a CHP.
261+
262+
Args:
263+
component: component to check.
264+
265+
Returns:
266+
Whether the specified component is part of a CHP chain.
267+
"""
268+
116269

117270
class _MicrogridComponentGraph(ComponentGraph):
118271
"""ComponentGraph implementation designed to work with the microgrid API.
@@ -352,6 +505,190 @@ def validate(self) -> None:
352505
self._validate_junctions()
353506
self._validate_leaf_components()
354507

508+
def is_pv_inverter(self, component: Component) -> bool:
509+
"""Check if the specified component is a PV inverter.
510+
511+
Args:
512+
component: component to check.
513+
514+
Returns:
515+
Whether the specified component is a PV inverter.
516+
"""
517+
return (
518+
component.category == ComponentCategory.INVERTER
519+
and component.type == InverterType.SOLAR
520+
)
521+
522+
def is_pv_meter(self, component: Component) -> bool:
523+
"""Check if the specified component is a PV meter.
524+
525+
This is done by checking if the component has only PV inverters as its
526+
successors.
527+
528+
Args:
529+
component: component to check.
530+
531+
Returns:
532+
Whether the specified component is a PV meter.
533+
"""
534+
successors = self.successors(component.component_id)
535+
return (
536+
component.category == ComponentCategory.METER
537+
and len(successors) > 0
538+
and all(
539+
self.is_pv_inverter(successor)
540+
for successor in self.successors(component.component_id)
541+
)
542+
)
543+
544+
def is_pv_chain(self, component: Component) -> bool:
545+
"""Check if the specified component is part of a PV chain.
546+
547+
A component is part of a PV chain if it is either a PV inverter or a PV
548+
meter.
549+
550+
Args:
551+
component: component to check.
552+
553+
Returns:
554+
Whether the specified component is part of a PV chain.
555+
"""
556+
return self.is_pv_inverter(component) or self.is_pv_meter(component)
557+
558+
def is_ev_charger(self, component: Component) -> bool:
559+
"""Check if the specified component is an EV charger.
560+
561+
Args:
562+
component: component to check.
563+
564+
Returns:
565+
Whether the specified component is an EV charger.
566+
"""
567+
return component.category == ComponentCategory.EV_CHARGER
568+
569+
def is_ev_charger_meter(self, component: Component) -> bool:
570+
"""Check if the specified component is an EV charger meter.
571+
572+
This is done by checking if the component has only EV chargers as its
573+
successors.
574+
575+
Args:
576+
component: component to check.
577+
578+
Returns:
579+
Whether the specified component is an EV charger meter.
580+
"""
581+
successors = self.successors(component.component_id)
582+
return (
583+
component.category == ComponentCategory.METER
584+
and len(successors) > 0
585+
and all(self.is_ev_charger(successor) for successor in successors)
586+
)
587+
588+
def is_ev_charger_chain(self, component: Component) -> bool:
589+
"""Check if the specified component is part of an EV charger chain.
590+
591+
A component is part of an EV charger chain if it is either an EV charger or an
592+
EV charger meter.
593+
594+
Args:
595+
component: component to check.
596+
597+
Returns:
598+
Whether the specified component is part of an EV charger chain.
599+
"""
600+
return self.is_ev_charger(component) or self.is_ev_charger_meter(component)
601+
602+
def is_battery_inverter(self, component: Component) -> bool:
603+
"""Check if the specified component is a battery inverter.
604+
605+
Args:
606+
component: component to check.
607+
608+
Returns:
609+
Whether the specified component is a battery inverter.
610+
"""
611+
return (
612+
component.category == ComponentCategory.INVERTER
613+
and component.type == InverterType.BATTERY
614+
)
615+
616+
def is_battery_meter(self, component: Component) -> bool:
617+
"""Check if the specified component is a battery meter.
618+
619+
This is done by checking if the component has only battery inverters as
620+
its successors.
621+
622+
Args:
623+
component: component to check.
624+
625+
Returns:
626+
Whether the specified component is a battery meter.
627+
"""
628+
successors = self.successors(component.component_id)
629+
return (
630+
component.category == ComponentCategory.METER
631+
and len(successors) > 0
632+
and all(self.is_battery_inverter(successor) for successor in successors)
633+
)
634+
635+
def is_battery_chain(self, component: Component) -> bool:
636+
"""Check if the specified component is part of a battery chain.
637+
638+
A component is part of a battery chain if it is either a battery inverter or a
639+
battery meter.
640+
641+
Args:
642+
component: component to check.
643+
644+
Returns:
645+
Whether the specified component is part of a battery chain.
646+
"""
647+
return self.is_battery_inverter(component) or self.is_battery_meter(component)
648+
649+
def is_chp(self, component: Component) -> bool:
650+
"""Check if the specified component is a CHP.
651+
652+
Args:
653+
component: component to check.
654+
655+
Returns:
656+
Whether the specified component is a CHP.
657+
"""
658+
return component.category == ComponentCategory.CHP
659+
660+
def is_chp_meter(self, component: Component) -> bool:
661+
"""Check if the specified component is a CHP meter.
662+
663+
This is done by checking if the component has only CHPs as its
664+
successors.
665+
666+
Args:
667+
component: component to check.
668+
669+
Returns:
670+
Whether the specified component is a CHP meter.
671+
"""
672+
successors = self.successors(component.component_id)
673+
return (
674+
component.category == ComponentCategory.METER
675+
and len(successors) > 0
676+
and all(self.is_chp(successor) for successor in successors)
677+
)
678+
679+
def is_chp_chain(self, component: Component) -> bool:
680+
"""Check if the specified component is part of a CHP chain.
681+
682+
A component is part of a CHP chain if it is either a CHP or a CHP meter.
683+
684+
Args:
685+
component: component to check.
686+
687+
Returns:
688+
Whether the specified component is part of a CHP chain.
689+
"""
690+
return self.is_chp(component) or self.is_chp_meter(component)
691+
355692
def _validate_graph(self) -> None:
356693
"""Check that the underlying graph data is valid.
357694

src/frequenz/sdk/microgrid/component/_component.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ class ComponentCategory(Enum):
6464
BATTERY = microgrid_pb.ComponentCategory.COMPONENT_CATEGORY_BATTERY
6565
EV_CHARGER = microgrid_pb.ComponentCategory.COMPONENT_CATEGORY_EV_CHARGER
6666
LOAD = microgrid_pb.ComponentCategory.COMPONENT_CATEGORY_LOAD
67+
CHP = microgrid_pb.ComponentCategory.COMPONENT_CATEGORY_CHP
6768

6869
# types not yet supported by the API but which can be inferred
6970
# from available graph info
7071
PV_ARRAY = 1000001
71-
CHP = 1000002 # combined heat and power plant
7272

7373

7474
def _component_category_from_protobuf(

0 commit comments

Comments
 (0)