Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9e52dba
Add initial DataLoader ABC and NetCDFDataLoader implementation.
oj-tooth Apr 28, 2026
cb23d10
Add initial DataWriter ABC and NetCDFDataWriter implementation.
oj-tooth Apr 28, 2026
71f1479
Add initial ObsSampler & ErrorKernel ABCs and TestObsSampler & TestEr…
oj-tooth Apr 28, 2026
e7f03b0
Add initial Regridder ABC and TestRegridder implementation.
oj-tooth Apr 28, 2026
de4240f
Add initial OceanOSSE pipeline run and describe drivers & utility fun…
oj-tooth Apr 28, 2026
3ae7e80
Add initial Pydantic validation for OceanOSSE configuration .toml files.
oj-tooth Apr 28, 2026
1b57004
Update OceanOSSE CLI & __init__ with latest modules.
oj-tooth Apr 28, 2026
6b46b89
Add example_config.toml configuration file to perform a dummy-run of …
oj-tooth Apr 28, 2026
5ae14ba
Update pyproject.toml and pixi.toml to include new dependencies and a…
oj-tooth Apr 28, 2026
a00910e
Adding climatology calculator
b-barton May 13, 2026
a182ed1
Testing climatology
b-barton May 13, 2026
e58218c
Adding regridder class
b-barton May 13, 2026
e7b8450
Changed to monthday which deals with leap days
b-barton May 13, 2026
97ac4eb
Test now has criteria for getting the same mean and a single value
b-barton May 13, 2026
9460187
Moving climatology to init
b-barton May 13, 2026
6fac8d0
Added to regrid to insert profiles at model indices
b-barton May 13, 2026
210779e
Started a test for regrid
b-barton May 13, 2026
b62f596
Gridded data now gets replaced with profiles
b-barton May 13, 2026
0b6eb00
Test for climatology being replaced with profiles
b-barton May 13, 2026
b7f2d3b
Removing matplotlib from test
b-barton May 13, 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
26 changes: 18 additions & 8 deletions OceanOSSE/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
"""
OceanOSSE

Python toolbox for performing Observing System Simulation Experiments (OSSEs) in ocean general circulation models.
Python toolbox for performing Observing System Simulation Experiments (OSSEs)
in ocean general circulation models.
"""

__author__ = "Ollie Tooth (oliver.tooth@noc.ac.uk)"
__credits__ = "National Oceanography Centre (NOC), Southampton, UK"

from importlib.metadata import version as _version

from OceanOSSE import (
cli,
pipeline,
)
from OceanOSSE import cli, pipeline
from OceanOSSE.gridding.regridder import Regridder
from OceanOSSE.io.dataloader import DataLoader
from OceanOSSE.io.datawriter import DataWriter
from OceanOSSE.sampling.sampler import ErrorKernel, ObsSampler
from OceanOSSE.gridding.regridder_simple import SwapRegridder

try:
__version__ = _version("OceanOSSE")
except Exception:
# Local copy or not installed with setuptools.
# Disable minimum version checks on downstream libraries.
__version__ = "9999.0.0"

__all__ = ("cli", "pipeline")
__all__ = (
"cli",
"pipeline",
"DataLoader",
"DataWriter",
"ErrorKernel",
"ObsSampler",
"Regridder",
)
117 changes: 116 additions & 1 deletion OceanOSSE/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,119 @@
Created By: Ollie Tooth (oliver.tooth@noc.ac.uk)
"""

# -- Import Dependencies -- #
# -- Import dependencies -- #
import logging
import sys

import typer
from typing_extensions import Annotated, Optional

from OceanOSSE.pipeline import describe_pipeline, run_pipeline

from .__init__ import __version__

app = typer.Typer()
logger = logging.getLogger(__name__)


# -- Define CLI Functions -- #
def create_header(
config_path: str,
log_path: str,
) -> None:
"""
Add OceanOSSE header to log.

Parameters:
-----------
config_path : str
Filepath to OceanOSSE config .toml file.
log_path : str
Filepath to OceanOSSE log file.
"""
logger.info(
f"""
╔══════════════════════════════════════════════════════════════╗
║ OceanOSSE ║
║ Ocean Observing System Simulation Experiment Tool ║
╠══════════════════════════════════════════════════════════════╣
OceanOSSE Version : {__version__}
Python Version : {sys.version.split()[0]}
Config File : {config_path}
Log File : {log_path}
╚══════════════════════════════════════════════════════════════╝
""",
extra={"simple": True},
)


def init_logging(log_path: str) -> None:
"""
Initialise OceanOSSE logging.

Parameters:
-----------
log_path : str
Filepath to log file. If None, logs to 'ocean_osse.log'.
"""
# === Validate Inputs === #
if not isinstance(log_path, str):
raise TypeError("log_path must be a string.")

logging.basicConfig(
format="⦿══⦿ OceanOSSE ⦿══⦿ ║ %(levelname)10s ║ %(asctime)s ║ %(message)s",
level=logging.INFO,
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[logging.FileHandler(log_path), logging.StreamHandler()],
)


# === Create Typer App === #
@app.callback()
def main() -> None:
"""
Main callback for Typer app to allow
single run command to be defined.
"""
pass


@app.command()
def run(
config: Annotated[str, typer.Argument(help="Path to OceanOSSE config .toml file")],
log: Annotated[
Optional[str],
typer.Option(
help="Path to write OceanOSSE log file", rich_help_panel="Options"
),
] = "ocean_osse.log",
dry_run: Annotated[
Optional[bool],
typer.Option(
help="Describe OceanOSSE workflow without execution.",
rich_help_panel="Options",
),
] = False,
) -> None:
"""
Run OceanOSSE workflow defined by configuration (.toml) file in current process.
"""
# === Initialise Logging === #
init_logging(log_path=log)
create_header(config_path=config, log_path=log)

# === Run OceanOSSE === #
args = {
"config_file": config,
"log_filepath": log,
}
if dry_run:
describe_pipeline(args=args)
else:
run_pipeline(args=args)

logging.info("✔ OceanOSSE Completed ✔")


if __name__ == "__main__":
app()
122 changes: 122 additions & 0 deletions OceanOSSE/gridding/regridder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""
regridder.py

Description: Regridding module for OceanOSSE package.

Created By: OceanOSSE Development Team (NOC, UK)
"""

# -- Import Dependencies -- #
from __future__ import annotations

import abc
import logging
from typing import Self

import xarray as xr

logger = logging.getLogger(__name__)


# -- Regridder Abstract Base Class -- #
class Regridder(abc.ABC):
"""
Abstract base class for regridding synthetic ocean observations onto
the original model grid, using methods such as objective analysis
or interpolation.

Parameters
----------
target_grid : xarray.Dataset or None, optional
Dataset describing the target grid (coordinates, masks, etc.).
"""

def __init__(
self,
target_grid: xr.Dataset | None = None,
) -> None:
if target_grid is not None and not isinstance(target_grid, xr.Dataset):
raise TypeError("``target_grid`` must be an xarray.Dataset or None.")
self._target_grid = target_grid

def __repr__(self) -> str:
has_grid = self._target_grid is not None
return f"{type(self).__name__}(target_grid={'<Dataset>' if has_grid else None})"

@classmethod
@abc.abstractmethod
def from_config(cls, config: dict) -> Self:
"""
Construct a Regridder from the from the `[regridding]` table of
the .toml configuration file.

Parameters
----------
config : dict
Configuration dictionary containing input parameters from .toml
configuration file.

Returns
-------
Self
Initialised Regridder instance.
"""
...

@abc.abstractmethod
def regrid(self, ds: xr.Dataset) -> xr.Dataset:
"""
Regrid the synthetic observation dataset onto the target grid.

Parameters
----------
ds : xarray.Dataset
Synthetic observations dataset.

Returns
-------
xarray.Dataset
Dataset of synthetic observations regridded onto target grid.
"""
...


# -- Regridder Implementations -- #


class TestRegridder(Regridder):
"""
Regridder used for testing and scaffold validation.

Returns the the synthetic observations dataset unchanged.
"""

@classmethod
def from_config(cls, config: dict) -> Self:
"""
Instantiate a TestRegridder from the `[regridding]` table of
the .toml configuration file.
"""
return cls()

def regrid(self, ds: xr.Dataset) -> xr.Dataset:
"""
Regrid the synthetic observation dataset onto the target grid.

Parameters
----------
ds : xarray.Dataset
Synthetic observations dataset.

Returns
-------
xarray.Dataset
Dataset of synthetic observations (unchanged from input).
"""
logger.debug(
"Regridding synthetic observations with TestRegridder -> returns input dataset unchanged."
)
logging.info(
"--> Completed: Regridded synthetic observations with TestRegridder."
)
return ds
Loading
Loading