scheduling.rst 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. .. _scheduling:
  2. Scheduling
  3. ===========
  4. Scheduling is the main value-drive of FlexMeasures. We have two major types of schedulers built-in, for storage devices (usually batteries or hot water storage) and processes (usually in industry).
  5. FlexMeasures computes schedules for energy systems that consist of multiple devices that consume and/or produce electricity.
  6. We model a device as an asset with a power sensor, and compute schedules only for flexible devices, while taking into account inflexible devices.
  7. .. contents::
  8. :local:
  9. :depth: 2
  10. .. _describing_flexibility:
  11. Describing flexibility
  12. ----------------------
  13. To compute a schedule, FlexMeasures first needs to assess the flexibility state of the system.
  14. This is described by:
  15. - :ref:`The flex-context <flex_context>` ― information about the system as a whole, in order to assess the value of activating flexibility.
  16. - :ref:`Flex-models <flex_models_and_schedulers>` ― information about the state and possible actions of the flexible device. We will discuss these per scheduled device type.
  17. This information goes beyond the usual time series recorded by an asset's sensors. It can be sent to FlexMeasures through the API when triggering schedule computation.
  18. Also, this information can be persisted on the FlexMeasures data model (in the db), and is editable through the UI (actually, that is design work in progress, currently possible with the flex context).
  19. Let's dive into the details ― what can you tell FlexMeasures about your optimization problem?
  20. .. _flex_context:
  21. The flex-context
  22. -----------------
  23. The ``flex-context`` is independent of the type of flexible device that is optimized, or which scheduler is used.
  24. With the flexibility context, we aim to describe the system in which the flexible assets operate, such as its physical and contractual limitations.
  25. Fields can have fixed values, but some fields can also point to sensors, so they will always represent the dynamics of the asset's environment (as long as that sensor has current data).
  26. The full list of flex-context fields follows below.
  27. For more details on the possible formats for field values, see :ref:`variable_quantities`.
  28. Where should you set these fields?
  29. Within requests to the API or by editing the relevant asset in the UI.
  30. If they are not sent in via the API (the endpoint triggering schedule computation), the scheduler will look them up on the `flex-context` field of the asset.
  31. And if the asset belongs to a larger system (a hierarchy of assets), the scheduler will also search if parent assets have them set.
  32. .. list-table::
  33. :header-rows: 1
  34. :widths: 20 25 90
  35. * - Field
  36. - Example value
  37. - Description
  38. * - ``inflexible-device-sensors``
  39. - ``[3,4]``
  40. - Power sensors that are relevant, but not flexible, such as a sensor recording rooftop solar power connected behind the main meter, whose production falls under the same contract as the flexible device(s) being scheduled.
  41. Their power demand cannot be adjusted but still matters for finding the best schedule for other devices. Must be a list of integers.
  42. * - ``consumption-price``
  43. - ``{"sensor": 5}``
  44. or
  45. ``"0.29 EUR/kWh"``
  46. - The price of consuming energy. Can be (a sensor recording) market prices, but also CO₂ intensity - whatever fits your optimization problem. (This field replaced the ``consumption-price-sensor`` field. [#old_sensor_field]_)
  47. * - ``production-price``
  48. - ``{"sensor": 6}``
  49. or
  50. ``"0.12 EUR/kWh"``
  51. - The price of producing energy.
  52. Can be (a sensor recording) market prices, but also CO₂ intensity - whatever fits your optimization problem, as long as the unit matches the ``consumption-price`` unit. (This field replaced the ``production-price-sensor`` field. [#old_sensor_field]_)
  53. * - ``site-power-capacity``
  54. - ``"45kVA"``
  55. - Maximum achievable power at the grid connection point, in either direction [#asymmetric]_.
  56. Becomes a hard constraint in the optimization problem, which is especially suitable for physical limitations. [#minimum_capacity_overlap]_
  57. * - ``site-consumption-capacity``
  58. - ``"45kW"``
  59. - Maximum consumption power at the grid connection point.
  60. If ``site-power-capacity`` is defined, the minimum between the ``site-power-capacity`` and ``site-consumption-capacity`` will be used. [#consumption]_
  61. If a ``site-consumption-breach-price`` is defined, the ``site-consumption-capacity`` becomes a soft constraint in the optimization problem.
  62. Otherwise, it becomes a hard constraint. [#minimum_capacity_overlap]_
  63. * - ``site-consumption-breach-price``
  64. - ``"1000 EUR/kW"``
  65. - The price of breaching the ``site-consumption-capacity``, useful to treat ``site-consumption-capacity`` as a soft constraint but still make the scheduler attempt to respect it.
  66. Can be (a sensor recording) contractual penalties, but also a theoretical penalty just to allow the scheduler to breach the consumption capacity, while influencing how badly breaches should be avoided. [#penalty_field]_ [#breach_field]_
  67. * - ``site-production-capacity``
  68. - ``"0kW"``
  69. - Maximum production power at the grid connection point.
  70. If ``site-power-capacity`` is defined, the minimum between the ``site-power-capacity`` and ``site-production-capacity`` will be used. [#production]_
  71. If a ``site-production-breach-price`` is defined, the ``site-production-capacity`` becomes a soft constraint in the optimization problem.
  72. Otherwise, it becomes a hard constraint. [#minimum_capacity_overlap]_
  73. * - ``site-production-breach-price``
  74. - ``"1000 EUR/kW"``
  75. - The price of breaching the ``site-production-capacity``, useful to treat ``site-production-capacity`` as a soft constraint but still make the scheduler attempt to respect it.
  76. Can be (a sensor recording) contractual penalties, but also a theoretical penalty just to allow the scheduler to breach the production capacity, while influencing how badly breaches should be avoided. [#penalty_field]_ [#breach_field]_
  77. * - ``site-peak-consumption``
  78. - ``{"sensor": 7}``
  79. - Current peak consumption.
  80. Costs from peaks below it are considered sunk costs. Default to 0 kW.
  81. * - ``site-peak-consumption-price``
  82. - ``"260 EUR/MWh"``
  83. - Consumption peaks above the ``site-peak-consumption`` are penalized against this per-kW price. [#penalty_field]_
  84. * - ``site-peak-production``
  85. - ``{"sensor": 8}``
  86. - Current peak production.
  87. Costs from peaks below it are considered sunk costs. Default to 0 kW.
  88. * - ``site-peak-production-price``
  89. - ``"260 EUR/MWh"``
  90. - Production peaks above the ``site-peak-production`` are penalized against this per-kW price. [#penalty_field]_
  91. * - ``soc-minima-breach-price``
  92. - ``"120 EUR/kWh"``
  93. - Penalty for not meeting ``soc-minima`` defined in the flex-model. [#penalty_field]_ [#breach_field]_
  94. * - ``soc-maxima-breach-price``
  95. - ``"120 EUR/kWh"``
  96. - Penalty for not meeting ``soc-maxima`` defined in the flex-model. [#penalty_field]_ [#breach_field]_
  97. * - ``consumption-breach-price``
  98. - ``"10 EUR/kW"``
  99. - The price of breaching the ``consumption-capacity`` in the flex-model, useful to treat ``consumption-capacity`` as a soft constraint but still make the scheduler attempt to respect it. [#penalty_field]_ [#breach_field]_
  100. * - ``production-breach-price``
  101. - ``"10 EUR/kW"``
  102. - The price of breaching the ``production-capacity`` in the flex-model, useful to treat ``production-capacity`` as a soft constraint but still make the scheduler attempt to respect it. [#penalty_field]_ [#breach_field]_
  103. .. [#old_sensor_field] The old field only accepted an integer (sensor ID).
  104. .. [#asymmetric] ``site-consumption-capacity`` and ``site-production-capacity`` allow defining asymmetric contracted transport capacities for each direction (i.e. production and consumption).
  105. .. [#minimum_capacity_overlap] In case this capacity field defines partially overlapping time periods, the minimum value is selected. See :ref:`variable_quantities`.
  106. .. [#consumption] Example: with a connection capacity (``site-power-capacity``) of 1 MVA (apparent power) and a consumption capacity (``site-consumption-capacity``) of 800 kW (active power), the scheduler will make sure that the grid outflow doesn't exceed 800 kW.
  107. .. [#penalty_field] Prices must share the same currency. Negative prices are not allowed (penalties only).
  108. .. [#production] Example: with a connection capacity (``site-power-capacity``) of 1 MVA (apparent power) and a production capacity (``site-production-capacity``) of 400 kW (active power), the scheduler will make sure that the grid inflow doesn't exceed 400 kW.
  109. .. [#breach_field] Breach prices are applied both to (the height of) the highest breach in the planning window and to (the area of) each breach that occurs.
  110. That means both high breaches and long breaches are penalized.
  111. For example, a :abbr:`SoC (state of charge)` breach price of 120 EUR/kWh is applied as a breach price of 120 EUR/kWh on the height of the highest breach, and as a breach price of 120 EUR/kWh/h on the area (kWh*h) of each breach.
  112. For a 5-minute resolution sensor, this would amount to applying a SoC breach price of 10 EUR/kWh for breaches measured every 5 minutes (in addition to the 120 EUR/kWh applied to the highest breach only).
  113. .. note:: If no (symmetric, consumption and production) site capacity is defined (also not as defaults), the scheduler will not enforce any bound on the site power.
  114. The flexible device can still have its own power limit defined in its flex-model.
  115. .. _flex_models_and_schedulers:
  116. The flex-models & corresponding schedulers
  117. -------------------------------------------
  118. FlexMeasures comes with a storage scheduler and a process scheduler, which work with flex models for storages and loads, respectively.
  119. The storage scheduler is suitable for batteries and :abbr:`EV (electric vehicle)` chargers, and is automatically selected when scheduling an asset with one of the following asset types: ``"battery"``, ``"one-way_evse"`` and ``"two-way_evse"``.
  120. The process scheduler is suitable for shiftable, breakable and inflexible loads, and is automatically selected for asset types ``"process"`` and ``"load"``.
  121. We describe the respective flex models below.
  122. At the moment, they have to be sent through the API (the endpoint to trigger schedule computation, or using the FlexMeasures client) or through the CLI (the command to add schedules).
  123. We will soon work on the possibility to store (a subset of) these fields on the data model and edit them in the UI.
  124. Storage
  125. ^^^^^^^^
  126. For *storage* devices, the FlexMeasures scheduler deals with the state of charge (SoC) for an optimal outcome.
  127. You can do a lot with this ― examples for storage devices are:
  128. - batteries
  129. - :abbr:`EV (electric vehicle)` batteries connected to charge points
  130. - hot water storage ("heat batteries", where the SoC relates to the water temperature)
  131. - pumped hydro storage (SoC is the water level)
  132. - water basins (here, SoC is supposed to be low, as water is being pumped out)
  133. - buffers of energy-intensive chemicals that are needed in other industry processes
  134. The ``flex-model`` for storage devices describes to the scheduler what the flexible asset's state is,
  135. and what constraints or preferences should be taken into account.
  136. The full list of flex-model fields for the storage scheduler follows below.
  137. For more details on the possible formats for field values, see :ref:`variable_quantities`.
  138. .. list-table::
  139. :header-rows: 1
  140. :widths: 20 40 80
  141. * - Field
  142. - Example value
  143. - Description
  144. * - ``soc-at-start``
  145. - ``"3.1 kWh"``
  146. - The (estimated) state of charge at the beginning of the schedule (defaults to 0). [#quantity_field]_
  147. * - ``soc-unit``
  148. - ``"kWh"`` or ``"MWh"``
  149. - 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).
  150. However, we advise to mention the unit in each field explicitly (for instance, ``"3.1 kWh"`` rather than ``3.1``).
  151. Enumerated option only.
  152. * - ``soc-min``
  153. - ``"2.5 kWh"``
  154. - A constant lower boundary for all values in the schedule (defaults to 0). [#quantity_field]_
  155. * - ``soc-max``
  156. - ``"7 kWh"``
  157. - A constant upper boundary for all values in the schedule (defaults to max soc target, if provided). [#quantity_field]_
  158. * - ``soc-minima``
  159. - ``[{"datetime": "2024-02-05T08:00:00+01:00", value: "8.2 kWh"}]``
  160. - Set points that form lower boundaries, e.g. to target a full car battery in the morning (defaults to NaN values). [#maximum_overlap]_
  161. * - ``soc-maxima``
  162. - ``{"value": "51 kWh", "start": "2024-02-05T12:00:00+01:00", "end": "2024-02-05T13:30:00+01:00"}``
  163. - Set points that form upper boundaries at certain times (defaults to NaN values). [#minimum_overlap]_
  164. * - ``soc-targets``
  165. - ``[{"datetime": "2024-02-05T08:00:00+01:00", value: "3.2 kWh"}]``
  166. - Exact set point(s) that the scheduler needs to realize (defaults to NaN values).
  167. * - ``soc-gain``
  168. - ``[".1kWh"]``
  169. - SoC gain per time step, e.g. from a secondary energy source (defaults to zero).
  170. * - ``soc-usage``
  171. - ``[{"sensor": 23}]``
  172. - SoC reduction per time step, e.g. from a load or heat sink (defaults to zero).
  173. * - ``roundtrip-efficiency``
  174. - ``"90%"``
  175. - Below 100%, this represents roundtrip losses (of charging & discharging), usually used for batteries. Can be percent or ratio ``[0,1]`` (defaults to 100%). [#quantity_field]_
  176. * - ``charging-efficiency``
  177. - ``".9"``
  178. - Apply efficiency losses only at time of charging, not across roundtrip (defaults to 100%).
  179. * - ``discharging-efficiency``
  180. - ``"90%"``
  181. - Apply efficiency losses only at time of discharging, not across roundtrip (defaults to 100%).
  182. * - ``storage-efficiency``
  183. - ``"99.9%"``
  184. - This can encode losses over time, so each time step the energy is held longer leads to higher losses (defaults to 100%). Also read [#storage_efficiency]_ about applying this value per time step across longer time spans.
  185. * - ``prefer-charging-sooner``
  186. - ``True``
  187. - Tie-breaking policy to apply if conditions are stable, which signals a preference to charge sooner rather than later (defaults to True). It also signals a preference to discharge later. Boolean option only.
  188. * - ``prefer-curtailing-later``
  189. - ``True``
  190. - Tie-breaking policy to apply if conditions are stable, which signals a preference to curtail both consumption and production later, whichever is applicable (defaults to True). Boolean option only.
  191. * - ``power-capacity``
  192. - ``"50kW"``
  193. - Device-level power constraint. How much power can be applied to this asset (defaults to the Sensor attribute ``capacity_in_mw``). [#minimum_overlap]_
  194. * - ``consumption-capacity``
  195. - ``{"sensor": 56}``
  196. - Device-level power constraint on consumption. How much power can be drawn by this asset. [#minimum_overlap]_
  197. * - ``production-capacity``
  198. - ``"0kW"`` (only consumption)
  199. - Device-level power constraint on production. How much power can be supplied by this asset. For :abbr:`PV (photovoltaic solar panels)` curtailment, set this to reference your sensor containing PV power forecasts. [#minimum_overlap]_
  200. .. [#quantity_field] Can only be set as a fixed quantity.
  201. .. [#maximum_overlap] In case this field defines partially overlapping time periods, the maximum value is selected. See :ref:`variable_quantities`.
  202. .. [#minimum_overlap] In case this field defines partially overlapping time periods, the minimum value is selected. See :ref:`variable_quantities`.
  203. .. [#storage_efficiency] The storage efficiency (e.g. 95% or 0.95) to use for the schedule is applied over each time step equal to the sensor resolution. For example, a storage efficiency of 95 percent per (absolute) day, for scheduling a 1-hour resolution sensor, should be passed as a storage efficiency of :math:`0.95^{1/24} = 0.997865`.
  204. For more details on the possible formats for field values, see :ref:`variable_quantities`.
  205. Usually, not the whole flexibility model is needed.
  206. FlexMeasures can infer missing values in the flex model, and even get them (as default) from the sensor's attributes.
  207. You can add new storage schedules with the CLI command ``flexmeasures add schedule for-storage``.
  208. If you model devices that *buffer* energy (e.g. thermal energy storage systems connected to heat pumps), we can use the same flexibility parameters described above for storage devices.
  209. However, here are some tips to model a buffer correctly:
  210. - Describe the thermal energy content in kWh or MWh.
  211. - Set ``soc-minima`` to the accumulative usage forecast.
  212. - Set ``charging-efficiency`` to the sensor describing the :abbr:`COP (coefficient of performance)` values.
  213. - Set ``storage-efficiency`` to a value below 100% to model (heat) loss.
  214. What happens if the flex model describes an infeasible problem for the storage scheduler? Excellent question!
  215. It is highly important for a robust operation that these situations still lead to a somewhat good outcome.
  216. From our practical experience, we derived a ``StorageFallbackScheduler``.
  217. It simplifies an infeasible situation by just starting to charge, discharge, or do neither,
  218. depending on the first target state of charge and the capabilities of the asset.
  219. Of course, we also log a failure in the scheduling job, so it's important to take note of these failures. Often, mis-configured flex models are the reason.
  220. For a hands-on tutorial on using some of the storage flex-model fields, head over to :ref:`tut_v2g` use case and `the API documentation for triggering schedules <../api/v3_0.html#post--api-v3_0-sensors-(id)-schedules-trigger>`_.
  221. Finally, are you interested in the linear programming details behind the storage scheduler?
  222. Then head over to :ref:`storage_device_scheduler`!
  223. You can also review the current flex-model for storage in the code, at ``flexmeasures.data.schemas.scheduling.storage.StorageFlexModelSchema``.
  224. Shiftable loads (processes)
  225. ^^^^^^^^^^^^^^^^^^^^^^^^^^
  226. For *processes* that can be shifted or interrupted, but have to happen at a constant rate (of consumption), FlexMeasures provides the ``ProcessScheduler``.
  227. Some examples from practice (usually industry) could be:
  228. - A centrifuge's daily work of combing through sludge water. Depends on amount of sludge present.
  229. - Production processes with a target amount of output until the end of the current shift. The target usually comes out of production planning.
  230. - Application of coating under hot temperature, with fixed number of times it needs to happen before some deadline.
  231. .. list-table::
  232. :header-rows: 1
  233. :widths: 20 25 90
  234. * - Field
  235. - Example value
  236. - Description
  237. * - ``power``
  238. - ``"15kW"``
  239. - Nominal power of the load.
  240. * - ``duration``
  241. - ``"PT4H"``
  242. - Time that the load needs to lasts.
  243. * - ``optimization_direction``
  244. - ``"MAX"``
  245. - Objective of the scheduler, to maximize (``"MAX"``) or minimize (``"MIN"``).
  246. * - ``time_restrictions``
  247. - ``[{"start": "2015-01-02T08:00:00+01:00", "duration": "PT2H"}]``
  248. - Time periods in which the load cannot be scheduled to run.
  249. * - ``process_type``
  250. - ``"INFLEXIBLE"``, ``"SHIFTABLE"`` or ``"BREAKABLE"``
  251. - Is the load inflexible and should it run as soon as possible? Or can the process's start time be shifted? Or can it even be broken up into smaller segments?
  252. You can review the current flex-model for processes in the code, at ``flexmeasures.data.schemas.scheduling.process.ProcessSchedulerFlexModelSchema``.
  253. You can add new shiftable-process schedules with the CLI command ``flexmeasures add schedule for-process``.
  254. .. note:: Currently, the ``ProcessScheduler`` uses only the ``consumption-price`` field of the flex-context, so it ignores any site capacities and inflexible devices.
  255. Work on other schedulers
  256. --------------------------
  257. We believe the two schedulers (and their flex-models) we describe here are covering a lot of use cases already.
  258. Here are some thoughts on further innovation:
  259. - Writing your own scheduler.
  260. You can always write your own scheduler (see :ref:`plugin_customization`).
  261. You then might want to add your own flex model, as well.
  262. FlexMeasures will let the scheduler decide which flexibility model is relevant and how it should be validated.
  263. - We also aim to model situations with more than one flexible asset, and that have different types of flexibility (e.g. EV charging and smart heating in the same site).
  264. This is ongoing architecture design work, and therefore happens in development settings, until we are happy with the outcomes.
  265. Thoughts welcome :)
  266. - Aggregating flexibility of a group of assets (e.g. a neighborhood) and optimizing its aggregated usage (e.g. for grid congestion support) is also an exciting direction for expansion.