From 0f1290e84e3b35c8eb8053a30ea906f9e5bed8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=2E=20M=C3=B8ller?= Date: Fri, 21 Aug 2026 09:02:45 +0200 Subject: [PATCH 1/3] Disallow pvlib in download mode --- sunflow/main.py | 27 +++++++++++++++------------ sunflow/validation.py | 12 +++++++++++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/sunflow/main.py b/sunflow/main.py index 0a4bac9..984dcf9 100644 --- a/sunflow/main.py +++ b/sunflow/main.py @@ -5,6 +5,7 @@ from dataclasses import dataclass from datetime import datetime, timedelta, timezone from enum import Enum +from typing import Any import isodate import numpy as np @@ -221,6 +222,7 @@ def run_nowcast( domain_satellite_name: str, nowcast_config: NowcastConfig, s3_config: S3Config, + clearsky_config: dict[str, Any], full_ensemble: bool = False, custom_time: bool = True, ) -> RunResult: @@ -247,10 +249,6 @@ def run_nowcast( time_step_str = time_step.strftime("%Y-%m-%dT%H:%M:%SZ") logger.info(f"--- Running nowcast for {time_step_str} ---") nc_variable_names = config["nc_variable_names"].copy() - clearsky_config = config.get( - "clearsky", - {"method": "file", "path": config["filename_format"]}, - ) # Fetch current data (with retry loop in operational mode) fetch_current_data_with_retry( @@ -349,7 +347,7 @@ def run_nowcast( nowcast_config.max_clearsky_fallback_days, clearsky_config["path"], config, - domain_nowcast, + domain_satellite, dataset_name, domain_satellite_name, nowcast_config, @@ -553,14 +551,20 @@ def cli() -> None: f"Starting solarnowcasting.main (with configuration version: {model_version})..." ) - # Load configuration args = parse_arguments() - nowcast_config = NowcastConfig.from_env(ensemble_members=args.ensemble_members) - s3_config = S3Config.from_env() - run_mode = args.run_mode dataset_name = args.dataset domain_satellite_name = args.domain_satellite + + # Load configurations + nowcast_config = NowcastConfig.from_env(ensemble_members=args.ensemble_members) + s3_config = S3Config.from_env() + config = yaml.safe_load(open("config.yaml"))[dataset_name] + clearsky_config = config.get( + "clearsky", + {"method": "file", "path": config["filename_format"]}, + ) + domain_satellite = resolve_domain_bbox( domain_satellite_name, args.custom_domain_satellite, @@ -593,8 +597,6 @@ def cli() -> None: f"domain_nowcast={domain_nowcast}." ) - config = yaml.safe_load(open("config.yaml"))[dataset_name] - if run_mode != "s3": os.makedirs(nowcast_config.nowcast_directory, exist_ok=True) @@ -627,7 +629,7 @@ def cli() -> None: "Consider setting alpha=0.0 and beta=0.0 for a single-member run." ) - validate_run_mode(run_mode, dataset_name) + validate_run_mode(run_mode, dataset_name, clearsky_config) validate_config(config, dataset_name) validate_nowcast_config(nowcast_config) verify_environment_variables(run_mode, dataset_name) @@ -681,6 +683,7 @@ def cli() -> None: domain_satellite_name, nowcast_config, s3_config, + clearsky_config, full_ensemble=args.full_ensemble, custom_time=custom_time, ) diff --git a/sunflow/validation.py b/sunflow/validation.py index b32e475..39ac419 100644 --- a/sunflow/validation.py +++ b/sunflow/validation.py @@ -91,7 +91,9 @@ def validate_nowcast_config(nowcast_config: NowcastConfig) -> None: sys.exit(1) -def validate_run_mode(run_mode: str, dataset_name: str) -> None: +def validate_run_mode( + run_mode: str, dataset_name: str, clearsky_config: dict[str, Any] +) -> None: """Validate that the run mode is compatible with the dataset. Exits immediately if the combination of run mode and dataset name @@ -100,6 +102,7 @@ def validate_run_mode(run_mode: str, dataset_name: str) -> None: Args: run_mode: The requested run mode ('download', 'files', or 's3'). dataset_name: Name of the dataset. + clearsky_config: Clearsky configuration dictionary. Raises: SystemExit: If the run mode is incompatible with the dataset. @@ -111,6 +114,13 @@ def validate_run_mode(run_mode: str, dataset_name: str) -> None: "Use run_mode 'files' or 's3' instead. Exiting.\n" ) sys.exit(1) + if run_mode == "download" and clearsky_config["method"] == "pvlib": + logger.error( + "Currently the pvlib clearsky method is not supported " + "for run_mode 'download'. " + "Use run_mode 'files' or 's3' instead. Exiting.\n" + ) + sys.exit(1) def verify_environment_variables(run_mode: str, dataset_name: str) -> None: From 7ffeb3c63c4057d8de59bdc745462a1d3e00f73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=2E=20M=C3=B8ller?= Date: Fri, 21 Aug 2026 09:04:44 +0200 Subject: [PATCH 2/3] Clarify that download is only currently implemented for KNMI and DWD data --- sunflow/downloaders.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sunflow/downloaders.py b/sunflow/downloaders.py index 528776d..eba7863 100644 --- a/sunflow/downloaders.py +++ b/sunflow/downloaders.py @@ -117,6 +117,11 @@ def download_current_data( merged_ds = subset_to_bbox(ds, bbox) current_time = merged_ds.time.values[0] + else: + raise ValueError( + f"Unsupported dataset_name: {dataset_name} " f"for run_mode 'download'" + ) + # Save data current_time_dt = current_time.astype("datetime64[s]").astype(datetime) filename = generate_input_filename( From 7eed17c46d288fd2e998a6059dbd112327daf5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=2E=20M=C3=B8ller?= Date: Fri, 21 Aug 2026 09:23:50 +0200 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 10 ++++++++-- sunflow/main.py | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e33ae..1386e51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +### Added + +- Added checks of invalid configuration combinations [!22](https://github.com/dmidk/sunflow/pull/22), @KristianHMoller - Added `{second}` and `{munite}` as a filename formatting variable [!15](https://github.com/dmidk/sunflow/pull/15), @JoachimKoenigslieb -- Use `.expand_dims` instead of `.assign_coords` to make sure we have both time dimension and time coordinates when loading from files [!15](https://github.com/dmidk/sunflow/pull/15), @JoachimKoenigslieb - Added a `clearsky` config object which can load clear-sky data from files via `clearsky.path` or generate it with `pvlib` via the `simplified_solis` method [!15](https://github.com/dmidk/sunflow/pull/15), @JoachimKoenigslieb -- `check_solar_elevation` now does not assume location is in Copenhagen by default [!15](https://github.com/dmidk/sunflow/pull/15), @JoachimKoenigslieb - Added `MIN_SOLAR_ELEVATION_DEGREES` (defaulting to 6 degrees) to configure the minimum maximum-corner solar elevation required to run [!15](https://github.com/dmidk/sunflow/pull/15), @JoachimKoenigslieb +### Changed + +- Use `.expand_dims` instead of `.assign_coords` to make sure we have both time dimension and time coordinates when loading from files [!15](https://github.com/dmidk/sunflow/pull/15), @JoachimKoenigslieb +- `check_solar_elevation` now does not assume location is in Copenhagen by default [!15](https://github.com/dmidk/sunflow/pull/15), @JoachimKoenigslieb ## [v1.2.0] diff --git a/sunflow/main.py b/sunflow/main.py index 984dcf9..b78efb3 100644 --- a/sunflow/main.py +++ b/sunflow/main.py @@ -238,6 +238,7 @@ def run_nowcast( domain_satellite_name: Domain identifier used for input filenames. nowcast_config: NowcastConfig object. s3_config: S3Config object. + clearsky_config: Clearsky configuration dict. full_ensemble: If True, save all ensemble members. If False, save configured ensemble statistics over ensemble members. custom_time: If True, skip the retry wait loop on missing data.