marEx 4.0__tar.gz → 4.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- marex-4.0.3/.codecov.yml +34 -0
- {marex-4.0 → marex-4.0.3}/.github/workflows/ci.yml +5 -0
- {marex-4.0/marEx.egg-info → marex-4.0.3}/PKG-INFO +1 -1
- marex-4.0.3/examples/batch jobs/run_detect.py +91 -0
- marex-4.0.3/examples/batch jobs/run_track.py +131 -0
- marex-4.0.3/examples/batch jobs/submit_track.sh +79 -0
- {marex-4.0 → marex-4.0.3}/marEx/__init__.py +5 -0
- {marex-4.0 → marex-4.0.3}/marEx/detect.py +213 -78
- {marex-4.0 → marex-4.0.3}/marEx/helper.py +185 -6
- {marex-4.0 → marex-4.0.3/marEx.egg-info}/PKG-INFO +1 -1
- {marex-4.0 → marex-4.0.3}/marEx.egg-info/SOURCES.txt +4 -0
- {marex-4.0 → marex-4.0.3}/tests/conftest.py +6 -0
- {marex-4.0 → marex-4.0.3}/tests/test_detect_detrending.py +1 -1
- {marex-4.0 → marex-4.0.3}/tests/test_error_handling.py +30 -0
- {marex-4.0 → marex-4.0.3}/tests/test_track_edge_cases.py +2 -5
- {marex-4.0 → marex-4.0.3}/.github/workflows/README.md +0 -0
- {marex-4.0 → marex-4.0.3}/.github/workflows/release.yml +0 -0
- {marex-4.0 → marex-4.0.3}/.github/workflows/validate.py +0 -0
- {marex-4.0 → marex-4.0.3}/.readthedocs.yaml +0 -0
- {marex-4.0 → marex-4.0.3}/CITATION.cff +0 -0
- {marex-4.0 → marex-4.0.3}/CONTRIBUTING.md +0 -0
- {marex-4.0 → marex-4.0.3}/MANIFEST.in +0 -0
- {marex-4.0 → marex-4.0.3}/README.md +0 -0
- {marex-4.0 → marex-4.0.3}/examples/gridded data/01_preprocess_extremes.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/gridded data/02_id_track_events.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/gridded data/03_visualise_events.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/regional data/01_preprocess_extremes.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/regional data/02_id_track_events.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/regional data/03_visualise_events.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/unstructured data/01_preprocess_extremes.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/unstructured data/02_id_track_events.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/examples/unstructured data/03_visualise_events.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/_coverage_init.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/_dependencies.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/exceptions.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/logging_config.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/plotX/__init__.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/plotX/base.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/plotX/gridded.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/plotX/unstructured.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx/track.py +0 -0
- {marex-4.0 → marex-4.0.3}/marEx.egg-info/dependency_links.txt +0 -0
- {marex-4.0 → marex-4.0.3}/marEx.egg-info/requires.txt +0 -0
- {marex-4.0 → marex-4.0.3}/marEx.egg-info/top_level.txt +0 -0
- {marex-4.0 → marex-4.0.3}/pyproject.toml +0 -0
- {marex-4.0 → marex-4.0.3}/setup.cfg +0 -0
- {marex-4.0 → marex-4.0.3}/tests/__init__.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/coverage_config.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/make_test_data.ipynb +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_detect_helpers.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_exceptions.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_gridded_preprocessing.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_gridded_tracking.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_integration.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_logging_system.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_plotx.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_track_helpers.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_unstructured_preprocessing.py +0 -0
- {marex-4.0 → marex-4.0.3}/tests/test_unstructured_tracking.py +0 -0
marex-4.0.3/.codecov.yml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Codecov configuration for marEx
|
|
2
|
+
# https://docs.codecov.com/docs/codecov-yaml
|
|
3
|
+
|
|
4
|
+
coverage:
|
|
5
|
+
status:
|
|
6
|
+
# Overall project coverage
|
|
7
|
+
project:
|
|
8
|
+
default:
|
|
9
|
+
target: 95% # Maintain 95% overall project coverage
|
|
10
|
+
threshold: 1%
|
|
11
|
+
if_ci_failed: error
|
|
12
|
+
|
|
13
|
+
# Coverage for new code in patches/PRs - disabled
|
|
14
|
+
patch:
|
|
15
|
+
default:
|
|
16
|
+
enabled: false # Do not enforce patch coverage requirements
|
|
17
|
+
|
|
18
|
+
# Comment configuration
|
|
19
|
+
comment:
|
|
20
|
+
layout: "reach,diff,flags,tree"
|
|
21
|
+
behavior: default
|
|
22
|
+
require_changes: false
|
|
23
|
+
require_base: false
|
|
24
|
+
require_head: true
|
|
25
|
+
|
|
26
|
+
# Ignore paths
|
|
27
|
+
ignore:
|
|
28
|
+
- "tests/"
|
|
29
|
+
- "docs/"
|
|
30
|
+
- "examples/"
|
|
31
|
+
- "setup.py"
|
|
32
|
+
- "**/_dependencies.py"
|
|
33
|
+
- "**/_coverage_init.py"
|
|
34
|
+
- "**/plotX/unstructured.py"
|
|
@@ -64,6 +64,7 @@ jobs:
|
|
|
64
64
|
name: Test Suite
|
|
65
65
|
runs-on: ${{ matrix.os }}
|
|
66
66
|
needs: code-quality
|
|
67
|
+
timeout-minutes: 90 # Windows can be significantly slower than Linux/macOS
|
|
67
68
|
strategy:
|
|
68
69
|
fail-fast: false
|
|
69
70
|
matrix:
|
|
@@ -144,18 +145,22 @@ jobs:
|
|
|
144
145
|
pytest tests/test_logging_system.py -n 2 -v --tb=short
|
|
145
146
|
|
|
146
147
|
- name: Run preprocessing tests (gridded)
|
|
148
|
+
timeout-minutes: 30 # Windows can be slow for these tests
|
|
147
149
|
run: |
|
|
148
150
|
pytest tests/test_gridded_preprocessing.py -n 2 -v --tb=short
|
|
149
151
|
|
|
150
152
|
- name: Run preprocessing tests (unstructured)
|
|
153
|
+
timeout-minutes: 30 # Windows can be slow for these tests
|
|
151
154
|
run: |
|
|
152
155
|
pytest tests/test_unstructured_preprocessing.py -n 2 -v --tb=short
|
|
153
156
|
|
|
154
157
|
- name: Run tracking tests (gridded)
|
|
158
|
+
timeout-minutes: 30 # Windows can be slow for these tests
|
|
155
159
|
run: |
|
|
156
160
|
pytest tests/test_gridded_tracking.py -n 2 -v --tb=short
|
|
157
161
|
|
|
158
162
|
- name: Run tracking tests (unstructured)
|
|
163
|
+
timeout-minutes: 30 # Windows can be slow for these tests
|
|
159
164
|
run: |
|
|
160
165
|
pytest tests/test_unstructured_tracking.py -n 2 -v --tb=short
|
|
161
166
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Global Daily SST (OSTIA) Analysis: Identifying Marine Extremes with MarEx-Detect
|
|
4
|
+
|
|
5
|
+
Pre-Process with Shifting-Baseline & Hobday et al. (2016) Definition for Extremes
|
|
6
|
+
|
|
7
|
+
Run from login node - this script will launch SLURM jobs via Dask distributed cluster
|
|
8
|
+
|
|
9
|
+
NOTE: This script uses a distributed cluster because detect.py does not contain
|
|
10
|
+
Numba JIT-compiled functions that execute locally. Unlike run_track.py, this
|
|
11
|
+
approach works correctly for detection/preprocessing tasks. If you prefer to
|
|
12
|
+
follow HPC best practices and run everything in SLURM jobs, consider creating
|
|
13
|
+
a submit_detect.sh script similar to submit_track.sh.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from getpass import getuser
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
import xarray as xr
|
|
21
|
+
|
|
22
|
+
import marEx
|
|
23
|
+
import marEx.helper as hpc
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main():
|
|
27
|
+
"""Run MarEx preprocessing and extreme detection pipeline on distributed SLURM cluster."""
|
|
28
|
+
# Configuration from environment variables
|
|
29
|
+
n_workers = int(os.getenv("DASK_N_WORKERS", "128"))
|
|
30
|
+
workers_per_node = int(os.getenv("DASK_WORKERS_PER_NODE", "64"))
|
|
31
|
+
runtime = int(os.getenv("DASK_RUNTIME", "39"))
|
|
32
|
+
slurm_account = os.getenv("SLURM_ACCOUNT", "bk1377")
|
|
33
|
+
|
|
34
|
+
# Lustre Scratch Directory
|
|
35
|
+
scratch_dir = Path("/scratch") / getuser()[0] / getuser()
|
|
36
|
+
|
|
37
|
+
# Start Distributed Dask Cluster on SLURM
|
|
38
|
+
print("Starting distributed Dask cluster on SLURM...")
|
|
39
|
+
print(f" Workers: {n_workers}")
|
|
40
|
+
print(f" Workers per node: {workers_per_node}")
|
|
41
|
+
print(f" Runtime: {runtime} minutes")
|
|
42
|
+
print(f" SLURM account: {slurm_account}")
|
|
43
|
+
|
|
44
|
+
client = hpc.start_distributed_cluster(
|
|
45
|
+
n_workers=n_workers,
|
|
46
|
+
workers_per_node=workers_per_node,
|
|
47
|
+
runtime=runtime,
|
|
48
|
+
scratch_dir=scratch_dir / "clients",
|
|
49
|
+
account=slurm_account,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Choose optimal chunk size & load data
|
|
53
|
+
print("Loading data...")
|
|
54
|
+
file_name = scratch_dir / "mhws" / "ostia.zarr"
|
|
55
|
+
chunk_size = {"time": 30, "lat": 360, "lon": 720}
|
|
56
|
+
sst = xr.open_zarr(str(file_name), chunks=chunk_size).sst
|
|
57
|
+
print(f"Data loaded: {sst}")
|
|
58
|
+
|
|
59
|
+
# Process Data using MarEx-Detect helper functions:
|
|
60
|
+
print("Processing extremes data...")
|
|
61
|
+
extremes_ds = marEx.preprocess_data(
|
|
62
|
+
sst,
|
|
63
|
+
method_anomaly="shifting_baseline", # Anomalies from a rolling climatology using previous window_year years
|
|
64
|
+
method_extreme="hobday_extreme", # Local day-of-year specific thresholds with windowing
|
|
65
|
+
threshold_percentile=95, # Use the 95th percentile as the extremes threshold
|
|
66
|
+
window_year_baseline=15,
|
|
67
|
+
smooth_days_baseline=21, # Defines the rolling climatology window (15 years) and smoothing window (21 days)
|
|
68
|
+
window_days_hobday=11, # Defines the window (11 days) of compiled samples collected for extremes detection
|
|
69
|
+
dimensions={
|
|
70
|
+
"time": "time",
|
|
71
|
+
"x": "lon",
|
|
72
|
+
"y": "lat",
|
|
73
|
+
}, # Define the dimensions of the data -- if 'y' exists, MarEx-Detect knows this is a gridded dataset
|
|
74
|
+
dask_chunks={"time": 25}, # Dask chunks for *output* data
|
|
75
|
+
use_temp_checkpoints=True, # Enable checkpointing to prevent expensive recomputations
|
|
76
|
+
)
|
|
77
|
+
print(f"Processing complete: {extremes_ds}")
|
|
78
|
+
|
|
79
|
+
# Save Extremes Data to zarr for more efficient parallel I/O
|
|
80
|
+
print("Saving extremes data...")
|
|
81
|
+
output_file = scratch_dir / "mhws" / "extremes_binary_gridded_shifting_hobday_batch.zarr"
|
|
82
|
+
extremes_ds.to_zarr(output_file, mode="w")
|
|
83
|
+
print(f"Data saved to: {output_file}")
|
|
84
|
+
|
|
85
|
+
# Close the Dask cluster
|
|
86
|
+
client.close()
|
|
87
|
+
print("Processing complete!")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
main()
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Global Daily Event Analysis: Marine Heatwave ID & Tracking using MarEx
|
|
4
|
+
|
|
5
|
+
Performs morphological preprocessing, blob identification, temporal tracking,
|
|
6
|
+
and graph reduction to create globally unique IDs for each tracked extreme event.
|
|
7
|
+
|
|
8
|
+
This script should be run INSIDE a SLURM job (via sbatch submit_track.sh).
|
|
9
|
+
It uses a local Dask cluster that utilizes the compute resources allocated to the job.
|
|
10
|
+
This ensures that all computation, including Numba JIT-compiled functions, runs on
|
|
11
|
+
compute nodes rather than the login node.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
from getpass import getuser
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import xarray as xr
|
|
19
|
+
|
|
20
|
+
import marEx
|
|
21
|
+
import marEx.helper as hpc
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main():
|
|
25
|
+
"""Run MarEx event tracking pipeline on local Dask cluster within SLURM job allocation."""
|
|
26
|
+
# Configuration from environment variables
|
|
27
|
+
n_workers = int(os.getenv("DASK_N_WORKERS", "32"))
|
|
28
|
+
threads_per_worker = int(os.getenv("DASK_THREADS_PER_WORKER", "1"))
|
|
29
|
+
|
|
30
|
+
# Tracking configuration
|
|
31
|
+
run_basic = os.getenv("RUN_BASIC_TRACKER", "false").lower() == "true"
|
|
32
|
+
grid_resolution = float(os.getenv("GRID_RESOLUTION", "0.25"))
|
|
33
|
+
area_filter = int(os.getenv("AREA_FILTER", "600"))
|
|
34
|
+
r_fill = int(os.getenv("R_FILL", "12"))
|
|
35
|
+
t_fill = int(os.getenv("T_FILL", "4"))
|
|
36
|
+
overlap_threshold = float(os.getenv("OVERLAP_THRESHOLD", "0.25"))
|
|
37
|
+
|
|
38
|
+
# Lustre Scratch Directory
|
|
39
|
+
scratch_dir = Path("/scratch") / getuser()[0] / getuser()
|
|
40
|
+
|
|
41
|
+
# Start Local Dask Cluster
|
|
42
|
+
# This cluster runs within the SLURM job allocation, ensuring all computation
|
|
43
|
+
# (including Numba JIT-compiled functions) executes on compute nodes
|
|
44
|
+
print("Starting local Dask cluster within SLURM job allocation...")
|
|
45
|
+
print(f" Workers: {n_workers}")
|
|
46
|
+
print(f" Threads per worker: {threads_per_worker}")
|
|
47
|
+
|
|
48
|
+
client = hpc.start_local_cluster(
|
|
49
|
+
n_workers=n_workers,
|
|
50
|
+
threads_per_worker=threads_per_worker,
|
|
51
|
+
scratch_dir=scratch_dir / "clients",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Choose optimal chunk size & load preprocessed data
|
|
55
|
+
print("\nLoading preprocessed extremes data...")
|
|
56
|
+
input_file = scratch_dir / "mhws" / "extremes_binary_gridded_shifting_hobday_batch.zarr"
|
|
57
|
+
chunk_size = {"time": 25, "lat": -1, "lon": -1}
|
|
58
|
+
ds = xr.open_zarr(str(input_file), chunks=chunk_size)
|
|
59
|
+
print(f"Data loaded: {ds}")
|
|
60
|
+
|
|
61
|
+
# Run ID, Tracking, & Merging
|
|
62
|
+
print("\n" + "=" * 80)
|
|
63
|
+
print("Running Full Tracking with Merge/Split Detection...")
|
|
64
|
+
print("=" * 80)
|
|
65
|
+
|
|
66
|
+
tracker = marEx.tracker(
|
|
67
|
+
ds.extreme_events,
|
|
68
|
+
ds.mask.where(
|
|
69
|
+
(ds.lat < 85) & (ds.lat > -90), other=False
|
|
70
|
+
), # Modify Mask: Anisotropy of lat/lon grid near poles biases ID & Tracking
|
|
71
|
+
grid_resolution=grid_resolution, # Grid resolution in degrees, used to calculate object areas on the globe
|
|
72
|
+
area_filter_absolute=area_filter, # Remove objects smaller than specified cells
|
|
73
|
+
R_fill=r_fill, # Fill small holes with radius < R_fill _cells_
|
|
74
|
+
T_fill=t_fill, # Allow gaps of T_fill days and still continue event tracking with same ID
|
|
75
|
+
allow_merging=True, # Allow extreme events to split/merge. Keeps track of merge events & unique IDs
|
|
76
|
+
overlap_threshold=overlap_threshold, # Overlap threshold for merging events
|
|
77
|
+
nn_partitioning=True, # Use new NN method to partition merged children areas
|
|
78
|
+
verbose=True,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
extreme_events_ds, merges_ds = tracker.run(return_merges=True)
|
|
82
|
+
print(f"\nTracking complete: {extreme_events_ds}")
|
|
83
|
+
print(f"Merges dataset: {merges_ds}")
|
|
84
|
+
|
|
85
|
+
# Save IDed/Tracked/Merged Events to zarr for efficient parallel I/O
|
|
86
|
+
print("\nSaving tracked events data...")
|
|
87
|
+
output_file = scratch_dir / "mhws" / "extreme_events_merged_gridded_shifting_batch.zarr"
|
|
88
|
+
extreme_events_ds.to_zarr(output_file, mode="w")
|
|
89
|
+
print(f"Events data saved to: {output_file}")
|
|
90
|
+
|
|
91
|
+
# Save Merges Dataset to netcdf
|
|
92
|
+
print("Saving merges data...")
|
|
93
|
+
merges_file = scratch_dir / "mhws" / "extreme_events_merged_gridded_shifting_merges_batch.nc"
|
|
94
|
+
merges_ds.to_netcdf(merges_file, mode="w")
|
|
95
|
+
print(f"Merges data saved to: {merges_file}")
|
|
96
|
+
|
|
97
|
+
# Optionally run basic tracking for comparison
|
|
98
|
+
if run_basic:
|
|
99
|
+
print("\n" + "=" * 80)
|
|
100
|
+
print("Running Basic Tracking (No Merge/Split, No Temporal Gap Filling)...")
|
|
101
|
+
print("=" * 80)
|
|
102
|
+
|
|
103
|
+
tracker_basic = marEx.tracker(
|
|
104
|
+
ds.extreme_events,
|
|
105
|
+
ds.mask.where(
|
|
106
|
+
(ds.lat < 85) & (ds.lat > -90), other=False
|
|
107
|
+
), # Modify Mask: Anisotropy of lat/lon grid near poles biases ID & Tracking
|
|
108
|
+
area_filter_absolute=area_filter, # Remove objects smaller than specified cells
|
|
109
|
+
R_fill=r_fill, # Fill small holes with radius < R_fill _cells_
|
|
110
|
+
T_fill=0, # No temporal hole filling
|
|
111
|
+
allow_merging=False, # Do not allow extreme events to split/merge
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
extreme_events_basic_ds = tracker_basic.run()
|
|
115
|
+
print(f"\nBasic tracking complete: {extreme_events_basic_ds}")
|
|
116
|
+
|
|
117
|
+
# Save Basic IDed Events to zarr
|
|
118
|
+
print("\nSaving basic tracked events data...")
|
|
119
|
+
basic_output_file = scratch_dir / "mhws" / "extreme_events_basic_gridded_shifting_batch.zarr"
|
|
120
|
+
extreme_events_basic_ds.to_zarr(basic_output_file, mode="w")
|
|
121
|
+
print(f"Basic events data saved to: {basic_output_file}")
|
|
122
|
+
|
|
123
|
+
# Close the Dask cluster
|
|
124
|
+
client.close()
|
|
125
|
+
print("\n" + "=" * 80)
|
|
126
|
+
print("Tracking complete!")
|
|
127
|
+
print("=" * 80)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
main()
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#SBATCH --job-name=marEx_track
|
|
3
|
+
#SBATCH --partition=compute
|
|
4
|
+
#SBATCH --cpus-per-task=128
|
|
5
|
+
#SBATCH --account=bk1377
|
|
6
|
+
#SBATCH --output=slurm_%j.out
|
|
7
|
+
#SBATCH --time=02:59:00
|
|
8
|
+
#SBATCH --mem=0
|
|
9
|
+
#SBATCH --exclusive
|
|
10
|
+
|
|
11
|
+
# SLURM Batch Script for MarEx Event Tracking
|
|
12
|
+
#
|
|
13
|
+
# This script submits run_track.py as a SLURM job, ensuring all computation
|
|
14
|
+
# (including Numba JIT-compiled functions) runs on allocated compute nodes.
|
|
15
|
+
#
|
|
16
|
+
# Usage:
|
|
17
|
+
# sbatch submit_track.sh
|
|
18
|
+
#
|
|
19
|
+
# Configuration via environment variables (optional):
|
|
20
|
+
# export DASK_N_WORKERS=32 # Number of Dask workers
|
|
21
|
+
# export DASK_THREADS_PER_WORKER=1 # Threads per worker
|
|
22
|
+
# export RUN_BASIC_TRACKER=true # Run basic tracker comparison
|
|
23
|
+
# export GRID_RESOLUTION=0.25 # Grid resolution in degrees
|
|
24
|
+
# export AREA_FILTER=600 # Minimum object area (cells)
|
|
25
|
+
# export R_FILL=12 # Spatial hole filling radius
|
|
26
|
+
# export T_FILL=4 # Temporal gap filling (days)
|
|
27
|
+
# export OVERLAP_THRESHOLD=0.25 # Merge overlap threshold
|
|
28
|
+
# sbatch submit_track.sh
|
|
29
|
+
|
|
30
|
+
# Print job information
|
|
31
|
+
echo "========================================="
|
|
32
|
+
echo "SLURM Job Information"
|
|
33
|
+
echo "========================================="
|
|
34
|
+
echo "Job ID: $SLURM_JOB_ID"
|
|
35
|
+
echo "Job Name: $SLURM_JOB_NAME"
|
|
36
|
+
echo "Node: $SLURM_NODELIST"
|
|
37
|
+
echo "Start Time: $(date)"
|
|
38
|
+
echo "Working Directory: $(pwd)"
|
|
39
|
+
echo "========================================="
|
|
40
|
+
echo ""
|
|
41
|
+
|
|
42
|
+
# Set ulimits for stack size
|
|
43
|
+
ulimit -S -s unlimited
|
|
44
|
+
ulimit -S -c unlimited
|
|
45
|
+
|
|
46
|
+
# Initialise conda for bash shell
|
|
47
|
+
source $(conda info --base)/etc/profile.d/conda.sh
|
|
48
|
+
conda activate super
|
|
49
|
+
|
|
50
|
+
# Set default environment variables if not already set
|
|
51
|
+
export DASK_N_WORKERS=${DASK_N_WORKERS:-32}
|
|
52
|
+
export DASK_THREADS_PER_WORKER=${DASK_THREADS_PER_WORKER:-1}
|
|
53
|
+
|
|
54
|
+
# Print configuration
|
|
55
|
+
echo "Configuration:"
|
|
56
|
+
echo " DASK_N_WORKERS: $DASK_N_WORKERS"
|
|
57
|
+
echo " DASK_THREADS_PER_WORKER: $DASK_THREADS_PER_WORKER"
|
|
58
|
+
echo " RUN_BASIC_TRACKER: ${RUN_BASIC_TRACKER:-false}"
|
|
59
|
+
echo " GRID_RESOLUTION: ${GRID_RESOLUTION:-0.25}"
|
|
60
|
+
echo " AREA_FILTER: ${AREA_FILTER:-600}"
|
|
61
|
+
echo " R_FILL: ${R_FILL:-12}"
|
|
62
|
+
echo " T_FILL: ${T_FILL:-4}"
|
|
63
|
+
echo " OVERLAP_THRESHOLD: ${OVERLAP_THRESHOLD:-0.25}"
|
|
64
|
+
echo ""
|
|
65
|
+
|
|
66
|
+
# Run the tracking script
|
|
67
|
+
echo "Starting MarEx tracking..."
|
|
68
|
+
python run_track.py
|
|
69
|
+
|
|
70
|
+
# Capture exit status
|
|
71
|
+
EXIT_STATUS=$?
|
|
72
|
+
|
|
73
|
+
echo ""
|
|
74
|
+
echo "========================================="
|
|
75
|
+
echo "Job completed at: $(date)"
|
|
76
|
+
echo "Exit status: $EXIT_STATUS"
|
|
77
|
+
echo "========================================="
|
|
78
|
+
|
|
79
|
+
exit $EXIT_STATUS
|
|
@@ -57,6 +57,9 @@ from .exceptions import ( # Main exception hierarchy; Convenience constructors
|
|
|
57
57
|
wrap_exception,
|
|
58
58
|
)
|
|
59
59
|
|
|
60
|
+
# Import HPC helper utilities
|
|
61
|
+
from .helper import configure_dask
|
|
62
|
+
|
|
60
63
|
# Import logging configuration functions
|
|
61
64
|
from .logging_config import (
|
|
62
65
|
configure_logging,
|
|
@@ -116,6 +119,8 @@ __all__ = [
|
|
|
116
119
|
"is_verbose_mode",
|
|
117
120
|
"is_quiet_mode",
|
|
118
121
|
"get_logger",
|
|
122
|
+
# HPC helper utilities
|
|
123
|
+
"configure_dask",
|
|
119
124
|
]
|
|
120
125
|
|
|
121
126
|
# Version information
|