-
-
Notifications
You must be signed in to change notification settings - Fork 43
Detangle generation data #428
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
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
3fbeea0
Split generation into input and target
dfulu ca98c8f
clean up
dfulu 34973f6
clean up more
dfulu e2323bb
Move global variable to its rightful place at the top
dfulu e25fc68
Convert locations input to csv and add option to exclude IDs from config
dfulu 045fc29
Add input/target to eror message
dfulu 2c35348
Fix location IDs in tests
dfulu 834c1f2
Update src/ocf_data_sampler/datasets/pvnet/preprocess.py
dfulu cfa6e8e
Improve test_apply_dropout_to_datasets
dfulu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| """Configuration model.""" | ||
|
|
||
| from ocf_data_sampler.config.load import load_yaml_configuration | ||
| from ocf_data_sampler.config.model import Configuration, InputData | ||
| from ocf_data_sampler.config.model import PVNetDataConfig | ||
| from ocf_data_sampler.config.save import save_yaml_configuration |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,4 @@ | ||
| """Configuration model for the dataset. | ||
|
|
||
| Absolute or relative zarr filepath(s). | ||
| Prefix with a protocol like s3:// to read from alternative filesystems. | ||
| """ | ||
| """Configuration model for the PVNet dataset.""" | ||
|
|
||
| from collections.abc import Iterator | ||
| from typing import Literal | ||
|
|
@@ -20,16 +16,6 @@ class Base(BaseModel): | |
| model_config = ConfigDict(extra="forbid") | ||
|
|
||
|
|
||
| class General(Base): | ||
| """General pydantic model.""" | ||
|
|
||
| name: str = Field("example", description="The name of this configuration file") | ||
| description: str = Field( | ||
| "example configuration", | ||
| description="Description of this configuration file", | ||
| ) | ||
|
|
||
|
|
||
| class TimeWindowMixin(Base): | ||
| """Mixin class, to add interval start, end and resolution minutes.""" | ||
|
|
||
|
|
@@ -72,7 +58,16 @@ def validate_intervals(self) -> "TimeWindowMixin": | |
| return self | ||
|
|
||
|
|
||
| class DropoutMixin(Base): | ||
| class FillValueMixin(Base): | ||
|
AUdaltsova marked this conversation as resolved.
|
||
| """Mixin class, to add a value used for filling missing data.""" | ||
|
|
||
| dropout_fill_value: float = Field( | ||
| default=0.0, | ||
| description="The value used to fill in dropped out data or any missing values." | ||
| ) | ||
|
|
||
|
|
||
| class DropoutMixin(FillValueMixin): | ||
| """Mixin class, to add dropout minutes.""" | ||
|
|
||
| dropout_timedeltas_minutes: list[int] = Field( | ||
|
|
@@ -87,11 +82,6 @@ class DropoutMixin(Base): | |
| "floats (probability that dropout of the corresponding timedelta is applied)", | ||
| ) | ||
|
|
||
| dropout_fill_value: float = Field( | ||
| default=0.0, | ||
| description="The value used to fill in dropped out data or any missing values." | ||
| ) | ||
|
|
||
| @field_validator("dropout_timedeltas_minutes") | ||
| def dropout_timedeltas_minutes_negative(cls, v: list[int]) -> list[int]: | ||
| """Validate 'dropout_timedeltas_minutes'.""" | ||
|
|
@@ -235,7 +225,7 @@ class NWP(TimeWindowMixin, DropoutMixin, SpatialWindowMixin, NormalisationConsta | |
|
|
||
| provider: str = Field(..., description="The provider of the NWP data") | ||
|
|
||
| accum_channels: list[str] = Field([], description="the nwp channels which need to be diffed") | ||
| accum_channels: list[str] = Field([], description="The NWP channels which need to be diffed") | ||
|
|
||
| max_staleness_minutes: int | None = Field( | ||
| None, | ||
|
|
@@ -319,7 +309,48 @@ def items(self) -> Iterator[tuple[str, NWP]]: | |
| return self.root.items() | ||
|
|
||
|
|
||
| class Generation(TimeWindowMixin, DropoutMixin): | ||
| class GenerationWindow(Base): | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This class is used for both the input and target generation slices. The full config paths are This class doesn't have |
||
| """Interval bounds for a generation window. | ||
|
|
||
| Unlike `TimeWindowMixin`, no temporal resolution here - it belongs to the shared | ||
| generation data source (`Generation.time_resolution_minutes`), not to an individual window. | ||
| """ | ||
|
|
||
| interval_start_minutes: int = Field( | ||
| ..., | ||
| description="Data interval starts at `t0 + interval_start_minutes`", | ||
| ) | ||
|
|
||
| interval_end_minutes: int = Field( | ||
| ..., | ||
| description="Data interval ends at `t0 + interval_end_minutes`", | ||
| ) | ||
|
|
||
| @model_validator(mode="after") | ||
| def validate_interval_order(self) -> "GenerationWindow": | ||
| """Validator for time interval fields.""" | ||
| start = self.interval_start_minutes | ||
| end = self.interval_end_minutes | ||
| if start > end: | ||
| raise ValueError( | ||
| f"interval_start_minutes ({start}) must be <= interval_end_minutes ({end})", | ||
| ) | ||
| return self | ||
|
|
||
|
|
||
| class GenerationInputWindow(GenerationWindow, DropoutMixin): | ||
|
AUdaltsova marked this conversation as resolved.
|
||
| """A generation window with dropout configuration. | ||
|
|
||
| Dropout is configurable here since only the input window (not the prediction target) | ||
| should ever be randomly masked out. | ||
| """ | ||
|
|
||
|
|
||
| class GenerationTargetWindow(GenerationWindow, FillValueMixin): | ||
| """Generation target window configuration model.""" | ||
|
|
||
|
|
||
| class Generation(Base): | ||
| """Generation configuration model.""" | ||
|
|
||
| zarr_path: str = Field( | ||
|
|
@@ -328,11 +359,77 @@ class Generation(TimeWindowMixin, DropoutMixin): | |
| "to read from alternative filesystems.", | ||
| ) | ||
|
|
||
| time_resolution_minutes: int = Field( | ||
| ..., | ||
| gt=0, | ||
| description="The temporal resolution of the generation data in minutes", | ||
| ) | ||
|
|
||
| input: GenerationInputWindow | None = None | ||
| target: GenerationTargetWindow | None = None | ||
|
|
||
| @model_validator(mode="after") | ||
| def validate_windows(self) -> "Generation": | ||
| """Validate the input/target windows are set and divisible by the shared resolution.""" | ||
| if self.input is None and self.target is None: | ||
| raise ValueError( | ||
| "At least one of `generation.input` or `generation.target` must be configured", | ||
| ) | ||
|
AUdaltsova marked this conversation as resolved.
|
||
|
|
||
| for name, window in (("input", self.input), ("target", self.target)): | ||
| if window is None: | ||
| continue | ||
| for bound_name, bound in ( | ||
| ("interval_start_minutes", window.interval_start_minutes), | ||
| ("interval_end_minutes", window.interval_end_minutes), | ||
| ): | ||
| if bound % self.time_resolution_minutes != 0: | ||
| raise ValueError( | ||
| f"generation.{name}.{bound_name} ({bound}) must be divisible by " | ||
| f"generation.time_resolution_minutes ({self.time_resolution_minutes})", | ||
| ) | ||
| return self | ||
|
|
||
|
|
||
| class SamplingGrid(Base): | ||
|
AUdaltsova marked this conversation as resolved.
|
||
| """Configuration for the (location, time) grid that t0 times are sampled from.""" | ||
|
|
||
| locations_csv_path: str = Field( | ||
| ..., | ||
| description="Absolute or relative CSV filepath to the locations metadata (location IDs " | ||
| "and their coordinates) - see `ocf_data_sampler.load.locations.open_locations`.", | ||
| ) | ||
|
|
||
| exclude_location_ids: list[int] = Field( | ||
| default=[], | ||
| description="Location IDs from the locations metadata to drop from the sampling grid. " | ||
| "Every ID listed must be present in the locations data.", | ||
| ) | ||
|
dfulu marked this conversation as resolved.
|
||
|
|
||
| t0_resolution_minutes: int = Field( | ||
| ..., | ||
| gt=0, | ||
| description="The cadence t0 candidates are enumerated at, needed to compute valid t0 " | ||
| "times regardless of which other input sources are configured.", | ||
| ) | ||
|
|
||
| @field_validator("exclude_location_ids") | ||
| def validate_exclude_location_ids_unique(cls, v: list[int]) -> list[int]: | ||
| """Validate 'exclude_location_ids'.""" | ||
| duplicates = {i for i in v if v.count(i) > 1} | ||
| if duplicates: | ||
| raise ValueError(f"exclude_location_ids contains duplicates: {sorted(duplicates)}") | ||
| return v | ||
|
|
||
|
|
||
| class SolarPosition(TimeWindowMixin): | ||
| """Solar position configuration model.""" | ||
|
|
||
|
|
||
| class DatetimeEncoding(TimeWindowMixin): | ||
| """Datetime encoding configuration model.""" | ||
|
|
||
|
|
||
|
AUdaltsova marked this conversation as resolved.
|
||
| _embedding_type = list[tuple[str, Literal["cyclic", "linear"]]] | ||
| class T0Embedding(Base): | ||
| """Configuration for the t0 time embedding.""" | ||
|
|
@@ -374,18 +471,13 @@ def validate_embeddings(cls, embeddings: _embedding_type) -> _embedding_type: | |
| return embeddings | ||
|
|
||
|
|
||
| class InputData(Base): | ||
| """Input data model.""" | ||
| class PVNetDataConfig(Base): | ||
|
dfulu marked this conversation as resolved.
|
||
| """Configuration model for the PVNet dataset.""" | ||
|
|
||
| sampling_grid: SamplingGrid | ||
|
AUdaltsova marked this conversation as resolved.
|
||
| satellite: Satellite | None = None | ||
| nwp: MultiNWP | None = None | ||
| generation: Generation | None = None | ||
| solar_position: SolarPosition | None = None | ||
| datetime_encoding: DatetimeEncoding | None = None | ||
| t0_embedding: T0Embedding | None = None | ||
|
|
||
|
dfulu marked this conversation as resolved.
|
||
|
|
||
| class Configuration(Base): | ||
| """Configuration model for the dataset.""" | ||
|
|
||
| general: General = General() | ||
| input_data: InputData = InputData() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.