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
44 changes: 44 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Unit Tests

on:
push:
schedule:
- cron: "0 2 * * 0"
workflow_dispatch:

permissions:
contents: read

jobs:
unit-tests:
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
cache: pip
cache-dependency-path: |
requirements/dev-requirements.txt

- name: Upgrade pip
run: python -m pip install --upgrade pip

- name: Install development dependencies
run: python -m pip install -r requirements/dev-requirements.txt

- name: Install unit-test runtime dependencies
run: |
python -m pip install "numpy<2" xarray matplotlib cmocean gsw
python -m pip install "https://github.com/sdat2/pyxpcm/archive/sof-agu.zip"
python -m pip install --upgrade "numpy<2"

- name: Run unit tests
env:
MPLBACKEND: Agg
run: python -m unittest discover -s src/tests -p "test_*.py" -v
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,23 @@ of individual eddy-like features (such as the Agulhas rings).
make env
```

or with `micromamba`

```bash
micromamba create -f requirements/environment.yml -p ./env
```

- Activate the environment in conda:

```bash
conda activate ./env
```
```bash
conda activate ./env

micromamba activate ./env
```

```bash
micromamba activate ./env
```

- Change the settings in `src.constants` to set download location etc.

Expand Down
2 changes: 1 addition & 1 deletion requirements/dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# As a standard they include certain formatters and linters.

# local package
-e ../.
-e .

# external requirements (mostly linters and formatters)
flake8 # flake8 linter
Expand Down
4 changes: 2 additions & 2 deletions requirements/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ channels:
dependencies:
- python=3.8
- xarray==0.15
- cartopy
- matplotlib==3.2.2
- cartopy==0.18
- matplotlib
- pip
- pip:
- -r dev-requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion requirements/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ wandb
xarray==0.15
netcdf4
scikit-learn
matplotlib==3.2.2
matplotlib

# pynio
numba
Expand Down
2 changes: 1 addition & 1 deletion src/animate.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Animate da."""
"""Animate dataarray."""
import os
from typing import Callable
import numpy as np
Expand Down
89 changes: 53 additions & 36 deletions src/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,67 @@

# Place all your constants here
import os
from typing import Literal, List, Dict
import numpy as np
import pathlib
from sys import platform
import cmocean.cm as cmo

# Note: constants should be UPPER_CASE

# Basic location defaults, to be referenced from here:
constants_path = os.path.realpath(__file__)
SRC_PATH = os.path.dirname(constants_path)
PROJECT_PATH = os.path.dirname(SRC_PATH)
DATA_PATH = os.path.join(PROJECT_PATH, "nc")
FIGURE_PATH = os.path.join(PROJECT_PATH, "figures")
KO_PATH = os.path.join(SRC_PATH, "data", "kim_(&orsi)_altimetric_fronts")
# TODO move some of these to a config file.

# Data directory on GWS
GWS_DATA_DIR = pathlib.Path("/gws/nopw/j04/ai4er/users/sdat2/OLD")
# Basic location defaults, to be referenced from here:
constants_path: str = os.path.realpath(__file__)
SRC_PATH: str = os.path.dirname(constants_path)
PROJECT_PATH: str = os.path.dirname(SRC_PATH)
DATA_PATH: str = os.path.join(PROJECT_PATH, "nc")
FIGURE_PATH: str = os.path.join(PROJECT_PATH, "figures")
KO_PATH: str = os.path.join(SRC_PATH, "data", "kim_(&orsi)_altimetric_fronts")

# Figure type
FIGURE_TYPE = ".png"
FIGURE_TYPE: Literal[".png", ".pdf"] = ".png"

# start ****DATA LOCATION section***
# This will certainly need to be changed on your macine
# This will certainly need to be changed on your machine
GEN_ROOT: str = DATA_PATH
DEFAULT_NC: str = os.path.join(GEN_ROOT, "i-metric-joint-k-5-d-3.nc")

# Paths to BSOSE (unique to Jasmin)
# Keep the historical Linux vs Darwin defaults, but prefer folders that
# already exist so the code remains robust when moved between machines.
if platform in ["Linux", "linux"]:
GEN_DATA_PATH: str = os.path.join(GWS_DATA_DIR, "bsose_data")
BSOSE_PATH: str = os.path.join(GEN_DATA_PATH, "bsose_stuv")
DEFAULT_NC: str = (
str(GWS_DATA_DIR) + "/nc/i-metric-joint-k-5-d-3.nc" # not valid in jasmin.
)

# Paths to different BSOSE-i106 files (unique to my machine):
elif platform in ["Darwin", "darwin"]:
BSOSE_PATH: str = os.path.join("/Users", "simon", "bsose_monthly")
GEN_DATA_PATH: str = BSOSE_PATH
DEFAULT_NC: str = (
"~/pyxpcm_sithom/nc/i-metric-joint-k-5-d-3.nc" # not valid in jasmin.
)

_preferred_data_dirs = [
os.path.join(GEN_ROOT, "bsose_data"),
os.path.join(GEN_ROOT, "bsose_monthly"),
]
else:
assert False
_preferred_data_dirs = [
os.path.join(GEN_ROOT, "bsose_monthly"),
os.path.join(GEN_ROOT, "bsose_data"),
]

GEN_DATA_PATH: str = next(
(path for path in _preferred_data_dirs if os.path.isdir(path)),
_preferred_data_dirs[0],
)

_bsose_candidates = [
os.path.join(GEN_DATA_PATH, "bsose_stuv"),
GEN_DATA_PATH,
]
BSOSE_PATH: str = next(
(path for path in _bsose_candidates if os.path.isdir(path)),
_bsose_candidates[0],
)

# end ****DATA LOCATION section***


os.makedirs(DATA_PATH, exist_ok=True)
os.makedirs(FIGURE_PATH, exist_ok=True)
os.makedirs(KO_PATH, exist_ok=True)
os.makedirs(GEN_DATA_PATH, exist_ok=True)
os.makedirs(BSOSE_PATH, exist_ok=True)

# Salt, Theta, Uvel, Vvel
SALT_FILE: str = os.path.join(BSOSE_PATH, "bsose_i106_2008to2012_monthly_Salt.nc")
THETA_FILE: str = os.path.join(BSOSE_PATH, "bsose_i106_2008to2012_monthly_Theta.nc")
Expand All @@ -66,9 +82,9 @@

# Particular names within BSOSE-i106
DEPTH_NAME: str = D_COORD
USELESS_LIST: list = ["iter", "Depth", "rA", "drF", "hFacC"] # list of variables from BSOSE to discard before processing
VAR_NAME_LIST: list = ["SALT", "THETA"] # variables used in to fit the pcm model on
FEATURES_D: dict = {"THETA": "THETA", "SALT": "SALT"} # Mapping for within pyxpcm
USELESS_LIST: List[str] = ["iter", "Depth", "rA", "drF", "hFacC"] # list of variables from BSOSE to discard before processing
VAR_NAME_LIST: List[str] = ["SALT", "THETA"] # variables used in to fit the pcm model on
FEATURES_D: Dict[str, str] = {"THETA": "THETA", "SALT": "SALT"} # Mapping for within pyxpcm

# Naming of intermediate files
INTERP_FILE_NAME: str = os.path.join(DATA_PATH, "interp.nc")
Expand All @@ -82,7 +98,7 @@
# random variables used locally to make it reproducible.
MIN_DEPTH: float = 300 # the depth of the minimum cut off (m)
MAX_DEPTH: float = 2000 # the depth of the maximum cut off (m)
K_LIST: list = [5, 4, 2, 10] # K's to make when running batch script.
K_LIST: List[int] = [5, 4, 2, 10] # K's to make when running batch script.
K_CLUSTERS: int = 5 # number of clusters for the main example figure.
D_PCS: int = 3 # number of principal components to be used.
EXAMPLE_TIME_INDEX: int = 40 # the default time to go for.
Expand All @@ -96,9 +112,10 @@
CLUST_COLORS: str = "Set1" # "Dark1"

# Move plots to location
FINAL_LOC: str = "../FBSO/images"

FINAL_LOC: str = os.path.join(PROJECT_PATH, "images") # "../FBSO/images"
os.makedirs(FINAL_LOC, exist_ok=True)

# infor for profile plots
ZS = [-x for x in range(300, 2000, 10)] # Z levels.
LZ = len(ZS) # number of Z levels.
# info for profile plots
ZS: List[int] = [-x for x in range(300, 2000, 10)] # Z levels.
LZ: int = len(ZS) # number of Z levels.
43 changes: 13 additions & 30 deletions src/data_loading/io_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def return_pair_i_metric(
pca (int, optional): Number of principal components. Defaults to cst.D_PCS.
save_nc (bool, optional): Whether or not to save the resulting dataset.
Defaults to True.
t_index (int, optional): time index cst.EXAMPLE_TIME_INDEX.
t_index (int, optional): Time index cst.EXAMPLE_TIME_INDEX.

Returns:
xr.DataArray: pair i metric.
Expand Down Expand Up @@ -57,12 +57,9 @@ def return_name(k_clusters: int, pca_components: int) -> str:
Returns:
str: file names.
"""
return (
str(cst.GWS_DATA_DIR)
+ "/nc/i-metric-joint-k-"
+ str(k_clusters)
+ "-d-"
+ str(pca_components)
return os.path.join(
cst.DATA_PATH,
"i-metric-joint-k-" + str(k_clusters) + "-d-" + str(pca_components),
)


Expand All @@ -76,17 +73,13 @@ def return_plot_folder(k_clusters: int, pca_components: int) -> str:
Returns:
str: file names.
"""
folder = (
"../FBSO-Report/"
+ "images/i-metric-joint-k-"
+ str(k_clusters)
+ "-d-"
+ str(pca_components)
+ "/"
folder = os.path.join(
cst.FIGURE_PATH,
"i-metric-joint-k-" + str(k_clusters) + "-d-" + str(pca_components),
)
if not os.path.exists(folder):
os.makedirs(folder)
return folder
return os.path.join(folder, "")


def return_folder(k_clusters: int, pca_components: int) -> str:
Expand All @@ -100,7 +93,7 @@ def return_folder(k_clusters: int, pca_components: int) -> str:
str: file names.

"""
folder = return_name(k_clusters, pca_components) + "/"
folder = os.path.join(return_name(k_clusters, pca_components), "")
if not os.path.exists(folder):
os.makedirs(folder)
return folder
Expand All @@ -117,12 +110,9 @@ def _return_pair_name(k_clusters: int, pca_components: int) -> str:
str: file names.

"""
return (
str(cst.GWS_DATA_DIR)
+ "nc/pair-i-metric-k-"
+ str(k_clusters)
+ "-d-"
+ str(pca_components)
return os.path.join(
cst.DATA_PATH,
"pair-i-metric-k-" + str(k_clusters) + "-d-" + str(pca_components),
)


Expand All @@ -137,14 +127,7 @@ def _return_pair_folder(k_clusters: int, pca_components: int) -> str:
str: file names.

"""
folder = (
str(cst.GWS_DATA_DIR)
+ "/nc/pair-i-metric-k-"
+ str(k_clusters)
+ "-d-"
+ str(pca_components)
+ "/"
)
folder = os.path.join(_return_pair_name(k_clusters, pca_components), "")
if not os.path.exists(folder):
os.makedirs(folder)
return folder
1 change: 0 additions & 1 deletion src/data_loading/xr_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ def _old_order_indexes(dataarray: xr.DataArray, index_list: list) -> np.ndarray:

Returns:
np.ndarray: dataarray_values.

"""

coords_list = []
Expand Down
5 changes: 3 additions & 2 deletions src/make_figures.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Make figures: run through all the paper figures and make them.
"""
Make figures: run through all the paper figures and make them.

Takes roughly 5 minutes the first time it is run.
"""
Expand All @@ -23,7 +24,7 @@


@twr.timeit
def make_all_figures():
def make_all_figures() -> None:
"""
Make all the figures in the paper in a sequence.

Expand Down
Loading
Loading