Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0892d3f
chore: sync main into develop [skip ci]
github-actions[bot] Jun 10, 2026
7fcfb0e
chore(docs): track freeze outputs for 19.2-19.4 reference pages
bartzbeielstein Jun 11, 2026
f028cfd
Merge pull request #362 from sequential-parameter-optimization/chore/…
bartzbeielstein Jun 11, 2026
3a3deb3
feat(calendar): add per-Bundesland school-holiday features (roadmap #6)
bartzbeielstein Jun 11, 2026
5e46c40
fix(calendar): apply code-review fixes for school-holiday feature branch
bartzbeielstein Jun 11, 2026
48b96a7
feat(downloader): per-zone collect mode for download_zone_loads + bot…
bartzbeielstein Jun 11, 2026
cfeeda4
feat(utils): generic TTL'd atomic snapshot store
bartzbeielstein Jun 12, 2026
34a7a0c
feat(preprocessing): coverage guards, forecast shape report, leakage …
bartzbeielstein Jun 12, 2026
fae172a
chore(docs): track freeze outputs for the school-holiday reference pages
bartzbeielstein Jun 12, 2026
9e2710a
fix(utils): code-review fixes for SnapshotStore
bartzbeielstein Jun 12, 2026
f40cf41
fix(downloader): apply code-review fixes to zone-collect-mode
bartzbeielstein Jun 12, 2026
de7f3ca
fix(docs): drop cross-branch snapshot-store entries from _quarto.yml
bartzbeielstein Jun 12, 2026
1d7d0ab
fix(preprocessing,guards): six surgical code-review fixes
bartzbeielstein Jun 12, 2026
6e22a12
docs(downloader): regenerate reference pages after docstring fixes
bartzbeielstein Jun 12, 2026
2d7f2d6
docs(utils): regenerate reference pages after docstring fixes
bartzbeielstein Jun 12, 2026
c84d387
Merge pull request #364 from sequential-parameter-optimization/feat/s…
bartzbeielstein Jun 12, 2026
ed54496
chore(release): 22.1.0-rc.1 [skip ci]
semantic-release-bot Jun 12, 2026
edf4427
Merge pull request #365 from sequential-parameter-optimization/feat/z…
bartzbeielstein Jun 12, 2026
b66baab
Merge pull request #366 from sequential-parameter-optimization/feat/s…
bartzbeielstein Jun 12, 2026
90fd4ea
Merge pull request #367 from sequential-parameter-optimization/feat/o…
bartzbeielstein Jun 12, 2026
29fd249
chore(docs): track freeze outputs for 22.1.0-rc feature reference pages
bartzbeielstein Jun 12, 2026
a54ee26
chore(release): 22.1.0-rc.2 [skip ci]
semantic-release-bot Jun 12, 2026
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
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
## [22.1.0-rc.2](https://github.com/sequential-parameter-optimization/spotforecast2-safe/compare/v22.1.0-rc.1...v22.1.0-rc.2) (2026-06-12)


### Features

* **downloader:** per-zone collect mode for download_zone_loads + bottom-up zone QC frame ([48b96a7](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/48b96a7957cac27215eb6d5b18d2b576328d87a2)), closes [#363](https://github.com/sequential-parameter-optimization/spotforecast2-safe/issues/363)
* **preprocessing:** coverage guards, forecast shape report, leakage guard ([34a7a0c](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/34a7a0cb1f9d61a3043f12ed86343ed062d2ce94))
* **utils:** generic TTL'd atomic snapshot store ([cfeeda4](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/cfeeda4095b60d004121b01e23eed60c8c72beda))


### Bug Fixes

* **docs:** drop cross-branch snapshot-store entries from _quarto.yml ([de7f3ca](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/de7f3caefae01a6188140ff73e32681b976df4fe))
* **downloader:** apply code-review fixes to zone-collect-mode ([f40cf41](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/f40cf4187bd7d0b6fc5811cf851f327c54cbef23))
* **preprocessing,guards:** six surgical code-review fixes ([1d7d0ab](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/1d7d0ab6c53977bb242b862e430e1b10e6619b97))
* **utils:** code-review fixes for SnapshotStore ([9e2710a](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/9e2710a217cdb5f7543e0b2230a4719d872e164e))


### Documentation

* **downloader:** regenerate reference pages after docstring fixes ([6e22a12](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/6e22a129bd7ddd6cbe9e9fa4f8ea24ef013b8d40))
* **utils:** regenerate reference pages after docstring fixes ([2d7f2d6](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/2d7f2d60e8404df7341b0b5be10e7be25b0c387c))

## [22.1.0-rc.1](https://github.com/sequential-parameter-optimization/spotforecast2-safe/compare/v22.0.0...v22.1.0-rc.1) (2026-06-12)


### Features

* **calendar:** add per-Bundesland school-holiday features (roadmap [#6](https://github.com/sequential-parameter-optimization/spotforecast2-safe/issues/6)) ([3a3deb3](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/3a3deb3c8a6ca91029463f0a376ede7910b9a377))


### Bug Fixes

* **calendar:** apply code-review fixes for school-holiday feature branch ([5e46c40](https://github.com/sequential-parameter-optimization/spotforecast2-safe/commit/5e46c40142ab77c692fb4a28e5be0d0c4317e928))

## [22.0.0](https://github.com/sequential-parameter-optimization/spotforecast2-safe/compare/v21.2.0...v22.0.0) (2026-06-10)


Expand Down
540 changes: 540 additions & 0 deletions LICENSES/ODbL-1.0.txt

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions MODEL_CARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This card describes what spotforecast2-safe is, how to use it safely, the condit
| Field | Value |
| --- | --- |
| Name | spotforecast2-safe |
| Version | 22.0.0 |
| Version | 22.1.0-rc.2 |
| Type | Deterministic Python library for time series feature engineering and recursive multi-step forecasting. It performs no training of its own. |
| Developed by | Thomas Bartz-Beielstein, ORCID [0000-0002-5938-5158](https://orcid.org/0000-0002-5938-5158) |
| Distributed by | the `sequential-parameter-optimization` GitHub organization |
Expand All @@ -18,7 +18,7 @@ This card describes what spotforecast2-safe is, how to use it safely, the condit

The library depends only on numpy, pandas, scikit-learn, lightgbm, numba, pyarrow, requests, feature-engine, holidays, astral, and tqdm. It deliberately excludes plotly, matplotlib, spotoptim, optuna, torch, and tensorflow, so no plotting or automated-tuning code ships in this package.

Two Common Platform Enumeration (CPE) identifiers let vulnerability-tracking and software bill of materials (SBOM) tools recognize the package. The wildcard identifier `cpe:2.3:a:sequential_parameter_optimization:spotforecast2_safe:*:*:*:*:*:*:*:*` matches any release; the current release is `cpe:2.3:a:sequential_parameter_optimization:spotforecast2_safe:22.0.0:*:*:*:*:*:*:*`.
Two Common Platform Enumeration (CPE) identifiers let vulnerability-tracking and software bill of materials (SBOM) tools recognize the package. The wildcard identifier `cpe:2.3:a:sequential_parameter_optimization:spotforecast2_safe:*:*:*:*:*:*:*:*` matches any release; the current release is `cpe:2.3:a:sequential_parameter_optimization:spotforecast2_safe:22.1.0-rc.2:*:*:*:*:*:*:*`.

The library itself is a low-risk component: it is deterministic, its source is fully inspectable, and it fails safe on invalid input. It is built to support high-risk AI systems in the sense of the EU AI Act, but it is not itself such a system. When it is embedded in a high-risk deployment, the duties that attach to that system fall on the integrator, not on the library.

Expand All @@ -30,7 +30,7 @@ Responsibilities are divided as follows.
| Distribution | sequential-parameter-optimization on GitHub | repository issue tracker |
| Deployment, operation, and audit | the system integrator | defined per deployment |

The current release is 22.0.0, with a stable public interface pinned in `spotforecast2_safe.__init__.__all__`. The full version history, including release dates, is recorded in `CHANGELOG.md` and on the GitHub Releases page; it is maintained automatically by the release pipeline and is not repeated here.
The current release is 22.1.0-rc.2, with a stable public interface pinned in `spotforecast2_safe.__init__.__all__`. The full version history, including release dates, is recorded in `CHANGELOG.md` and on the GitHub Releases page; it is maintained automatically by the release pipeline and is not repeated here.

## 2. Intended Use and Scope

Expand Down Expand Up @@ -216,7 +216,7 @@ Maintainer: Thomas Bartz-Beielstein, ORCID [0000-0002-5938-5158](https://orcid.o
}
```

Or as a formatted reference: Bartz-Beielstein, T. (2026). *spotforecast2-safe: Safety-critical subset of spotforecast2* (Version 22.0.0) [Computer software]. https://github.com/sequential-parameter-optimization/spotforecast2-safe
Or as a formatted reference: Bartz-Beielstein, T. (2026). *spotforecast2-safe: Safety-critical subset of spotforecast2* (Version 22.1.0-rc.2) [Computer software]. https://github.com/sequential-parameter-optimization/spotforecast2-safe

The technical report (`bart26h/index.qmd`) is the long-form reference for design rationale, compliance mapping, and evaluation protocol.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"hash": "cef70272987d4d216006d080f8b10a96",
"result": {
"engine": "jupyter",
"markdown": "---\ntitle: calendar.features.get_ephemeris_features\n---\n\n\n\n```python\ncalendar.features.get_ephemeris_features(\n start,\n cov_end,\n location,\n freq='h',\n timezone='UTC',\n)\n```\n\nCreate continuous solar-geometry features from the ephemeris.\n\nUnlike `get_day_night_features` (which rounds sunrise/sunset to whole\nhours and emits a binary daylight flag), this builder exposes the\n*continuous* solar geometry the hour-of-day RBFs only encode implicitly:\nthe per-hour solar elevation, the exact daylight duration, and the signed\ntime relative to sunrise and sunset. These linearise lighting-load timing\nand the midday PV offset, are purely deterministic from the date and the\nfixed coordinates, add no dependency, and leak nothing for any forecast\nhour (Xie & Hong 2018, ``xieh18a``; López 2020, ``lope20a``).\n\nThe returned DataFrame contains four ``float64`` columns:\n\n- ``solar_elevation`` — solar elevation angle in degrees (negative at\n night, peaking at solar noon).\n- ``daylight_duration_h`` — exact sunset−sunrise span for the date, hours.\n- ``hours_since_sunrise`` — signed hours since that date's sunrise\n (negative before sunrise).\n- ``hours_to_sunset`` — signed hours until that date's sunset\n (negative after sunset).\n\n## Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|----------|-----------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------|\n| start | [Union](`typing.Union`)\\[[str](`str`), [pd](`pandas`).[Timestamp](`pandas.Timestamp`)\\] | Start of the time range. String values are parsed with ``utc=True``. | _required_ |\n| cov_end | [Union](`typing.Union`)\\[[str](`str`), [pd](`pandas`).[Timestamp](`pandas.Timestamp`)\\] | Inclusive end of the time range. String values are parsed with ``utc=True``. | _required_ |\n| location | [LocationInfo](`astral.LocationInfo`) | `LocationInfo` describing the geographic location. | _required_ |\n| freq | [str](`str`) | Pandas-compatible frequency string for the output index. Defaults to ``\"h\"`` (hourly). | `'h'` |\n| timezone | [str](`str`) | Timezone label applied to the generated index. Defaults to ``\"UTC\"``. | `'UTC'` |\n\n## Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------------------------------------|---------------------------------------------------------------------|\n| | [pd](`pandas`).[DataFrame](`pandas.DataFrame`) | pd.DataFrame: Columns ``solar_elevation``, ``daylight_duration_h``, |\n| | [pd](`pandas`).[DataFrame](`pandas.DataFrame`) | ``hours_since_sunrise``, ``hours_to_sunset``; tz-aware |\n| | [pd](`pandas`).[DataFrame](`pandas.DataFrame`) | `DatetimeIndex` with the requested ``freq``. |\n\n## Examples {.doc-section .doc-section-examples}\n\n\n::: {#7e8352c8 .cell execution_count=1}\n``` {.python .cell-code}\nimport pandas as pd\nfrom astral import LocationInfo\nfrom spotforecast2_safe.calendar import get_ephemeris_features\n\nstart = pd.Timestamp(\"2024-06-21\", tz=\"UTC\")\ncov_end = pd.Timestamp(\"2024-06-21 23:00\", tz=\"UTC\")\nlocation = LocationInfo(latitude=51.5136, longitude=7.4653, timezone=\"UTC\")\n\nfeats = get_ephemeris_features(start, cov_end, location)\nprint(\"columns:\", feats.columns.tolist())\nprint(\"shape:\", feats.shape)\n# Summer solstice: long day and a high midday sun in Dortmund.\nprint(\"max elevation:\", round(feats[\"solar_elevation\"].max(), 1))\nassert feats.shape == (24, 4)\nassert feats[\"solar_elevation\"].max() > 50.0\nassert feats[\"daylight_duration_h\"].iloc[0] > 14.0\n```\n\n::: {.cell-output .cell-output-stdout}\n```\ncolumns: ['solar_elevation', 'daylight_duration_h', 'hours_since_sunrise', 'hours_to_sunset']\nshape: (24, 4)\nmax elevation: 61.4\n```\n:::\n:::\n\n\n",
"supporting": [
"calendar.features.get_ephemeris_features_files"
],
"filters": [],
"includes": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"hash": "eb4ab1f17065a1d243ac7230d1b3b7d7",
"result": {
"engine": "jupyter",
"markdown": "---\ntitle: calendar.holiday.create_day_type_df\n---\n\n\n\n```python\ncalendar.holiday.create_day_type_df(\n start,\n end,\n tz='UTC',\n freq='h',\n country_code='DE',\n state='NW',\n)\n```\n\nCreate a day-type refinement of the public-holiday column.\n\nReturns two integer columns derived purely from the weekday and the\npublic-holiday calendar (pure calendar arithmetic — known years ahead,\nleakage-free):\n\n- ``is_workday``: ``1`` when the day is Monday–Friday **and** not a public\n holiday, else ``0``.\n- ``day_type``: an integer class with public-holiday precedence —\n ``0`` working day, ``1`` Saturday (non-holiday), ``2`` Sunday\n (non-holiday), ``3`` public holiday (any weekday). A public holiday that\n falls on a weekend is still classed as ``3``.\n\nThese remove some of the worst single-day errors a plain holiday flag\nleaves behind (Ziel 2018, ``ziel18a``).\n\n## Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------------|----------------------------------------------------------------|------------------------------------------------------|------------|\n| start | [str](`str`) \\| [pd](`pandas`).[Timestamp](`pandas.Timestamp`) | Start date/datetime. | _required_ |\n| end | [str](`str`) \\| [pd](`pandas`).[Timestamp](`pandas.Timestamp`) | End date/datetime. | _required_ |\n| tz | [str](`str`) | Timezone to use if not inferred from start/end. | `'UTC'` |\n| freq | [str](`str`) | Frequency of the resulting DataFrame. | `'h'` |\n| country_code | [str](`str`) | Country code for holidays (e.g. ``\"DE\"``, ``\"US\"``). | `'DE'` |\n| state | [str](`str`) | State code for holidays (e.g. ``\"NW\"``, ``\"CA\"``). | `'NW'` |\n\n## Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------------------------------------|----------------------------------------------------------------------|\n| | [pd](`pandas`).[DataFrame](`pandas.DataFrame`) | pd.DataFrame: Index covering ``[start, end]`` at *freq* with integer |\n| | [pd](`pandas`).[DataFrame](`pandas.DataFrame`) | columns ``is_workday`` and ``day_type``; no NaNs. |\n\n## Examples {.doc-section .doc-section-examples}\n\n\n::: {#2a80153c .cell execution_count=1}\n``` {.python .cell-code}\nimport pandas as pd\nfrom spotforecast2_safe.calendar import create_day_type_df\n\n# 2024-01-01 Mon = New Year (holiday), 02 Tue = workday,\n# 06 Sat, 07 Sun.\ndf = create_day_type_df(\"2024-01-01\", \"2024-01-07\", freq=\"D\")\nprint(df[\"is_workday\"].tolist())\nprint(df[\"day_type\"].tolist())\nassert df.loc[\"2024-01-01\", \"day_type\"] == 3 # holiday\nassert df.loc[\"2024-01-02\", \"is_workday\"] == 1\nassert df.loc[\"2024-01-06\", \"day_type\"] == 1 # Saturday\nassert df.loc[\"2024-01-07\", \"day_type\"] == 2 # Sunday\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n[0, 1, 1, 1, 1, 0, 0]\n[3, 0, 0, 0, 0, 1, 2]\n```\n:::\n:::\n\n\n",
"supporting": [
"calendar.holiday.create_day_type_df_files"
],
"filters": [],
"includes": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"hash": "2ec09d8e46e065b2f395a0504ddf62b9",
"result": {
"engine": "jupyter",
"markdown": "---\ntitle: calendar.holiday.create_school_holiday_df\n---\n\n\n\n```python\ncalendar.holiday.create_school_holiday_df(\n start,\n end,\n tz='UTC',\n freq='h',\n country_code='DE',\n state='NW',\n)\n```\n\nCreate a DataFrame with a binary school-holiday indicator for a German state.\n\nBuilds a tz-aware time grid over ``[start, end]`` at *freq* and marks\nevery timestamp that falls within a school-holiday period of the requested\nBundesland as ``1``; all others are ``0``. Both edges of each interval\nare inclusive.\n\nData source: OpenHolidays API (https://openholidaysapi.org), ODbL-1.0.\nCoverage: 2022-01-01 to 2027-12-31 for all 16 German Bundesländer.\n\nOnly ``country_code=\"DE\"`` is supported. Requests whose span extends\nbeyond the covered range at either edge raise ``ValueError`` — there is\nno fill or extrapolation.\n\n## Parameters {.doc-section .doc-section-parameters}\n\n| Name | Type | Description | Default |\n|--------------|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| start | [str](`str`) \\| [pd](`pandas`).[Timestamp](`pandas.Timestamp`) | Start date/datetime of the requested grid. | _required_ |\n| end | [str](`str`) \\| [pd](`pandas`).[Timestamp](`pandas.Timestamp`) | End date/datetime of the requested grid (inclusive). | _required_ |\n| tz | [str](`str`) | Timezone for the resulting index. Ignored when *start* or *end* is already a tz-aware ``pd.Timestamp``. | `'UTC'` |\n| freq | [str](`str`) | Pandas-compatible frequency string. Defaults to ``\"h\"`` (hourly). | `'h'` |\n| country_code | [str](`str`) | Must be ``\"DE\"`` (Germany). Any other value raises ``ValueError``. | `'DE'` |\n| state | [str](`str`) | ISO 3166-2 subdivision short code for the Bundesland, e.g. ``\"NW\"`` (North Rhine-Westphalia), ``\"BY\"`` (Bavaria). Defaults to ``\"NW\"``. | `'NW'` |\n\n## Returns {.doc-section .doc-section-returns}\n\n| Name | Type | Description |\n|--------|------------------------------------------------|----------------------------------------------------------------------|\n| | [pd](`pandas`).[DataFrame](`pandas.DataFrame`) | pd.DataFrame: Single integer column ``is_school_holiday`` (values in |\n| | [pd](`pandas`).[DataFrame](`pandas.DataFrame`) | ``{0, 1}``; no NaNs) with a tz-aware `DatetimeIndex` at *freq*. |\n\n## Raises {.doc-section .doc-section-raises}\n\n| Name | Type | Description |\n|--------|----------------------------|-----------------------------------------------------------------------------------------------------------------------|\n| | [ValueError](`ValueError`) | If *country_code* is not ``\"DE\"``, or if the requested span extends beyond the dataset validity range at either edge. |\n\n## Examples {.doc-section .doc-section-examples}\n\n\n::: {#e831a63e .cell execution_count=1}\n``` {.python .cell-code}\nfrom spotforecast2_safe.calendar import create_school_holiday_df\n\n# NW Sommerferien 2024: 2024-07-08 → 2024-08-20 (inclusive).\n# Day before (2024-07-07) must be 0; first day (2024-07-08) must be 1.\ndf = create_school_holiday_df(\n \"2024-07-06\", \"2024-07-10\", freq=\"D\", state=\"NW\"\n)\nprint(df)\nassert df.loc[\"2024-07-07\", \"is_school_holiday\"] == 0\nassert df.loc[\"2024-07-08\", \"is_school_holiday\"] == 1\nassert df.loc[\"2024-07-09\", \"is_school_holiday\"] == 1\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n is_school_holiday\n2024-07-06 00:00:00+00:00 0\n2024-07-07 00:00:00+00:00 0\n2024-07-08 00:00:00+00:00 1\n2024-07-09 00:00:00+00:00 1\n2024-07-10 00:00:00+00:00 1\n```\n:::\n:::\n\n\n",
"supporting": [
"calendar.holiday.create_school_holiday_df_files/figure-html"
],
"filters": [],
"includes": {}
}
}
Loading