Skip to content

Commit c67a80e

Browse files
authored
Documentation for the FormulaEngine (#731)
2 parents 0fb0e58 + e71612e commit c67a80e

31 files changed

+179
-45
lines changed

docs/user-guide/formula-engine.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Formula Engine
2+
3+
::: frequenz.sdk.timeseries.formula_engine.FormulaEngine
4+
options:
5+
members: None
6+
show_bases: false
7+
show_root_full_path: false
8+
show_source: false
9+
10+
::: frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase
11+
options:
12+
members: None
13+
show_bases: false
14+
show_root_full_path: false
15+
show_source: false

docs/user-guide/glossary.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,20 @@ of type `int`.
158158

159159
For example, a battery with a component ID of **5**.
160160

161+
### Component Graph
162+
163+
A [graph](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))
164+
representation of the configuration in which the electrical components in a
165+
microgrid are connected with each other. Some of the ways in which the SDK uses
166+
the component graph are:
167+
168+
- figure out how to calculate high level metrics like
169+
[`grid_power`][frequenz.sdk.timeseries.logical_meter.LogicalMeter.grid_power],
170+
[`consumer_power`][frequenz.sdk.timeseries.logical_meter.LogicalMeter.consumer_power],
171+
etc. for a microgrid, using the available components.
172+
- identify the available {{glossary("battery", "batteries")}} or
173+
{{glossary("EV charger", "EV chargers")}} at a site that can be controlled.
174+
161175
### Island
162176

163177
A [microgrid](#microgrid) that is not connected to the public electricity

src/frequenz/sdk/timeseries/_formula_engine/__init__.py

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/frequenz/sdk/timeseries/battery_pool/_battery_pool.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
from ..._internal._channels import ReceiverFetcher
1818
from ...actor import _power_managing
1919
from ...timeseries import Energy, Percentage, Power, Sample, Temperature
20-
from .._formula_engine import FormulaEngine
21-
from .._formula_engine._formula_generators import (
20+
from ..formula_engine import FormulaEngine
21+
from ..formula_engine._formula_generators import (
2222
BatteryPowerFormula,
2323
FormulaGeneratorConfig,
2424
FormulaType,

src/frequenz/sdk/timeseries/battery_pool/_battery_pool_reference_store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from ...actor.power_distributing._battery_pool_status import BatteryStatus
1818
from ...microgrid import connection_manager
1919
from ...microgrid.component import ComponentCategory
20-
from .._formula_engine import FormulaEnginePool
20+
from ..formula_engine._formula_engine_pool import FormulaEnginePool
2121
from ._methods import MetricAggregator
2222

2323

src/frequenz/sdk/timeseries/ev_charger_pool/_ev_charger_pool.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@
1919
from ...microgrid import connection_manager
2020
from ...microgrid.component import ComponentCategory, ComponentMetricId
2121
from .. import Sample, Sample3Phase
22-
from .._formula_engine import FormulaEngine, FormulaEngine3Phase, FormulaEnginePool
23-
from .._formula_engine._formula_generators import (
22+
from .._quantities import Current, Power, Quantity
23+
from ..formula_engine import FormulaEngine, FormulaEngine3Phase
24+
from ..formula_engine._formula_engine_pool import FormulaEnginePool
25+
from ..formula_engine._formula_generators import (
2426
EVChargerCurrentFormula,
2527
EVChargerPowerFormula,
2628
FormulaGeneratorConfig,
2729
FormulaType,
2830
)
29-
from .._quantities import Current, Power, Quantity
3031
from ._set_current_bounds import BoundsSetter, ComponentCurrentLimit
3132
from ._state_tracker import EVChargerState, StateTracker
3233

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# License: MIT
2+
# Copyright © 2023 Frequenz Energy-as-a-Service GmbH
3+
4+
"""The formula engine module.
5+
6+
This module exposes the
7+
[FormulaEngine][frequenz.sdk.timeseries.formula_engine.FormulaEngine] and
8+
[FormulaEngine3Phase][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase]
9+
classes.
10+
"""
11+
12+
from ._formula_engine import FormulaEngine, FormulaEngine3Phase
13+
14+
__all__ = [
15+
"FormulaEngine",
16+
"FormulaEngine3Phase",
17+
]

src/frequenz/sdk/timeseries/_formula_engine/_exceptions.py renamed to src/frequenz/sdk/timeseries/formula_engine/_exceptions.py

File renamed without changes.

src/frequenz/sdk/timeseries/_formula_engine/_formula_engine.py renamed to src/frequenz/sdk/timeseries/formula_engine/_formula_engine.py

Lines changed: 106 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,68 @@ class FormulaEngine(
203203
QuantityT,
204204
],
205205
):
206-
"""
207-
The FormulaEngine evaluates formulas and streams the results.
206+
"""[`FormulaEngine`][frequenz.sdk.timeseries.formula_engine.FormulaEngine]s are a
207+
part of the SDK's data pipeline, and provide a way for the SDK to apply formulas on
208+
resampled data streams.
208209
209-
Use the `FormulaBuilder` to create `FormulaEngine` instances.
210-
"""
210+
They are used in the SDK to calculate and stream metrics like
211+
[`grid_power`][frequenz.sdk.timeseries.logical_meter.LogicalMeter.grid_power],
212+
[`consumer_power`][frequenz.sdk.timeseries.logical_meter.LogicalMeter.consumer_power],
213+
etc., which are building blocks of the
214+
[Frequenz SDK Microgrid Model][frequenz.sdk.microgrid--frequenz-sdk-microgrid-model].
215+
216+
The SDK creates the formulas by analysing the configuration of components in the
217+
{{glossary("Component Graph")}}.
218+
219+
### Streaming Interface
220+
221+
The
222+
[`FormulaEngine.new_receiver()`][frequenz.sdk.timeseries.formula_engine.FormulaEngine.new_receiver]
223+
method can be used to create a
224+
[Receiver](https://frequenz-floss.github.io/frequenz-channels-python/latest/reference/frequenz/channels/#frequenz.channels.Receiver)
225+
that streams the [Sample][frequenz.sdk.timeseries.Sample]s calculated by the formula
226+
engine.
227+
228+
```python
229+
from frequenz.sdk import microgrid
230+
231+
battery_pool = microgrid.battery_pool()
232+
233+
async for power in battery_pool.power.new_receiver():
234+
print(f"{power=}")
235+
```
236+
237+
### Composition
238+
239+
Composite `FormulaEngine`s can be built using arithmetic operations on
240+
`FormulaEngine`s streaming the same type of data.
241+
242+
For example, if you're interested in a particular composite metric that can be
243+
calculated by subtracting
244+
[`battery_pool().power`][frequenz.sdk.timeseries.battery_pool.BatteryPool.power] and
245+
[`ev_charger_pool().power`][frequenz.sdk.timeseries.ev_charger_pool.EVChargerPool]
246+
from the
247+
[`logical_meter().grid_power`][frequenz.sdk.timeseries.logical_meter.LogicalMeter.grid_power],
248+
we can build a `FormulaEngine` that provides a stream of this calculated metric as
249+
follows:
250+
251+
```python
252+
from frequenz.sdk import microgrid
253+
254+
logical_meter = microgrid.logical_meter()
255+
battery_pool = microgrid.battery_pool()
256+
ev_charger_pool = microgrid.ev_charger_pool()
257+
258+
# apply operations on formula engines to create a formula engine that would
259+
# apply these operations on the corresponding data streams.
260+
net_power = (
261+
logical_meter.grid_power - (battery_pool.power + ev_charger_pool.power)
262+
).build("net_power")
263+
264+
async for power in net_power.new_receiver():
265+
print(f"{power=}")
266+
```
267+
""" # noqa: D400, D205
211268

212269
def __init__(
213270
self,
@@ -356,11 +413,52 @@ class FormulaEngine3Phase(
356413
QuantityT,
357414
]
358415
):
359-
"""
360-
The FormulaEngine evaluates formulas and streams the results.
416+
"""A
417+
[`FormulaEngine3Phase`][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase]
418+
is similar to a
419+
[`FormulaEngine`][frequenz.sdk.timeseries.formula_engine.FormulaEngine], except that
420+
they stream [3-phase samples][frequenz.sdk.timeseries.Sample3Phase]. All the
421+
current formulas (like
422+
[`LogicalMeter.grid_current`][frequenz.sdk.timeseries.logical_meter.LogicalMeter.grid_current],
423+
[`EVChargerPool.current`][frequenz.sdk.timeseries.ev_charger_pool.EVChargerPool.current],
424+
etc.) are implemented as 3-phase formulas.
361425
362-
Use the `FormulaBuilder` to create `FormulaEngine` instances.
363-
"""
426+
### Streaming Interface
427+
428+
The
429+
[`FormulaEngine3Phase.new_receiver()`][frequenz.sdk.timeseries.formula_engine.FormulaEngine3Phase.new_receiver]
430+
method can be used to create a
431+
[Receiver](https://frequenz-floss.github.io/frequenz-channels-python/latest/reference/frequenz/channels/#frequenz.channels.Receiver)
432+
that streams the [Sample3Phase][frequenz.sdk.timeseries.Sample3Phase] values
433+
calculated by the formula engine.
434+
435+
```python
436+
from frequenz.sdk import microgrid
437+
438+
ev_charger_pool = microgrid.ev_charger_pool()
439+
440+
async for sample in ev_charger_pool.current.new_receiver():
441+
print(f"Current: {sample}")
442+
```
443+
444+
### Composition
445+
446+
`FormulaEngine3Phase` instances can be composed together, just like `FormulaEngine`
447+
instances.
448+
449+
```python
450+
from frequenz.sdk import microgrid
451+
452+
logical_meter = microgrid.logical_meter()
453+
ev_charger_pool = microgrid.ev_charger_pool()
454+
455+
# Calculate grid consumption current that's not used by the EV chargers
456+
other_current = (logical_meter.grid_current - ev_charger_pool.current).build("other_current")
457+
458+
async for sample in other_current.new_receiver():
459+
print(f"Other current: {sample}")
460+
```
461+
""" # noqa: D205, D400
364462

365463
def __init__(
366464
self,

src/frequenz/sdk/timeseries/_formula_engine/_formula_engine_pool.py renamed to src/frequenz/sdk/timeseries/formula_engine/_formula_engine_pool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
if TYPE_CHECKING:
2222
# Break circular import by enclosing these type hints in a `TYPE_CHECKING` block.
23-
from .._formula_engine import FormulaEngine, FormulaEngine3Phase
23+
from ..formula_engine import FormulaEngine, FormulaEngine3Phase
2424

2525

2626
class FormulaEnginePool:

0 commit comments

Comments
 (0)