deepSSF 0.1.1__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.
Files changed (43) hide show
  1. deepssf-0.1.1/.github/workflows/ci.yml +26 -0
  2. deepssf-0.1.1/.github/workflows/publish.yml +20 -0
  3. deepssf-0.1.1/.gitignore +32 -0
  4. deepssf-0.1.1/.pre-commit-config.yaml +9 -0
  5. deepssf-0.1.1/CHANGELOG.md +10 -0
  6. deepssf-0.1.1/CITATION.cff +13 -0
  7. deepssf-0.1.1/LICENSE +21 -0
  8. deepssf-0.1.1/PKG-INFO +145 -0
  9. deepssf-0.1.1/Package_generation_process.md +302 -0
  10. deepssf-0.1.1/README.md +106 -0
  11. deepssf-0.1.1/deepSSF_train_validate_s2.ipynb +3329 -0
  12. deepssf-0.1.1/environment.yml +33 -0
  13. deepssf-0.1.1/examples/deepssf_train_validate_example.html +2371 -0
  14. deepssf-0.1.1/examples/deepssf_train_validate_example.ipynb +2780 -0
  15. deepssf-0.1.1/examples/deepssf_train_validate_example_files/figure-html/cell-15-output-1.png +0 -0
  16. deepssf-0.1.1/examples/deepssf_train_validate_example_files/figure-html/cell-19-output-1.png +0 -0
  17. deepssf-0.1.1/examples/deepssf_train_validate_example_files/figure-html/cell-21-output-1.png +0 -0
  18. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/bootstrap/bootstrap-138a6193a3bd40baf1e627da441a4734.min.css +12 -0
  19. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/bootstrap/bootstrap-icons.css +2106 -0
  20. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/bootstrap/bootstrap-icons.woff +0 -0
  21. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/bootstrap/bootstrap.min.js +7 -0
  22. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/clipboard/clipboard.min.js +7 -0
  23. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/quarto-html/anchor.min.js +9 -0
  24. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/quarto-html/popper.min.js +6 -0
  25. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/quarto-html/quarto-syntax-highlighting-7f8f88aac4f3542376d5c11b86a4c14d.css +236 -0
  26. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/quarto-html/quarto.js +845 -0
  27. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/quarto-html/tabsets/tabsets.js +95 -0
  28. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/quarto-html/tippy.css +1 -0
  29. deepssf-0.1.1/examples/deepssf_train_validate_example_files/libs/quarto-html/tippy.umd.min.js +2 -0
  30. deepssf-0.1.1/pyproject.toml +95 -0
  31. deepssf-0.1.1/src/deepssf/__init__.py +82 -0
  32. deepssf-0.1.1/src/deepssf/data.py +693 -0
  33. deepssf-0.1.1/src/deepssf/datasets/data/buffalo_djelk_id2005.csv +10298 -0
  34. deepssf-0.1.1/src/deepssf/datasets/data/ndvi_2005.tif +0 -0
  35. deepssf-0.1.1/src/deepssf/datasets/data/slope_2005.tif +0 -0
  36. deepssf-0.1.1/src/deepssf/model.py +362 -0
  37. deepssf-0.1.1/src/deepssf/simulate.py +300 -0
  38. deepssf-0.1.1/src/deepssf/train.py +576 -0
  39. deepssf-0.1.1/src/deepssf/utils.py +345 -0
  40. deepssf-0.1.1/src/deepssf/validate.py +172 -0
  41. deepssf-0.1.1/tests/__init__.py +0 -0
  42. deepssf-0.1.1/tests/test_deepssf.py +839 -0
  43. deepssf-0.1.1/tests/test_smoke.py +17 -0
@@ -0,0 +1,26 @@
1
+ # Runs automatically on every push / pull request to GitHub:
2
+ # lints your code and runs the test suite across Python versions.
3
+ name: CI
4
+
5
+ on:
6
+ push:
7
+ branches: [main]
8
+ pull_request:
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - name: Install package + dev tools
22
+ run: pip install -e ".[dev]"
23
+ - name: Lint
24
+ run: ruff check .
25
+ - name: Test
26
+ run: pytest
@@ -0,0 +1,20 @@
1
+ # .github/workflows/publish.yml
2
+ name: Publish to PyPI
3
+
4
+ on:
5
+ release:
6
+ types: [published] # fires when you publish a GitHub Release
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ environment: pypi
12
+ permissions:
13
+ id-token: write # required for trusted publishing
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+ - run: pip install build && python -m build
20
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,32 @@
1
+ # Byte-compiled / build artifacts
2
+ __pycache__/
3
+ *.py[cod]
4
+ build/
5
+ dist/
6
+ *.egg-info/
7
+
8
+ # Virtual environments
9
+ .venv/
10
+ venv/
11
+ env/
12
+
13
+ # Test / tooling caches
14
+ .pytest_cache/
15
+ .ruff_cache/
16
+ .coverage
17
+
18
+ # Notebooks
19
+ .ipynb_checkpoints/
20
+
21
+ # IDE / OS
22
+ .vscode/
23
+ .idea/
24
+ .DS_Store
25
+
26
+ # Models / data (keep large binaries out of git)
27
+ *.pt
28
+ *.pth
29
+ *.ckpt
30
+
31
+ # Example notebook outputs (GIFs, snapshots, saved figures)
32
+ examples/outputs/
@@ -0,0 +1,9 @@
1
+ # Install once with: pre-commit install
2
+ # Then ruff lints + formats your staged files on every `git commit`.
3
+ repos:
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ rev: v0.5.0
6
+ hooks:
7
+ - id: ruff # lint
8
+ args: [--fix]
9
+ - id: ruff-format # format
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## [Unreleased]
6
+ ### Added
7
+ - Initial package scaffold.
8
+
9
+ ## [0.1.0] - TBD
10
+ - First release.
@@ -0,0 +1,13 @@
1
+ # Lets GitHub show a "Cite this repository" button and gives users a clean
2
+ # citation. Fill in DOI/authors to match your MEE paper.
3
+ cff-version: 1.2.0
4
+ title: deepssf
5
+ message: "If you use this software, please cite it as below."
6
+ type: software
7
+ authors:
8
+ - given-names: Scott
9
+ family-names: Forrest
10
+ repository-code: "https://github.com/swforrest/deepssf"
11
+ url: "https://swforrest.github.io/deepSSF/"
12
+ license: MIT
13
+ version: 0.1.0
deepssf-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scott Forrest
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
deepssf-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: deepSSF
3
+ Version: 0.1.1
4
+ Summary: Deep learning step selection functions for predicting animal movement.
5
+ Project-URL: Homepage, https://swforrest.github.io/deepSSF/
6
+ Project-URL: Repository, https://github.com/swforrest/deepssf
7
+ Project-URL: Paper, https://besjournals.onlinelibrary.wiley.com/doi/full/10.1111/2041-210X.70136
8
+ Author-email: Scott Forrest <scottwforrest@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: animal-movement,deep-learning,ecology,ssf,step-selection
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: imageio>=2.28
22
+ Requires-Dist: ipykernel>=6.0
23
+ Requires-Dist: jupyterlab>=4.0
24
+ Requires-Dist: matplotlib>=3.7
25
+ Requires-Dist: numpy>=1.24
26
+ Requires-Dist: pandas>=2.0
27
+ Requires-Dist: rasterio>=1.3
28
+ Requires-Dist: torch>=2.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: build>=1.2; extra == 'dev'
31
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.5; extra == 'dev'
34
+ Requires-Dist: twine>=5.0; extra == 'dev'
35
+ Provides-Extra: examples
36
+ Requires-Dist: ipykernel>=6.0; extra == 'examples'
37
+ Requires-Dist: jupyterlab>=4.0; extra == 'examples'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # deepSSF
41
+
42
+ Deep learning step selection functions for predicting animal movement.
43
+
44
+ This package provides the reusable, installable implementation of the deepSSF
45
+ method. The accompanying paper, tutorials, and reproducibility code live at the
46
+ [deepSSF project site](https://swforrest.github.io/deepSSF/).
47
+
48
+ ## Installation (pip only)
49
+
50
+ If you manage your own Python environment, install deepSSF with:
51
+
52
+ ```bash
53
+ pip install deepssf
54
+ ```
55
+
56
+ Development install (editable, with linting and testing tools):
57
+
58
+ ```bash
59
+ git clone https://github.com/swforrest/deepssf
60
+ cd deepssf
61
+ pip install -e ".[dev]"
62
+ ```
63
+
64
+ ## Quick start
65
+
66
+ ```python
67
+ import deepssf
68
+ print(deepssf.__version__)
69
+ ```
70
+
71
+ ## Setting up (for users new to Python)
72
+
73
+ If you are coming from R, think of a conda environment the way you think of
74
+ an `renv` project library — it is a self-contained Python installation that
75
+ keeps this project's packages separate from everything else on your computer.
76
+ The steps below create one for deepssf and should take about five minutes.
77
+
78
+ ### 1. Install Miniconda (once, system-wide)
79
+
80
+ Download and run the installer from the
81
+ [official Miniconda page](https://docs.anaconda.com/miniconda/).
82
+
83
+ - **Windows**: use the **Anaconda Prompt** for all subsequent commands, and
84
+ choose an install path that contains **no spaces** (e.g. `C:\miniconda3`).
85
+ - **macOS / Linux**: a normal terminal works fine.
86
+
87
+ > **Miniforge alternative**: if you prefer to avoid Anaconda's default channel
88
+ > entirely, [Miniforge](https://github.com/conda-forge/miniforge) is a
89
+ > drop-in replacement that ships with `conda-forge` as the only channel.
90
+
91
+ ### 2. Create the environment
92
+
93
+ ```bash
94
+ git clone https://github.com/swforrest/deepssf
95
+ cd deepssf
96
+ conda env create -f environment.yml
97
+ ```
98
+
99
+ This installs Python 3.11, the geospatial libraries (rasterio / GDAL / PROJ),
100
+ Jupyter Lab, and the deepSSF package itself with all of its dependencies.
101
+ PyTorch is installed via pip with no extra flags — pip automatically picks the
102
+ right build for your hardware: **MPS on Apple Silicon, CUDA on NVIDIA GPUs,
103
+ CPU everywhere else**. No configuration is needed; the package selects the
104
+ correct backend at runtime.
105
+
106
+ ### 3. Activate the environment
107
+
108
+ ```bash
109
+ conda activate deepssf
110
+ ```
111
+
112
+ You will need to run this once per terminal session before using deepSSF.
113
+
114
+ ### 4. (Optional) Register the Jupyter kernel
115
+
116
+ If you use VS Code or another editor that manages its own Jupyter kernel list,
117
+ register the environment so it appears as a kernel option:
118
+
119
+ ```bash
120
+ python -m ipykernel install --user --name deepssf --display-name "Python (deepssf)"
121
+ ```
122
+
123
+ ### 5. Launch Jupyter Lab
124
+
125
+ ```bash
126
+ jupyter lab
127
+ ```
128
+
129
+ Then open `examples/deepssf_train_validate_example.ipynb` to get started.
130
+
131
+ ---
132
+
133
+ ## Documentation
134
+
135
+ Tutorials and walkthroughs: https://swforrest.github.io/deepSSF/
136
+
137
+ ## Citation
138
+
139
+ If you use deepssf in your research, please cite the paper. See `CITATION.cff` or use the citation and link to paper below.
140
+
141
+ Forrest, S. W., Pagendam, D., Hassan, C., Potts, J. R., Drovandi, C., Bode, M., & Hoskins, A. J. (2026). **Predicting animal movement with deepSSF : A deep learning step selection framework**. Methods in Ecology and Evolution, 17(2), 371–391. https://doi.org/10.1111/2041-210x.70136
142
+
143
+ ## License
144
+
145
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,302 @@
1
+ # Package Generation Process
2
+
3
+ This document records what was done to convert the deepSSF research codebase
4
+ (originally a collection of Jupyter notebooks) into the `deepssf` installable
5
+ Python package.
6
+
7
+ ---
8
+
9
+ ## 1. Starting Point
10
+
11
+ The repo contained:
12
+
13
+ - A number of analysis notebooks from https://swforrest.github.io/deepSSF/ with
14
+ model definitions, data loading, training, simulation, and validation code
15
+ written as a combination of inline and as separate py scripts.
16
+ - No `pyproject.toml`, no `src/` layout, no tests, no installable package.
17
+
18
+ ---
19
+
20
+ ## 2. Package Scaffold
21
+
22
+ ### Directory layout
23
+
24
+ The standard `src`-layout was adopted so the package is importable only after
25
+ installation (editable or otherwise), preventing accidental imports from the
26
+ working directory:
27
+
28
+ ```
29
+ deepSSF_package/
30
+ ├── src/
31
+ │ └── deepssf/
32
+ │ ├── __init__.py
33
+ │ ├── data.py
34
+ │ ├── model.py
35
+ │ ├── train.py
36
+ │ ├── simulate.py
37
+ │ ├── validate.py
38
+ │ ├── utils.py
39
+ │ └── datasets/data/ # bundled test dataset (CSV + 2 GeoTIFFs)
40
+ ├── tests/
41
+ │ ├── __init__.py
42
+ │ ├── test_deepssf.py
43
+ │ └── test_smoke.py
44
+ ├── examples/
45
+ │ └── deepssf_train_validate_example.ipynb
46
+ ├── pyproject.toml
47
+ ├── environment.yml
48
+ ├── README.md
49
+ ├── CHANGELOG.md
50
+ ├── CITATION.cff
51
+ └── LICENSE
52
+ ```
53
+
54
+ ### `pyproject.toml`
55
+
56
+ A single `pyproject.toml` replaces `setup.py` / `setup.cfg` / `requirements.txt`.
57
+ Key decisions:
58
+
59
+ - Build backend: `hatchling` (version read dynamically from `__init__.py`).
60
+ - Runtime deps declared once: `numpy`, `torch`, `pandas`, `matplotlib`,
61
+ `rasterio`, `imageio`.
62
+ - Optional dep groups:
63
+ - `[dev]` — `pytest`, `ruff`, `pre-commit`, `build`, `twine`.
64
+ - `[examples]` — `jupyterlab`, `ipykernel` (used by `environment.yml`).
65
+ - `requires-python = ">=3.10"`.
66
+
67
+ ---
68
+
69
+ ## 3. Code Ported from Notebooks
70
+
71
+ Each notebook section was extracted into its own module with type annotations,
72
+ docstrings, and cleaned-up interfaces.
73
+
74
+ ### `src/deepssf/model.py`
75
+
76
+ - `ModelParams` — thin wrapper around a config dict; attributes accessible by
77
+ name.
78
+ - `Conv2d_block_spatial` — habitat sub-network (conv stack → log-softmax over
79
+ H×W).
80
+ - `Scalar_to_Grid_Block` — broadcasts scalar covariates into spatial maps.
81
+ - `Conv2d_block_toFC` — movement sub-network (conv stack → flattened dense
82
+ layer).
83
+ - `ConvJointModel` — combines all three blocks; forward pass returns
84
+ `[B, H, W, 2]` (habitat channel + movement channel).
85
+
86
+ ### `src/deepssf/train.py`
87
+
88
+ - `negativeLogLikeLoss` — factory returning a loss function that reads the
89
+ observed next-step pixel `(px2, py2)` from the batch; supports `reduction`
90
+ in `{"mean", "sum", "none", "median"}` and a `freeze_movement` flag for
91
+ curriculum training.
92
+ - `EarlyStopping` — patience-based stopping with checkpoint saving.
93
+ - `make_optimisers` — returns two `Adam` optimisers (one per sub-network) with
94
+ `ReduceLROnPlateau` schedulers.
95
+ - `train_loop` / `test_loop` — single-epoch passes.
96
+ - `fit` — full training loop with early stopping, snapshot saving, and loss
97
+ history dict.
98
+
99
+ ### `src/deepssf/data.py`
100
+
101
+ - `load_s2_data` — loads all `S2_*.tif` monthly composites from a directory;
102
+ scales DN → surface reflectance.
103
+ - `load_environmental_layers` — dispatches to `load_s2_data` for the S2
104
+ directory; loads other layers from TIFF (scaled to [0, 1]) or `.npy` files.
105
+ - `MovementDataset` — `torch.utils.data.Dataset`; `__getitem__` extracts a
106
+ spatial patch centred on the departure pixel and returns
107
+ `(spatial, scalars, bearing_tm1, next_step_pixel, transform)`.
108
+ - `prepare_movement_df` — converts raw telemetry (one row per fix) to step
109
+ format (one row per consecutive pair). Outputs: `x1_`, `y1_`, `x2_`, `y2_`,
110
+ `t1_`, `dx`, `dy`, `bearing`, `bearing_tm1`, `dt_hour`, `hour_t1`,
111
+ `yday_t1`, and four cyclic encodings.
112
+ - `filter_steps_by_window` *(new)* — drops steps whose displacement `|dx|` or
113
+ `|dy|` exceeds `(window_size - 1) * pixel_size / 2`. Must be called after
114
+ `prepare_movement_df` and before `make_dataloaders` to prevent out-of-bounds
115
+ pixel indices in the loss function (see §6 below).
116
+ - `make_dataloaders` — convenience wrapper that builds `MovementDataset` and
117
+ splits it into train / val / test `DataLoader`s.
118
+
119
+ ### `src/deepssf/utils.py`
120
+
121
+ - `get_device` — selects MPS → CUDA → CPU at runtime.
122
+ - `clear_memory` — frees GPU/MPS cache.
123
+ - `subset_raster_with_padding_torch` / `_npy` — crops a raster window with
124
+ −1 padding at boundaries.
125
+ - `subset_raster_all_bands_torch` — multi-band variant.
126
+ - `subset_layer_vectorized` — fast NumPy/Torch crop used inside
127
+ `MovementDataset.__getitem__`.
128
+ - `recover_hour` / `recover_yday` — invert cyclic sine/cosine encodings.
129
+ - `create_gif` — assembles training snapshot PNGs into an animated GIF.
130
+
131
+ ### `src/deepssf/simulate.py`
132
+
133
+ Ported from `deepSSF_simulations.ipynb`:
134
+
135
+ - `make_simulation_inputs` — pre-computes cyclic scalar arrays for N steps
136
+ given a starting day-of-year and hour.
137
+ - `simulate_next_step` — runs one forward pass; samples the next location from
138
+ the joint probability map; returns new coordinates and three log-prob tensors.
139
+ - `simulate_trajectory` — loops `simulate_next_step` for N steps and returns a
140
+ DataFrame of `(x, y, hour, yday, month_index)`.
141
+
142
+ ### `src/deepssf/validate.py`
143
+
144
+ - `validate_next_step_probs` — iterates over observed steps, runs the model,
145
+ and appends `habitat_prob`, `move_prob`, and `next_step_prob` columns to the
146
+ input DataFrame.
147
+
148
+ ### `src/deepssf/__init__.py`
149
+
150
+ Curated public API: re-exports every user-facing name from all five modules,
151
+ plus `__version__ = "0.1.0"`. `__all__` is explicit.
152
+
153
+ ---
154
+
155
+ ## 4. Example Notebook
156
+
157
+ `examples/deepssf_train_validate_example.ipynb` is a cleaned-up, reproducible
158
+ version of the original analysis notebook. It uses only the public package API:
159
+ no inline model or data-prep code remains. Key changes from the original:
160
+
161
+ - Imports `from deepssf import ...` throughout.
162
+ - Defines `WINDOW_SIZE = 25` and `PIXEL_SIZE = 25` as named constants.
163
+ - Calls `filter_steps_by_window(step_df, window_size=WINDOW_SIZE, pixel_size=PIXEL_SIZE)`
164
+ immediately after `prepare_movement_df`, before `make_dataloaders`.
165
+ - Uses `PIXEL_SIZE` (not a bare literal) in `ModelParams`.
166
+ - Saves all outputs under `examples/outputs/`.
167
+
168
+ ---
169
+
170
+ ## 5. Test Suite
171
+
172
+ `tests/test_deepssf.py` — 48 tests covering every public function:
173
+
174
+ | Area | Tests |
175
+ |------|-------|
176
+ | `deepssf.utils` | `get_device`, `recover_hour/yday` roundtrips, `subset_raster_*` shapes and padding, `clear_memory` |
177
+ | `deepssf.data` | `extract_year_month_regex`, `day_to_month_index`, `prepare_movement_df` columns / row count / bearing / cyclic range / dx/dy / bearing_tm1, `filter_steps_by_window`, `MovementDataset.__getitem__` shapes, `make_dataloaders` (df= and prepare= variants) |
178
+ | `deepssf.model` | `ModelParams` construction, `Conv2d_block_spatial` output shape, `Scalar_to_Grid_Block` output shape, full forward pass shape, habitat log-normalisation |
179
+ | `deepssf.train` | `negativeLogLikeLoss` (mean, sum, none, median, freeze_movement, invalid reduction), `EarlyStopping` counter / reset, `make_optimisers`, `fit` loss history |
180
+ | `deepssf.simulate` | `make_simulation_inputs` shape / cyclic encoding / hour wrap, `simulate_next_step` return types and shapes, `simulate_trajectory` DataFrame shape and columns |
181
+ | `deepssf.validate` | `validate_next_step_probs` column presence and row-0 == 0 rule, `_day_to_s2_month` range |
182
+
183
+ Ruff (linting + import sorting) is configured in `pyproject.toml` and passes
184
+ clean on all source and test files.
185
+
186
+ ---
187
+
188
+ ## 6. Issues Encountered and Resolved
189
+
190
+ ### OpenMP duplicate-library crash on macOS (MPS)
191
+
192
+ **Symptom**: `OMP Error #15: Initializing libomp.dylib, but found libomp.dylib
193
+ already initialized` — process crashed on the first MPS forward pass.
194
+
195
+ **Root cause**: Two separate copies of libomp were loaded:
196
+ 1. pip-installed `torch` bundles its own `libomp.dylib`.
197
+ 2. conda-forge's `rasterio` pulled in `libopenblas` (OpenMP build) →
198
+ `llvm-openmp`, a second libomp.
199
+
200
+ Additionally, the system `~/.condarc` had `channel_priority: flexible` plus a
201
+ `defaults` channel entry, which caused conda to pre-install the full
202
+ conda-forge pytorch ecosystem as orphaned packages before pip had a chance to
203
+ install torch.
204
+
205
+ **Fix** (two parts):
206
+ 1. Added `- nodefaults` to `environment.yml` channels to prevent the system
207
+ `~/.condarc` channels from being merged into the solve.
208
+ 2. Moved `rasterio` from the conda section to the pip section. The macOS ARM64
209
+ pip wheel for rasterio bundles GDAL/PROJ internally, so conda-forge never
210
+ installs libopenblas or llvm-openmp. The conda section now installs only
211
+ pure-Python packages (jupyterlab, ipykernel) with no C extension or BLAS
212
+ dependencies.
213
+
214
+ ### torch 2.12 stricter MPS bounds checking
215
+
216
+ **Symptom**: `AcceleratorError: index 25 is out of bounds for dimension 1 with
217
+ size 25` during the first training epoch on MPS.
218
+
219
+ **Root cause**: `MovementDataset.__getitem__` computes the next-step pixel
220
+ index as `px2 - col_start`. For `window_size=25`, valid indices are 0–24. A
221
+ step whose displacement exceeds 12 pixels (i.e. 300 m at 25 m/pixel) produces
222
+ a local index of 25, which is out of bounds. torch 2.5.1 silently allowed
223
+ this; torch 2.12 on MPS correctly raises an error.
224
+
225
+ **Fix**: Rather than clamping the index (which would silently corrupt the loss
226
+ signal), the correct fix is to remove those steps before training. This
227
+ matches the original notebook's pattern. The solution was to:
228
+ - Add `dx` and `dy` columns to `prepare_movement_df` output (the actual x/y
229
+ displacements in CRS units).
230
+ - Add `hour_t1` column (needed by the simulation cell).
231
+ - Add the `filter_steps_by_window(df, window_size, pixel_size)` function.
232
+ - Call it in the example notebook between `prepare_movement_df` and
233
+ `make_dataloaders`.
234
+
235
+ ### macOS case-insensitive filesystem collision
236
+
237
+ The original development conda environment was named `deepSSF`. Running
238
+ `conda env remove -n deepssf` (lowercase) on macOS's case-insensitive APFS
239
+ filesystem removed `/opt/miniconda3/envs/deepSSF` — the two names are
240
+ identical to the OS. The new `deepssf` environment (created from
241
+ `environment.yml`) is now the primary development environment.
242
+
243
+ ---
244
+
245
+ ## 7. Environment Setup (`environment.yml`)
246
+
247
+ A conda/pip hybrid environment for reproducible setup on any platform:
248
+
249
+ ```yaml
250
+ name: deepssf
251
+
252
+ channels:
253
+ - conda-forge
254
+ - nodefaults # prevent system ~/.condarc channels from being merged in
255
+
256
+ dependencies:
257
+ - python=3.11
258
+ - pip
259
+
260
+ # Jupyter — installed via conda for reliable kernel registration
261
+ - jupyterlab>=4.0
262
+ - ipykernel>=6.0
263
+
264
+ - pip:
265
+ # Plain torch — pip selects MPS on macOS, CUDA on NVIDIA, CPU elsewhere
266
+ - torch>=2.0
267
+
268
+ # rasterio via pip — ARM64/Linux wheels bundle GDAL/PROJ internally,
269
+ # avoiding the conda-forge openblas → llvm-openmp conflict with torch's libomp
270
+ - rasterio>=1.3
271
+
272
+ # Install the package + Jupyter extras; all other deps come from pyproject.toml
273
+ - -e ".[examples]"
274
+ ```
275
+
276
+ ### Verification (Apple Silicon, MPS)
277
+
278
+ After `conda env create -f environment.yml && conda activate deepssf`:
279
+
280
+ | Check | Result |
281
+ |-------|--------|
282
+ | `torch.backends.mps.is_available()` | `True` |
283
+ | `import deepssf, rasterio` | OK |
284
+ | `pytest` | 48 passed, 1 warning |
285
+ | `ruff check src/ tests/` | All checks passed |
286
+ | Example notebook end-to-end | Completed; produced `best_model.pt`, `loss_history.png`, `simulated_trajectory.png`, `training_progress.gif`, `validation_probs.png` |
287
+
288
+ ---
289
+
290
+ ## 8. README
291
+
292
+ A "Setting up (for users new to Python)" section was added as the first major
293
+ section, aimed at R users unfamiliar with Python packaging:
294
+
295
+ - Frames a conda environment as equivalent to an `renv` project library.
296
+ - Links to the official Miniconda page; notes Windows users should use the
297
+ Anaconda Prompt and avoid paths with spaces.
298
+ - Mentions Miniforge as an alternative for those who prefer to avoid
299
+ Anaconda's default channel.
300
+ - Copy-pasteable commands: `conda env create`, `conda activate`, optional
301
+ `ipykernel install`, `jupyter lab`.
302
+ - Notes that PyTorch auto-selects MPS / CUDA / CPU with no manual configuration.
@@ -0,0 +1,106 @@
1
+ # deepSSF
2
+
3
+ Deep learning step selection functions for predicting animal movement.
4
+
5
+ This package provides the reusable, installable implementation of the deepSSF
6
+ method. The accompanying paper, tutorials, and reproducibility code live at the
7
+ [deepSSF project site](https://swforrest.github.io/deepSSF/).
8
+
9
+ ## Installation (pip only)
10
+
11
+ If you manage your own Python environment, install deepSSF with:
12
+
13
+ ```bash
14
+ pip install deepssf
15
+ ```
16
+
17
+ Development install (editable, with linting and testing tools):
18
+
19
+ ```bash
20
+ git clone https://github.com/swforrest/deepssf
21
+ cd deepssf
22
+ pip install -e ".[dev]"
23
+ ```
24
+
25
+ ## Quick start
26
+
27
+ ```python
28
+ import deepssf
29
+ print(deepssf.__version__)
30
+ ```
31
+
32
+ ## Setting up (for users new to Python)
33
+
34
+ If you are coming from R, think of a conda environment the way you think of
35
+ an `renv` project library — it is a self-contained Python installation that
36
+ keeps this project's packages separate from everything else on your computer.
37
+ The steps below create one for deepssf and should take about five minutes.
38
+
39
+ ### 1. Install Miniconda (once, system-wide)
40
+
41
+ Download and run the installer from the
42
+ [official Miniconda page](https://docs.anaconda.com/miniconda/).
43
+
44
+ - **Windows**: use the **Anaconda Prompt** for all subsequent commands, and
45
+ choose an install path that contains **no spaces** (e.g. `C:\miniconda3`).
46
+ - **macOS / Linux**: a normal terminal works fine.
47
+
48
+ > **Miniforge alternative**: if you prefer to avoid Anaconda's default channel
49
+ > entirely, [Miniforge](https://github.com/conda-forge/miniforge) is a
50
+ > drop-in replacement that ships with `conda-forge` as the only channel.
51
+
52
+ ### 2. Create the environment
53
+
54
+ ```bash
55
+ git clone https://github.com/swforrest/deepssf
56
+ cd deepssf
57
+ conda env create -f environment.yml
58
+ ```
59
+
60
+ This installs Python 3.11, the geospatial libraries (rasterio / GDAL / PROJ),
61
+ Jupyter Lab, and the deepSSF package itself with all of its dependencies.
62
+ PyTorch is installed via pip with no extra flags — pip automatically picks the
63
+ right build for your hardware: **MPS on Apple Silicon, CUDA on NVIDIA GPUs,
64
+ CPU everywhere else**. No configuration is needed; the package selects the
65
+ correct backend at runtime.
66
+
67
+ ### 3. Activate the environment
68
+
69
+ ```bash
70
+ conda activate deepssf
71
+ ```
72
+
73
+ You will need to run this once per terminal session before using deepSSF.
74
+
75
+ ### 4. (Optional) Register the Jupyter kernel
76
+
77
+ If you use VS Code or another editor that manages its own Jupyter kernel list,
78
+ register the environment so it appears as a kernel option:
79
+
80
+ ```bash
81
+ python -m ipykernel install --user --name deepssf --display-name "Python (deepssf)"
82
+ ```
83
+
84
+ ### 5. Launch Jupyter Lab
85
+
86
+ ```bash
87
+ jupyter lab
88
+ ```
89
+
90
+ Then open `examples/deepssf_train_validate_example.ipynb` to get started.
91
+
92
+ ---
93
+
94
+ ## Documentation
95
+
96
+ Tutorials and walkthroughs: https://swforrest.github.io/deepSSF/
97
+
98
+ ## Citation
99
+
100
+ If you use deepssf in your research, please cite the paper. See `CITATION.cff` or use the citation and link to paper below.
101
+
102
+ Forrest, S. W., Pagendam, D., Hassan, C., Potts, J. R., Drovandi, C., Bode, M., & Hoskins, A. J. (2026). **Predicting animal movement with deepSSF : A deep learning step selection framework**. Methods in Ecology and Evolution, 17(2), 371–391. https://doi.org/10.1111/2041-210x.70136
103
+
104
+ ## License
105
+
106
+ MIT — see [LICENSE](LICENSE).