feat: support a default fallback on sensor references - #2405
Conversation
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
…scheduler Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com> # Conflicts: # documentation/changelog.rst # documentation/features/scheduling.rst # flexmeasures/api/v3_0/tests/test_sensors_api_freshdb.py # flexmeasures/data/schemas/scheduling/__init__.py # flexmeasures/data/schemas/tests/test_sensor.py # flexmeasures/ui/static/openapi-specs.json
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Both relax-soc-constraints and relax-constraints default to True, so the former's default swallowed an explicit opt-out through the umbrella flag. Now an explicit relax-soc-constraints wins and otherwise the umbrella relax-constraints decides, per the semantics discussed in PR #2267: setting either flag to False keeps SoC minima/maxima hard. Also document why DBFlexContextSchema turns the relaxation defaults off. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pt-out The capacity bounds (power-capacity and site-power-capacity) still remain hard constraints after relaxation; mention them again alongside soc-min, soc-max and soc-targets, and explain that setting either relax-soc-constraints or relax-constraints to false keeps SoC minima/maxima hard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Correct RELAX_CONSTRAINTS metadata text: it now defaults to True, not False. - Give DBFlexContextSchema's relax flags their own description, since a stored flex-context defaults to False, unlike the True scheduling-time default applied after merging with the request. - Align the hard-constraints list in scheduling.rst with introduction.rst (both now mention power-capacity / site-power-capacity). - Add the missing v3.0-32 API changelog entry for the relax-soc-constraints default flip and the retired fallback scheduler's effect on GET schedule. - Drop now-tautological assertions checking for "StorageFallbackScheduler" in belief sources, since that class no longer exists in the codebase. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # documentation/api/change_log.rst
Conflicts were in four files: - storage.py: keep the removal of StorageFallbackScheduler (main had since changed its return_multiple block to dedupe shared sensors). - test_sensor_schedules.py: keep both main's new test_get_schedule_unfinished_job_returns_202_when_sunset_active and this branch's renamed test_get_schedule_infeasible_storage_job_without_fallback; drop the two retired fallback tests. - test_scheduling_sequential.py: keep both this branch's no-fallback assertions and main's new test_create_sequential_jobs_with_sign_explicit_context. - api/change_log.rst: keep both sides' entries. Also clean up the deferred subjobs in the no-fallback sequential test. With the fallback retired nothing unblocks them, so they used to leak into the next test and break main's new sign-explicit-context test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A sensor reference on any flex-model or flex-context field may now carry a
`default` quantity, e.g. {"sensor": 50, "default": "0 kWh"}. It fills the
time slots for which the referenced sensor holds no value, and is settable
from the flex-model UI.
This is the uncontroversial half of #2267, split out on Felix's suggestion
so it can land while the SoC constraint hardness question is settled across
the whole flex-model (see #2395). The canonical soc-min/soc-max work stays
on feat/dynamic-soc-bounds-defaults.
Note that a default fills *every* slot the sensor leaves empty, so a sensor
recording only occasional setpoints becomes densely constrained; the field
documentation says so.
Also omit `default` from serialized sensor references when it is unset,
rather than emitting `default: None`, which is not valid input on the way
back in and broke the forecaster config round-trips.
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Documentation build overview
31 files changed ·
|
`default` is declared on the shared SensorReferenceSchema, so it is accepted on every sensor reference in the API — but it is only applied in get_series_from_quantity_or_sensor. Sensor references resolved by get_power_values (inflexible devices) and by the forecasting pipelines (regressors) ignore it, silently. Rather than claim more than the code does, say where the field takes effect. Applying it in those two paths is worth a follow-up. Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
|
Manual end-to-end check. I drove the real
So the fallback fills the slots the sensor leaves silent, and the solver honours it as a floor, paying the high price to hold it. Also verified that a reference without a Known gap — follow-up needed
This is visible in the generated spec: the @Flix6x I've scoped the changelog and the field description to say where the field actually takes effect, rather than implement the missing paths in this PR. Opening a follow-up issue to apply |
This branch was carved out of #2267, which was stacked on feat/retire-fallback-scheduler, so #2252's commits travelled along with it. Now that this PR targets main, drop that content here: the tree of this commit equals main plus the sensor-reference `default` work alone. No behaviour of this PR changes; #2252 lands on its own. Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
|
@Flix6x i rebased the pr to main |
Signed-off-by: Mohamed Belhsan Hmida <149331360+BelhsanHmida@users.noreply.github.com>
Since #2345, a consumption-capacity or production-capacity that is zero throughout the scheduling window is read as a physical statement about the device and enforced strictly. A default fills every slot the sensor leaves empty, so a fallback of 0 on one of those fields turns a silent sensor into a hard bound, which is not what "use this value when the sensor has nothing to say" sounds like it does. Regenerating the specs here also restores their version to 1.0.0. The generator takes it from the installed FlexMeasures, so the 0.33.2 in the previous revision records a stale environment rather than an intended change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: F.N. Claessen <claessen@seita.nl>
|
Reviewed and approved — thanks for splitting this out, it lands cleanly. I pushed one commit rather than leaving review notes, since both parts are small and mechanical. 1. Restored the specs version to 2. Documented one interaction with #2345, which landed after this branch was opened. Since #2345, a "production-capacity": {"sensor": 42, "default": "0 kW"}against a sensor that is silent for the whole window yields an all-zero capacity, which becomes a hard bound. That is a reasonable thing for someone to write meaning "assume no export capability when I have no data", and they would not expect it to become uncrossable. So the caveat is now in three places: the Nothing to change in your implementation — this is a documentation consequence of two features meeting, and the note belongs with For context on the wider question of why a directional capacity carries two meanings at all, and what would let us stop inferring physics from the value |
Description
Split out of #2267 on @Flix6x's suggestion, so the uncontroversial half can land while the SoC constraint hardness question is settled across the whole flex-model (see #2395).
defaultfills every empty slot, so a sensor recording only occasional setpoints becomes densely constrained.defaultfrom serialized sensor references when unset, instead of emittingdefault: null(which is not valid input on the way back in, and broke the forecaster config round-trips).Not included, and still parked on
feat/dynamic-soc-bounds-defaults(#2267) pending #2395: thesoc-min→soc_minimafolding, the scalar softening (_relax_scalar_soc_minimum/_relax_scalar_soc_maximum), thesoc-minima/soc-maximadeprecation labelling, and thesoc_min/soc_maxfield-type change.Look & Feel
The flex-model sensor picker gains an optional "Default fallback" input.
How to test
Also ran the full CI-equivalent suite (
--doctest-modules, same ignores as the workflow): 1923 passed, with only failures that reproduce identically onmain(test_closest_sensor[1]/[3], andtest_numerical_errors[cbc]where the CBC solver binary is absent locally).Manual check — a sensor reference with a fallback in a storage flex-model:
{ "flex-model": { "soc-at-start": "12 kWh", "soc-minima": {"sensor": 300, "default": "10 kWh"}, "power-capacity": "5 kW" } }Slots where sensor 300 has no value are filled with 10 kWh.
Related Items
production-capacity: 0means two different things, and the rule that separates them is unwritten #2395Sign-off