Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
60 changes: 60 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
import os
import sys

from docutils import nodes
from sphinx import addnodes
from sphinx.domains.changeset import VersionChange, versionlabel_classes
from sphinx.locale import _

sys.path.insert(0, os.path.abspath(".."))

import swvo
Expand Down Expand Up @@ -96,5 +101,60 @@
html_css_files = ["custom.css"]


class DeprecatedNoVersion(VersionChange):
"""Like the built-in ``deprecated::`` directive, but the version argument is optional.

Renders "Deprecated: ..." instead of "Deprecated since version ...:" when no
version is given, for cases where the deprecation isn't tied to a specific
version we want to advertise.
"""

required_arguments = 0
optional_arguments = 2
final_argument_whitespace = True

def run(self):
name = "deprecated"
node = addnodes.versionmodified()
node.document = self.state.document
self.set_source_info(node)
node["type"] = name

version = self.arguments[0] if self.arguments else ""
node["version"] = version
text = _("Deprecated since version %s") % version if version else _("Deprecated")

messages = []
if len(self.arguments) == 2:
inodes, messages = self.parse_inline(self.arguments[1], lineno=self.lineno + 1)
para = nodes.paragraph(self.arguments[1], "", *inodes, translatable=False)
self.set_source_info(para)
node.append(para)
if self.content:
node += self.parse_content_to_nodes()

classes = ["versionmodified", versionlabel_classes[name]]
if len(node) > 0 and isinstance(node[0], nodes.paragraph):
if node[0].rawsource:
content = nodes.inline(node[0].rawsource, translatable=True)
content.source = node[0].source
content.line = node[0].line
content += node[0].children
node[0].replace_self(nodes.paragraph("", "", content, translatable=False))
para = node[0]
para.insert(0, nodes.inline("", "%s: " % text, classes=classes))
elif len(node) > 0:
para = nodes.paragraph("", "", nodes.inline("", "%s: " % text, classes=classes), translatable=False)
node.insert(0, para)
else:
para = nodes.paragraph("", "", nodes.inline("", "%s." % text, classes=classes), translatable=False)
node.append(para)

self.env.domains.changeset_domain.note_changeset(node)

return [node, *messages]


def setup(app):
app.add_css_file("custom.css")
app.add_directive("deprecated", DeprecatedNoVersion, override=True)
21 changes: 20 additions & 1 deletion swvo/io/RBMDataSet/RBMDataSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from __future__ import annotations

import datetime as dt
import logging
import warnings
from datetime import timedelta, timezone
from pathlib import Path
from typing import Any, Literal, cast
Expand Down Expand Up @@ -45,10 +47,23 @@
)
from swvo.io.utils import enforce_utc_timezone

logger = logging.getLogger(__name__)

_DEPRECATION_MESSAGE = (
"RBMDataSet is deprecated; RBM dataset handling has moved to el_paso "
"(https://github.com/GFZ/EL_PASO). This class is kept for backward compatibility only."
)


class RBMDataSet:
"""RBMDataSet class supporting .mat, .pickle, and .nc file formats.

.. deprecated::

RBM dataset handling has moved to
`el_paso <https://github.com/GFZ/EL_PASO>`_. This class is kept here only
for backward compatibility and will not receive new features.

This unified class handles loading RBM (Radiation Belt Model) data from multiple
file formats. It can load data either from files or from a dictionary.

Expand Down Expand Up @@ -139,6 +154,8 @@ def __init__(
verbose: bool = True,
enable_dict_loading: bool = False,
) -> None:
warnings.warn(_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2)

self.possible_variables: list[str] = list(VariableLiteral.__args__)

# Handle satellite conversion with special cases for GOES
Expand Down Expand Up @@ -601,7 +618,9 @@ def get_different_variables(self, rbm_other: RBMDataSet) -> list[str]:

return different_vars

from .bin_and_interpolate_to_model_grid import bin_and_interpolate_to_model_grid # noqa: I001
from .bin_and_interpolate_to_model_grid import ( # noqa: I001
bin_and_interpolate_to_model_grid,
)
from .identify_orbits import identify_orbits
from .interp_functions import interp_flux, interp_psd
from .linearize_trajectories import linearize_trajectories
8 changes: 8 additions & 0 deletions swvo/io/RBMDataSet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
#
# SPDX-License-Identifier: Apache-2.0

"""RBM dataset loading utilities.

.. deprecated::

This subpackage is deprecated. RBM dataset handling now lives in
`el_paso <https://github.com/GFZ/EL_PASO>`_. It is kept here only for
backward compatibility and will not receive new features.
"""

from swvo.io.RBMDataSet.custom_enums import (
FolderTypeEnum as FolderTypeEnum,
Expand Down
10 changes: 10 additions & 0 deletions swvo/io/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ def read(self, *args, **kwargs) -> pd.DataFrame | list[pd.DataFrame]:
-------
pd.DataFrame or list[pd.DataFrame]
Data for the specified parameters.

Examples
--------
>>> reader = SomeConcreteReader(data_dir="/path/to/data")
>>> data = reader.read(start_time, end_time, download=True)
"""
pass

Expand All @@ -159,5 +164,10 @@ def download_and_process(self, *args, **kwargs) -> None:
Returns
-------
None

Examples
--------
>>> reader = SomeConcreteReader(data_dir="/path/to/data")
>>> reader.download_and_process(start_time, end_time)
"""
pass
5 changes: 5 additions & 0 deletions swvo/io/dst/omni.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ def read( # ty: ignore[invalid-method-override]
-------
:class:`pandas.DataFrame`
OMNI DST data.

Examples
--------
>>> reader = DSTOMNI(data_dir="/path/to/omni_low_res")
>>> reader.read(start_time, end_time, download=True)
"""
data_out = super().read(start_time, end_time, download=download, variables="dst")
data_out.index.name = "t"
Expand Down
2 changes: 2 additions & 0 deletions swvo/io/dst/read_dst_from_multiple_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# SPDX-License-Identifier: Apache-2.0

"""Function to read Dst from multiple models."""

from __future__ import annotations

import logging
Expand Down
10 changes: 10 additions & 0 deletions swvo/io/dst/wdc.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ def download_and_process(self, start_time: datetime, end_time: datetime, reproce
Returns
-------
None

Examples
--------
>>> reader = DSTWDC(data_dir="/path/to/wdc")
>>> reader.download_and_process(start_time, end_time)
"""

start_time = enforce_utc_timezone(start_time)
Expand Down Expand Up @@ -228,6 +233,11 @@ def read(self, start_time: datetime, end_time: datetime, download: bool = False)
-------
:class:`pandas.DataFrame`
WDC Dst data.

Examples
--------
>>> reader = DSTWDC(data_dir="/path/to/wdc")
>>> reader.read(start_time, end_time, download=True)
"""

start_time = enforce_utc_timezone(start_time)
Expand Down
6 changes: 4 additions & 2 deletions swvo/io/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
#
# SPDX-License-Identifier: Apache-2.0

"""Shared exception types raised by swvo.io readers."""


class ModelError(Exception):
pass
"""Raised when a model passed to a multi-model reader is unknown or incompatible."""


class VariableNotFoundError(Exception):
pass
"""Raised when a requested variable is not available from a reader."""
5 changes: 5 additions & 0 deletions swvo/io/f10_7/omni.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def read( # ty: ignore[invalid-method-override]
-------
:class:`pandas.DataFrame`
F10.7 from OMNI Low Resolution data.

Examples
--------
>>> reader = F107OMNI(data_dir="/path/to/omni_low_res")
>>> reader.read(start_time, end_time, download=True)
"""

data_out = super().read(start_time, end_time, download=download, variables="f107")
Expand Down
2 changes: 2 additions & 0 deletions swvo/io/f10_7/read_f107_from_multiple_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# SPDX-License-Identifier: Apache-2.0

"""Function to read F10.7 from multiple models."""

from __future__ import annotations

import logging
Expand Down
10 changes: 10 additions & 0 deletions swvo/io/f10_7/swpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ def download_and_process(self) -> None:
Returns
-------
None

Examples
--------
>>> reader = F107SWPC(data_dir="/path/to/rt_swpc_f107")
>>> reader.download_and_process()
"""
temp_dir = Path("./temp_f107")
temp_dir.mkdir(exist_ok=True)
Expand Down Expand Up @@ -212,6 +217,11 @@ def read(self, start_time: datetime, end_time: datetime, *, download: bool = Fal
------
ValueError
Raises ValueError if `start_time` is `after end_time`.

Examples
--------
>>> reader = F107SWPC(data_dir="/path/to/rt_swpc_f107")
>>> reader.read(start_time, end_time, download=True)
"""

if start_time > end_time:
Expand Down
47 changes: 47 additions & 0 deletions swvo/io/hp/ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#
# SPDX-License-Identifier: Apache-2.0

"""
Module for handling SWIFT Hp ensemble data.
"""

from __future__ import annotations

import logging
Expand Down Expand Up @@ -102,6 +106,11 @@ def read(self, start_time: datetime, end_time: datetime) -> list[pd.DataFrame]:
------
FileNotFoundError
Returns `FileNotFoundError` if no ensemble file is found for the requested date.

Examples
--------
>>> reader = Hp30Ensemble(data_dir="/path/to/hp30_ensemble")
>>> reader.read(start_time, end_time)
"""
if start_time is not None:
start_time = enforce_utc_timezone(start_time)
Expand Down Expand Up @@ -198,6 +207,34 @@ def _ensemble_file_list(self, str_date: str) -> list[Path]:
return file_list

def read_with_horizon(self, start_time: datetime, end_time: datetime, horizon: Number) -> list[pd.DataFrame]:
"""Read Ensemble Hp forecast data for a given time range and forecast horizon.

Parameters
----------
start_time : datetime
Start time of the period for which to read the data.
end_time : datetime
End time of the period for which to read the data.
horizon : int | float
Forecast horizon (in hours).

Returns
-------
list[:class:`pandas.DataFrame`]
A list of data frames containing ensemble data for the requested period.

Raises
------
ValueError
Raises `ValueError` if `start_time` is not before `end_time`, if the
horizon is not between 0 and 72 hours, or if the horizon does not
match the index's required increment (0.5 hours for hp30, 1 hour for hp60).

Examples
--------
>>> reader = Hp30Ensemble(data_dir="/path/to/hp30_ensemble")
>>> reader.read_with_horizon(start_time, end_time, horizon=24)
"""
if start_time is not None:
start_time = enforce_utc_timezone(start_time)
if end_time is not None:
Expand Down Expand Up @@ -361,6 +398,11 @@ def read_with_horizon(self, start_time: datetime, end_time: datetime, horizon: f
Raises `ValueError` if the horizon is not between 0 and 72 hours.
ValueError
Raises `ValueError` if the horizon is not in 0.5 hour increments.

Examples
--------
>>> reader = Hp30Ensemble(data_dir="/path/to/hp30_ensemble")
>>> reader.read_with_horizon(start_time, end_time, horizon=24)
"""
return super().read_with_horizon(start_time, end_time, horizon)

Expand Down Expand Up @@ -402,5 +444,10 @@ def read_with_horizon(self, start_time: datetime, end_time: datetime, horizon: i
Raises `ValueError` if the horizon is not between 0 and 72 hours.
ValueError
Raises `ValueError` if the horizon is not in 1 hour increments.

Examples
--------
>>> reader = Hp60Ensemble(data_dir="/path/to/hp60_ensemble")
>>> reader.read_with_horizon(start_time, end_time, horizon=24)
"""
return super().read_with_horizon(start_time, end_time, horizon)
14 changes: 14 additions & 0 deletions swvo/io/hp/gfz.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#
# SPDX-License-Identifier: Apache-2.0

"""
Module for handling GFZ Hp data.
"""

from __future__ import annotations

import json
Expand Down Expand Up @@ -100,6 +104,11 @@ def download_and_process(
Returns
-------
None

Examples
--------
>>> reader = Hp30GFZ(data_dir="/path/to/hp_gfz")
>>> reader.download_and_process(start_time, end_time)
"""
temporary_dir = Path("./temp_hp_wget")
temporary_dir.mkdir(exist_ok=True, parents=True)
Expand Down Expand Up @@ -193,6 +202,11 @@ def read(self, start_time: datetime, end_time: datetime, *, download: bool = Fal
-------
:class:`pandas.DataFrame`
HpGFZ data for the given time range.

Examples
--------
>>> reader = Hp30GFZ(data_dir="/path/to/hp_gfz")
>>> reader.read(start_time, end_time, download=True)
"""
if start_time > end_time:
msg = "start_time must be before end_time"
Expand Down
2 changes: 2 additions & 0 deletions swvo/io/hp/read_hp_from_multiple_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ def read_hp_from_multiple_models(
End time of the data request.
model_order : Sequence, optional
Order in which data will be read from the models, defaults to [OMNI, Niemegk, Ensemble, SWPC].
hp_index : str, optional
Hp index to read. Possible options are: hp30, hp60. Defaults to "hp30".
reduce_ensemble : {"mean", "median"} or None, optional
The method to reduce ensembles to a single time series ("mean" or "median"), defaults to None.
historical_data_cutoff_time : datetime, optional
Expand Down
Loading
Loading