Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/merge time series schemas #1127

Merged
merged 52 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
902d95f
refactor: sync arg name
Flix6x Jul 18, 2024
6e868d8
refactor: sync internal property name
Flix6x Jul 18, 2024
d8b2499
refactor: flatten elif block
Flix6x Jul 18, 2024
77de0df
refactor: allow string deserialization and allow setting a default so…
Flix6x Jul 18, 2024
8c9fe3f
refactor: copy convert method
Flix6x Jul 20, 2024
ef0d5e8
fix: type annotation
Flix6x Jul 20, 2024
a9364b1
refactor: copy _serialize method
Flix6x Jul 20, 2024
b3070f7
refactor: adapt _serialize method
Flix6x Jul 20, 2024
1339b1a
refactor: adapt docstring
Flix6x Jul 20, 2024
5107026
refactor: update error message
Flix6x Jul 20, 2024
9084e53
refactor: update type annotation
Flix6x Jul 20, 2024
bb157cf
refactor: merge schemas
Flix6x Jul 20, 2024
ba8e1cc
refactor: reduce number of blank lines
Flix6x Jul 20, 2024
392a118
fix: deprecate old classes
Flix6x Jul 20, 2024
258520e
fix: duplicate import
Flix6x Jul 20, 2024
1475776
docs: document status quo
Flix6x Jul 20, 2024
5cecd86
style: black
Flix6x Jul 20, 2024
dbb91a8
style: flake8
Flix6x Jul 20, 2024
9478c5a
feature: allow interpreting float values as quantities based on a uni…
Flix6x Jul 23, 2024
ba26a2e
fix: maintain backwards compatibility for transforming Float fields i…
Flix6x Jul 23, 2024
ead17b8
docs: grammar
Flix6x Jul 24, 2024
c847870
docs: add todo
Flix6x Jul 24, 2024
137f6ae
fix: tests
Flix6x Jul 24, 2024
00bf425
style: black
Flix6x Jul 24, 2024
cc68ccf
docs: update V2G flex-model
Flix6x Jul 24, 2024
b29dad2
docs: update trigger endpoint examples
Flix6x Jul 24, 2024
ee10c19
docs: update other tutorials
Flix6x Jul 24, 2024
fe4d755
docs: update scheduling feature section
Flix6x Jul 24, 2024
35ab5d0
feat: convert schedule results ffrom MW to sensor unit
victorgarcia98 Jul 30, 2024
2202077
feat: minimum list length for soc-gain and soc-usage
Flix6x Aug 6, 2024
71ca8c4
refactor: apply default SoC unit to all fields starting with "soc_"
Flix6x Aug 6, 2024
8cfe9fd
refactor: move warning
Flix6x Aug 6, 2024
ed56897
Revert "refactor: move warning"
Flix6x Aug 6, 2024
df96eb9
fix: update test
Flix6x Aug 6, 2024
88f2597
refactor: move deserialization logic to dedicated class methods
Flix6x Aug 6, 2024
0acca6d
docs: fix comment about converting time series using to_unit
Flix6x Aug 6, 2024
ab30487
refactor: rename new schema
Flix6x Aug 6, 2024
8d17a92
refactor: sync code order: 1) Sensor, 2) time series, 3) Quantity
Flix6x Aug 6, 2024
7cca59e
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Aug 6, 2024
8ef8d2b
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Aug 7, 2024
161f314
fix: add test and add missing logic for handling a list of dictionari…
Flix6x Aug 8, 2024
03bac84
fix: check for real numeric values
Flix6x Aug 9, 2024
1b7fa03
Merge remote-tracking branch 'refs/remotes/origin/main' into feature/…
Flix6x Aug 9, 2024
1ffc335
docs: changelog entries
Flix6x Aug 9, 2024
8ccc6f6
docs: fix typo
Flix6x Aug 9, 2024
1a430c0
style: be more explicit about requiring the soc-unit field to be set
Flix6x Aug 9, 2024
b743aa2
Merge branch 'refs/heads/main' into feature/merge-time-series-schemas
Flix6x Aug 13, 2024
8ec14c5
docs: mention the new Marshmallow field
Flix6x Aug 16, 2024
8fd4ec1
docs: advise setting a unit per field explicitly
Flix6x Aug 16, 2024
15e19dc
refactor: simplify if statement
Flix6x Aug 16, 2024
8c233ca
refactor: move soc-unit guesswork into schema
Flix6x Aug 16, 2024
ba20453
Merge branch 'main' into feature/merge-time-series-schemas
Flix6x Aug 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions documentation/api/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,33 @@ v3.0-19 | 2024-08-13

- Allow posting a single instantaneous belief as a list of one element to `/sensors/data` (POST).

v3.0-19 | 2024-08-09
""""""""""""""""""""

- Allow setting a SoC unit directly in some fields (formerly ``Float`` fields, and now ``Quantity`` fields), while still falling back on the contents of the ``soc-unit`` field, for backwards compatibility:

- ``soc-at-start``
- ``soc-min``
- ``soc-max``

- Allow setting a unit directly in fields that already supported passing a time series:

- ``soc-maxima``
- ``soc-minima``
- ``soc-targets``

- Allow passing a time series in fields that formerly only accepted passing a fixed quantity or a sensor reference:

- ``power-capacity``
- ``consumption-capacity``
- ``production-capacity``
- ``charging-efficiency``
- ``discharging-efficiency``
- ``storage-efficiency``
- ``soc-gain``
- ``soc-usage``


v3.0-18 | 2024-03-07
""""""""""""""""""""

Expand Down
4 changes: 2 additions & 2 deletions documentation/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ New features
* Add basic sensor info to sensor page [see `PR #1115 <https://github.com/FlexMeasures/flexmeasures/pull/1115>`_]
* Support zoom-in action on the asset and sensor charts [see `PR #1130 <https://github.com/FlexMeasures/flexmeasures/pull/1130>`_]
* Added Primary and Secondary colors to account for white-labelled UI themes [see `PR #1137 <https://github.com/FlexMeasures/flexmeasures/pull/1137>`_]
* Introduce the ``VariableQuantityField`` to allow three ways of passing a variable quantity in most of the ``flex-model`` and ``flex-context`` fields [see `PR #1127 <https://github.com/FlexMeasures/flexmeasures/pull/1127>`_]

Infrastructure / Support
----------------------
* Support new single-belief fast track (looking uup only one belief) [see `PR #1067 <https://github.com/FlexMeasures/flexmeasures/pull/1067>`_]
* Support new single-belief fast track (looking up only one belief) [see `PR #1067 <https://github.com/FlexMeasures/flexmeasures/pull/1067>`_]
* Add new annotation types: ``"error"`` and ``"warning"`` [see `PR #1131 <https://github.com/FlexMeasures/flexmeasures/pull/1131>`_]
* Removed deprecated ``app.schedulers`` and ``app.forecasters`` (use ``app.data_generators["scheduler"]`` and ``app.data_generators["forecaster"]`` instead) [see `PR #1098 <https://github.com/FlexMeasures/flexmeasures/pull/1098/>`_]

Expand Down
15 changes: 8 additions & 7 deletions documentation/features/scheduling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,25 +108,26 @@ and what constraints or preferences should be taken into account.
- Example value
- Description
* - ``soc-at-start``
- ``"3.1"``
- ``"3.1 kWh"``
- The (estimated) state of charge at the beginning of the schedule (defaults to 0).
* - ``soc-unit``
- ``"kWh"`` or ``"MWh"``
- The unit in which all SoC related flex-model values are to be interpreted.
- The unit used to interpret any SoC related flex-model value that does not mention a unit itself (only applies to numeric values, so not to string values).
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
However, we advise to mention the unit in each field explicitly (for instance, ``"3.1 kWh"`` rather than ``3.1``).
* - ``soc-min``
- ``"2.5"``
- ``"2.5 kWh"``
- A constant lower boundary for all values in the schedule (defaults to 0).
* - ``soc-max``
- ``"7"``
- ``"7 kWh"``
- A constant upper boundary for all values in the schedule (defaults to max soc target, if provided)
* - ``soc-minima``
- ``[{"datetime": "2024-02-05T08:00:00+01:00", value: 8.2}]``
- ``[{"datetime": "2024-02-05T08:00:00+01:00", value: "8.2 kWh"}]``
- Set point(s) that form lower boundaries, e.g. to target a full car battery in the morning. Can be single values or a range (defaults to NaN values).
* - ``soc-maxima``
- ``{"value": 51, "start": "2024-02-05T12:00:00+01:00","end": "2024-02-05T13:30:00+01:00"}``
- ``{"value": "51 kWh", "start": "2024-02-05T12:00:00+01:00", "end": "2024-02-05T13:30:00+01:00"}``
- Set point(s) that form upper boundaries at certain times. Can be single values or a range (defaults to NaN values).
* - ``soc-targets``
- ``[{"datetime": "2024-02-05T08:00:00+01:00", value: 3.2}]``
- ``[{"datetime": "2024-02-05T08:00:00+01:00", value: "3.2 kWh"}]``
- Exact set point(s) that the scheduler needs to realize (defaults to NaN values).
* - ``soc-gain``
- ``.1kWh``
Expand Down
42 changes: 31 additions & 11 deletions documentation/tut/flex-model-v2g.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ Constraining the cycling to occur within a static 25-85% SoC range can be modell

{
"flex-model": {
"soc-min": 15,
"soc-max": 51,
"soc-unit": "kWh"
"soc-min": "15 kWh",
"soc-max": "51 kWh"
}
}

Expand All @@ -50,16 +49,15 @@ To enable a temporary target SoC of more than 85% (for car reservations, see the

{
"flex-model": {
"soc-min": 15,
"soc-max": 60,
"soc-min": "15 kWh",
"soc-max": "60 kWh",
"soc-maxima": [
{
"value": 51,
"value": "51 kWh",
"start": "2024-02-04T10:35:00+01:00",
"end": "2024-02-05T04:25:00+01:00"
}
],
"soc-unit": "kWh"
]
}
}

Expand All @@ -80,30 +78,52 @@ Given a reservation for 8 AM on February 5th, constraint 2 can be modelled throu
"flex-model": {
"soc-minima": [
{
"value": 57,
"value": "57 kWh",
"datetime": "2024-02-05T08:00:00+01:00"
}
]
}
}

This constraint also signals that if the car is not plugged out of the Charge Point at 8 AM, the scheduler is in principle allowed to start discharging immediately afterwards.
To make sure the car remains at 95% SoC for some time, additional soc-minima constraints should be set accordingly, taking into account the scheduling resolution (here, 5 minutes). For example, to keep it charged (nearly) fully until 8.15 AM:
To make sure the car remains at or above 95% SoC for some time, additional soc-minima constraints should be set accordingly, taking into account the scheduling resolution (here, 5 minutes). For example, to keep it charged (nearly) fully until 8.15 AM:

.. code-block:: json

{
"flex-model": {
"soc-minima": [
{
"value": 57,
"value": "57 kWh",
"start": "2024-02-05T08:00:00+01:00",
"end": "2024-02-05T08:15:00+01:00"
}
]
}
}

The car may still charge and discharge within those 15 minutes, but it won't go below 95%.
Alternatively, to keep the car from discharging altogether during that time, limit the ``production-capacity`` (likewise, use the ``consumption-capacity`` to prevent any charging):

.. code-block:: json

{
"flex-model": {
"soc-minima": [
{
"value": "57 kWh",
"datetime": "2024-02-05T08:00:00+01:00"
}
],
"production-capacity": [
{
"value": "0 kW",
"start": "2024-02-05T08:00:00+01:00",
"end": "2024-02-05T08:15:00+01:00"
}
]
}
}

.. _earning_by_cycling:

Expand Down
7 changes: 3 additions & 4 deletions documentation/tut/forecasting_scheduling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,17 @@ Here, we extend that (storage) example with an additional target value, represen
{
"start": "2015-06-02T10:00:00+00:00",
"flex-model": {
"soc-at-start": 12.1,
"soc-unit": "kWh"
"soc-at-start": "12.1 kWh",
"soc-targets": [
{
"value": 25,
"value": "25 kWh",
"datetime": "2015-06-02T16:00:00+00:00"
}
}
}


We now have described the state of charge at 10am to be ``12.1``. In addition, we requested that it should be ``25`` at 4pm.
We now have described the state of charge at 10am to be ``"12.1 kWh"``. In addition, we requested that it should be ``"25 kWh"`` at 4pm.
For instance, this could mean that a car should be charged at 90% at that time.

If FlexMeasures receives this message, a scheduling job will be made and put into the queue. In turn, the scheduling job creates a proposed schedule. We'll look a bit deeper into those further down in :ref:`getting_schedules`.
Expand Down
3 changes: 1 addition & 2 deletions documentation/tut/posting_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,7 @@ The endpoint also allows to limit the flexibility range and also to set target v
{
"start": "2015-06-02T10:00:00+00:00",
"flex-model": {
"soc-at-start": 12.1,
"soc-unit": "kWh"
"soc-at-start": "12.1 kWh"
}
}

Expand Down
12 changes: 5 additions & 7 deletions flexmeasures/api/v3_0/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,7 @@ def trigger_schedule(
{
"start": "2015-06-02T10:00:00+00:00",
"flex-model": {
"soc-at-start": 12.1,
"soc-unit": "kWh"
"soc-at-start": "12.1 kWh"
}
}

Expand Down Expand Up @@ -311,17 +310,16 @@ def trigger_schedule(
"start": "2015-06-02T10:00:00+00:00",
"duration": "PT24H",
"flex-model": {
"soc-at-start": 12.1,
"soc-unit": "kWh",
"soc-at-start": "12.1 kWh",
"soc-targets": [
{
"value": 25,
"value": "25 kWh",
"datetime": "2015-06-02T16:00:00+00:00"
},
],
"soc-minima": {"sensor" : 300},
"soc-min": 10,
"soc-max": 25,
"soc-min": "10 kWh",
"soc-max": "25 kWh",
"charging-efficiency": "120%",
"discharging-efficiency": {"sensor": 98},
"storage-efficiency": 0.9999,
Expand Down
2 changes: 1 addition & 1 deletion flexmeasures/api/v3_0/tests/test_sensor_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_get_schedule_wrong_job_id(
message_for_trigger_schedule(),
"soc-min",
"not-a-float",
"Not a valid number",
"Not a valid quantity",
),
(message_for_trigger_schedule(), "soc-unit", "MWH", "Must be one of"),
# todo: add back test in case we stop grandfathering ignoring too-far-into-the-future targets, or amend otherwise
Expand Down
30 changes: 15 additions & 15 deletions flexmeasures/cli/data_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
LongitudeField,
SensorIdField,
TimeIntervalField,
QuantityOrSensor,
VariableQuantityField,
)
from flexmeasures.data.schemas.sources import DataSourceIdField
from flexmeasures.data.schemas.times import TimeIntervalSchema
Expand Down Expand Up @@ -1171,7 +1171,7 @@ def create_schedule(ctx):
@click.option(
"--site-power-capacity",
"site_power_capacity",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
required=False,
default=None,
help="Site consumption/production power capacity. Provide this as a quantity in power units (e.g. 1 MW or 1000 kW)"
Expand All @@ -1181,7 +1181,7 @@ def create_schedule(ctx):
@click.option(
"--site-consumption-capacity",
"site_consumption_capacity",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
required=False,
default=None,
help="Site consumption power capacity. Provide this as a quantity in power units (e.g. 1 MW or 1000 kW)"
Expand All @@ -1191,7 +1191,7 @@ def create_schedule(ctx):
@click.option(
"--site-production-capacity",
"site_production_capacity",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
required=False,
default=None,
help="Site production power capacity. Provide this as a quantity in power units (e.g. 1 MW or 1000 kW)"
Expand Down Expand Up @@ -1256,7 +1256,7 @@ def create_schedule(ctx):
@click.option(
"--charging-efficiency",
"charging_efficiency",
type=QuantityOrSensor("%"),
type=VariableQuantityField("%"),
required=False,
default=None,
help="Storage charging efficiency to use for the schedule."
Expand All @@ -1266,7 +1266,7 @@ def create_schedule(ctx):
@click.option(
"--discharging-efficiency",
"discharging_efficiency",
type=QuantityOrSensor("%"),
type=VariableQuantityField("%"),
required=False,
default=None,
help="Storage discharging efficiency to use for the schedule."
Expand All @@ -1276,7 +1276,7 @@ def create_schedule(ctx):
@click.option(
"--soc-gain",
"soc_gain",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
Flix6x marked this conversation as resolved.
Show resolved Hide resolved
required=False,
default=None,
help="Specify the State of Charge (SoC) gain as a quantity in power units (e.g. 1 MW or 1000 kW)"
Expand All @@ -1286,7 +1286,7 @@ def create_schedule(ctx):
@click.option(
"--soc-usage",
"soc_usage",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
required=False,
default=None,
help="Specify the State of Charge (SoC) usage as a quantity in power units (e.g. 1 MW or 1000 kW) "
Expand All @@ -1296,7 +1296,7 @@ def create_schedule(ctx):
@click.option(
"--storage-power-capacity",
"storage_power_capacity",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
required=False,
default=None,
help="Storage consumption/production power capacity. Provide this as a quantity in power units (e.g. 1 MW or 1000 kW)"
Expand All @@ -1306,7 +1306,7 @@ def create_schedule(ctx):
@click.option(
"--storage-consumption-capacity",
"storage_consumption_capacity",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
required=False,
default=None,
help="Storage consumption power capacity. Provide this as a quantity in power units (e.g. 1 MW or 1000 kW)"
Expand All @@ -1316,7 +1316,7 @@ def create_schedule(ctx):
@click.option(
"--storage-production-capacity",
"storage_production_capacity",
type=QuantityOrSensor("MW"),
type=VariableQuantityField("MW"),
required=False,
default=None,
help="Storage production power capacity. Provide this as a quantity in power units (e.g. 1 MW or 1000 kW)"
Expand All @@ -1326,7 +1326,7 @@ def create_schedule(ctx):
@click.option(
"--storage-efficiency",
"storage_efficiency",
type=QuantityOrSensor("%", default_src_unit="dimensionless"),
type=VariableQuantityField("%", default_src_unit="dimensionless"),
required=False,
default="100%",
help="Storage efficiency (e.g. 95% or 0.95) to use for the schedule,"
Expand Down Expand Up @@ -1469,9 +1469,9 @@ def add_schedule_for_storage( # noqa C901
else:
unit = "MW"

scheduling_kwargs[key][field_name] = QuantityOrSensor(unit)._serialize(
value, None, None
)
scheduling_kwargs[key][field_name] = VariableQuantityField(
unit
)._serialize(value, None, None)

if as_job:
job = create_scheduling_job(asset_or_sensor=power_sensor, **scheduling_kwargs)
Expand Down
13 changes: 13 additions & 0 deletions flexmeasures/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,19 @@ def create_test_battery_assets(
)
db.session.add(test_battery_sensor)

test_battery_sensor_kw = Sensor(
name="power (kW)",
generic_asset=test_battery,
event_resolution=timedelta(minutes=15),
unit="kW",
attributes=dict(
daily_seasonality=True,
weekly_seasonality=True,
yearly_seasonality=True,
),
)
db.session.add(test_battery_sensor_kw)

test_battery_no_prices = GenericAsset(
name="Test battery with no known prices",
owner=setup_accounts["Prosumer"],
Expand Down
Loading
Loading