themisim 0.1.0__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.
- themisim-0.1.0/LICENSE +21 -0
- themisim-0.1.0/PKG-INFO +196 -0
- themisim-0.1.0/README.md +155 -0
- themisim-0.1.0/pyproject.toml +62 -0
- themisim-0.1.0/setup.cfg +4 -0
- themisim-0.1.0/src/themisim/__init__.py +73 -0
- themisim-0.1.0/src/themisim/catalog.py +220 -0
- themisim-0.1.0/src/themisim/cli/__init__.py +1 -0
- themisim-0.1.0/src/themisim/cli/build_index.py +96 -0
- themisim-0.1.0/src/themisim/cli/download.py +86 -0
- themisim-0.1.0/src/themisim/cli/query.py +93 -0
- themisim-0.1.0/src/themisim/concat.py +374 -0
- themisim-0.1.0/src/themisim/config.py +62 -0
- themisim-0.1.0/src/themisim/download.py +289 -0
- themisim-0.1.0/src/themisim/embed.py +1346 -0
- themisim-0.1.0/src/themisim/export.py +79 -0
- themisim-0.1.0/src/themisim/index.py +429 -0
- themisim-0.1.0/src/themisim/inventory.py +167 -0
- themisim-0.1.0/src/themisim/model.py +66 -0
- themisim-0.1.0/src/themisim/pipeline.py +206 -0
- themisim-0.1.0/src/themisim/preprocess.py +80 -0
- themisim-0.1.0/src/themisim/query.py +245 -0
- themisim-0.1.0/src/themisim/search.py +713 -0
- themisim-0.1.0/src/themisim/viz.py +173 -0
- themisim-0.1.0/src/themisim/weights.py +114 -0
- themisim-0.1.0/src/themisim.egg-info/PKG-INFO +196 -0
- themisim-0.1.0/src/themisim.egg-info/SOURCES.txt +34 -0
- themisim-0.1.0/src/themisim.egg-info/dependency_links.txt +1 -0
- themisim-0.1.0/src/themisim.egg-info/entry_points.txt +4 -0
- themisim-0.1.0/src/themisim.egg-info/requires.txt +20 -0
- themisim-0.1.0/src/themisim.egg-info/top_level.txt +1 -0
- themisim-0.1.0/tests/test_catalog.py +71 -0
- themisim-0.1.0/tests/test_embed_grouping.py +64 -0
- themisim-0.1.0/tests/test_export.py +61 -0
- themisim-0.1.0/tests/test_query.py +75 -0
- themisim-0.1.0/tests/test_search.py +109 -0
themisim-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeremiah Johnson
|
|
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.
|
themisim-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: themisim
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Similarity search over THEMIS all-sky imager imagery using SimCLR encoder features and a FAISS index
|
|
5
|
+
Author: Jeremiah Johnson
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jwjohnson314/themisim
|
|
8
|
+
Project-URL: Documentation, https://jwjohnson314.github.io/themisim/
|
|
9
|
+
Project-URL: Source, https://github.com/jwjohnson314/themisim
|
|
10
|
+
Project-URL: Issues, https://github.com/jwjohnson314/themisim/issues
|
|
11
|
+
Keywords: aurora,THEMIS,all-sky-imager,similarity-search,faiss,self-supervised
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: torch>=2.0
|
|
24
|
+
Requires-Dist: torchvision>=0.15
|
|
25
|
+
Requires-Dist: numpy<2,>=1.24
|
|
26
|
+
Requires-Dist: pandas>=2.0
|
|
27
|
+
Requires-Dist: pyarrow>=11
|
|
28
|
+
Requires-Dist: Pillow>=9.4
|
|
29
|
+
Requires-Dist: cdflib>=1.2
|
|
30
|
+
Requires-Dist: faiss-cpu>=1.8
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov>=4; extra == "dev"
|
|
34
|
+
Provides-Extra: notebook
|
|
35
|
+
Requires-Dist: jupyter; extra == "notebook"
|
|
36
|
+
Requires-Dist: matplotlib; extra == "notebook"
|
|
37
|
+
Provides-Extra: docs
|
|
38
|
+
Requires-Dist: sphinx>=7; extra == "docs"
|
|
39
|
+
Requires-Dist: furo>=2024.1; extra == "docs"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# THEMISim
|
|
43
|
+
|
|
44
|
+
Similarity search over [THEMIS](https://themis.ssl.berkeley.edu) all-sky imager
|
|
45
|
+
(ASI) auroral imagery. A SimCLR-trained ResNet-18 encoder turns each 256×256
|
|
46
|
+
frame into a 512-D feature vector where proximity as measured by cosine similarity corresponds to visual and morphological similarity rather than pixel-level identity; ~1 billion of these are indexed with FAISS (OPQ-IVF-PQ). Given any indexed frame, the library quickly and efficiently returns the most visually similar frames across the whole archive.
|
|
47
|
+
|
|
48
|
+
This software does three things:
|
|
49
|
+
|
|
50
|
+
1. **Download** THEMIS ASI CDFs from the Berkeley archive and encoder weights from HuggingFace.
|
|
51
|
+
2. **Build** a FAISS index from the pretrained encoder weights.
|
|
52
|
+
3. **Query** the index by `(site, datetime, frame)`, returning a tidy
|
|
53
|
+
`DataFrame`/CSV.
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install themisim
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`faiss-cpu` is pulled in as a dependency (the query path is CPU-only). If you
|
|
62
|
+
already have a GPU `faiss` from conda, install with `--no-deps` to keep it.
|
|
63
|
+
A CUDA-enabled PyTorch makes index building much faster but is optional — every
|
|
64
|
+
stage falls back to CPU.
|
|
65
|
+
|
|
66
|
+
## Quick start — querying an existing index
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from themisim import query
|
|
70
|
+
|
|
71
|
+
df = query("fsmi", "2015-03-18T06", 412, artifacts="data/artifacts")
|
|
72
|
+
df.head()
|
|
73
|
+
# site datetime score source_cdf
|
|
74
|
+
# 0 fsmi 2015-03-18 06:20:36 1.000000 http://themis.ssl.berkeley.edu/.../thg_l1_asf_fsmi_2015031806_v01.cdf
|
|
75
|
+
# ...
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
- `datetime` names the **hourly** CDF (`YYYY-MM-DDTHH`); sub-hour fields are
|
|
79
|
+
ignored. `2015-03-18 06`, `2015031806`, and a `datetime` object also work.
|
|
80
|
+
- `frame` is the 0-based frame index within that hour (THEMIS runs at a
|
|
81
|
+
3-second cadence, ~1200 frames/hour).
|
|
82
|
+
- The top result is normally the query frame itself (`score ≈ 1.0`).
|
|
83
|
+
|
|
84
|
+
Search parameters:
|
|
85
|
+
|
|
86
|
+
| arg | default | meaning |
|
|
87
|
+
|-----|---------|---------|
|
|
88
|
+
| `results` | 24 | count mode: number of results to return |
|
|
89
|
+
| `min_score` | `None` | threshold mode: return *every* match scoring ≥ this cutoff (overrides `results`) |
|
|
90
|
+
| `prefilter` | 500 | FAISS candidates pulled before exact cosine rerank |
|
|
91
|
+
| `nprobe` | 64 | IVF cells inspected per query |
|
|
92
|
+
| `diversify_seconds` | 30 | drop near-duplicate frames within ±N s at the same site (0 disables) |
|
|
93
|
+
|
|
94
|
+
### Bounding the result set: count vs. threshold
|
|
95
|
+
|
|
96
|
+
There are two ways to decide how many results come back:
|
|
97
|
+
|
|
98
|
+
- **Count** (default) — return the top `results` matches.
|
|
99
|
+
- **Threshold** — pass `min_score` (a cosine similarity in `[0, 1]`) and the
|
|
100
|
+
search ignores `results`, returning *every* (temporally diversified) match
|
|
101
|
+
scoring at or above the cutoff, best first. The result set is capped at 2000
|
|
102
|
+
for safety. Because the candidate pool is the top `prefilter` FAISS matches,
|
|
103
|
+
raise `prefilter` to surface more low-cutoff hits.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# every frame at least 0.9 cosine-similar to the query, not just the top 24
|
|
107
|
+
df = query("fsmi", "2015-03-18T06", 412, artifacts="data/artifacts",
|
|
108
|
+
min_score=0.9)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### From the command line
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
themis-query --site fsmi --datetime 2015-03-18T06 --frame 412 \
|
|
115
|
+
--artifacts data/artifacts --output results.csv
|
|
116
|
+
|
|
117
|
+
# threshold mode: every match scoring >= 0.9, instead of a fixed --results count
|
|
118
|
+
themis-query --site fsmi --datetime 2015-03-18T06 --frame 412 \
|
|
119
|
+
--artifacts data/artifacts --min-score 0.9 --output results.csv
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Output columns are `site, datetime, score, source_cdf` — identical to the
|
|
123
|
+
dashboard's CSV export.
|
|
124
|
+
|
|
125
|
+
## Build an index from scratch
|
|
126
|
+
|
|
127
|
+
Note that the full THEMIS ASI archive is ~1M CDFs (over 100 TB) and building the index takes on the order of GPU-days; the
|
|
128
|
+
prebuilt index (about 72 GB) is **not** currently downloadable. If you are interested in obtaining it please email me to discuss.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 1. fetch the encoder weights (44 MB)
|
|
133
|
+
python -c "from themisim import fetch_weights; print(fetch_weights())"
|
|
134
|
+
|
|
135
|
+
# 2. one-shot pipeline (download + build)
|
|
136
|
+
SITES=fsmi START=2015-03 END=2015-03 ./scripts/run_pipeline.sh
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
or step by step:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
themis-download --data-root data/cdf --sites fsmi --start 2015-03 --end 2015-03
|
|
143
|
+
themis-build-index --data-root data/cdf --artifacts data/artifacts \
|
|
144
|
+
--checkpoint weights/aurora-fm-no-finetune.tar
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The equivalent Python API:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from themisim import download_archive, build_index
|
|
151
|
+
|
|
152
|
+
download_archive("data/cdf", sites=["fsmi"], start="2015-03", end="2015-03")
|
|
153
|
+
build_index("data/cdf", "data/artifacts",
|
|
154
|
+
"weights/aurora-fm-no-finetune.tar")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`build_index` runs inventory → embed → concat → train/build, resuming cleanly
|
|
158
|
+
if interrupted (already-embedded hours are skipped). `--nlist auto` scales the
|
|
159
|
+
IVF cell count to the dataset size.
|
|
160
|
+
|
|
161
|
+
## Model weights
|
|
162
|
+
|
|
163
|
+
`fetch_weights()` downloads and SHA-256-verifies the ~44 MB SimCLR checkpoint
|
|
164
|
+
into `./weights` (override with `$THEMIS_ASI_WEIGHTS`). It is pulled from the
|
|
165
|
+
public Hugging Face repo
|
|
166
|
+
[`Jwjohnson314/Aurora-FM`](https://huggingface.co/Jwjohnson314/Aurora-FM); override
|
|
167
|
+
the URL via `$THEMIS_ASI_WEIGHTS_URL` or pass `url=`. If you already have the
|
|
168
|
+
`.tar`, drop it in the weights directory and it will be verified and reused
|
|
169
|
+
without a network call.
|
|
170
|
+
|
|
171
|
+
## Paths / configuration
|
|
172
|
+
|
|
173
|
+
Resolved from explicit arguments, then environment variables, then defaults:
|
|
174
|
+
|
|
175
|
+
| what | env var | default |
|
|
176
|
+
|------|---------|---------|
|
|
177
|
+
| downloaded CDFs | `THEMIS_ASI_DATA_ROOT` | `./data/cdf` |
|
|
178
|
+
| index artifacts | `THEMIS_ASI_ARTIFACTS` | `./data/artifacts` |
|
|
179
|
+
| model weights | `THEMIS_ASI_WEIGHTS` | `./weights` |
|
|
180
|
+
|
|
181
|
+
An artifacts directory contains `index.faiss`, `manifest.parquet`,
|
|
182
|
+
`vectors.f16.dat`, and `vectors.meta.json`.
|
|
183
|
+
|
|
184
|
+
## License, data & citation
|
|
185
|
+
|
|
186
|
+
The **code** in this repository is MIT-licensed — see [LICENSE](LICENSE).
|
|
187
|
+
|
|
188
|
+
The assets this tool downloads carry their own terms, which you must honor when
|
|
189
|
+
publishing results:
|
|
190
|
+
|
|
191
|
+
- **Model weights** (`Jwjohnson314/Aurora-FM`) are released under
|
|
192
|
+
**CC-BY-4.0** — attribution required.
|
|
193
|
+
- **THEMIS ASI data** is provided by the THEMIS mission (UC Berkeley / NASA) and
|
|
194
|
+
is subject to the
|
|
195
|
+
[THEMIS data use & citation policy](https://themis.ssl.berkeley.edu/roadrules.shtml).
|
|
196
|
+
Acknowledge the mission and instrument teams in any publication.
|
themisim-0.1.0/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# THEMISim
|
|
2
|
+
|
|
3
|
+
Similarity search over [THEMIS](https://themis.ssl.berkeley.edu) all-sky imager
|
|
4
|
+
(ASI) auroral imagery. A SimCLR-trained ResNet-18 encoder turns each 256×256
|
|
5
|
+
frame into a 512-D feature vector where proximity as measured by cosine similarity corresponds to visual and morphological similarity rather than pixel-level identity; ~1 billion of these are indexed with FAISS (OPQ-IVF-PQ). Given any indexed frame, the library quickly and efficiently returns the most visually similar frames across the whole archive.
|
|
6
|
+
|
|
7
|
+
This software does three things:
|
|
8
|
+
|
|
9
|
+
1. **Download** THEMIS ASI CDFs from the Berkeley archive and encoder weights from HuggingFace.
|
|
10
|
+
2. **Build** a FAISS index from the pretrained encoder weights.
|
|
11
|
+
3. **Query** the index by `(site, datetime, frame)`, returning a tidy
|
|
12
|
+
`DataFrame`/CSV.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install themisim
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`faiss-cpu` is pulled in as a dependency (the query path is CPU-only). If you
|
|
21
|
+
already have a GPU `faiss` from conda, install with `--no-deps` to keep it.
|
|
22
|
+
A CUDA-enabled PyTorch makes index building much faster but is optional — every
|
|
23
|
+
stage falls back to CPU.
|
|
24
|
+
|
|
25
|
+
## Quick start — querying an existing index
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from themisim import query
|
|
29
|
+
|
|
30
|
+
df = query("fsmi", "2015-03-18T06", 412, artifacts="data/artifacts")
|
|
31
|
+
df.head()
|
|
32
|
+
# site datetime score source_cdf
|
|
33
|
+
# 0 fsmi 2015-03-18 06:20:36 1.000000 http://themis.ssl.berkeley.edu/.../thg_l1_asf_fsmi_2015031806_v01.cdf
|
|
34
|
+
# ...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `datetime` names the **hourly** CDF (`YYYY-MM-DDTHH`); sub-hour fields are
|
|
38
|
+
ignored. `2015-03-18 06`, `2015031806`, and a `datetime` object also work.
|
|
39
|
+
- `frame` is the 0-based frame index within that hour (THEMIS runs at a
|
|
40
|
+
3-second cadence, ~1200 frames/hour).
|
|
41
|
+
- The top result is normally the query frame itself (`score ≈ 1.0`).
|
|
42
|
+
|
|
43
|
+
Search parameters:
|
|
44
|
+
|
|
45
|
+
| arg | default | meaning |
|
|
46
|
+
|-----|---------|---------|
|
|
47
|
+
| `results` | 24 | count mode: number of results to return |
|
|
48
|
+
| `min_score` | `None` | threshold mode: return *every* match scoring ≥ this cutoff (overrides `results`) |
|
|
49
|
+
| `prefilter` | 500 | FAISS candidates pulled before exact cosine rerank |
|
|
50
|
+
| `nprobe` | 64 | IVF cells inspected per query |
|
|
51
|
+
| `diversify_seconds` | 30 | drop near-duplicate frames within ±N s at the same site (0 disables) |
|
|
52
|
+
|
|
53
|
+
### Bounding the result set: count vs. threshold
|
|
54
|
+
|
|
55
|
+
There are two ways to decide how many results come back:
|
|
56
|
+
|
|
57
|
+
- **Count** (default) — return the top `results` matches.
|
|
58
|
+
- **Threshold** — pass `min_score` (a cosine similarity in `[0, 1]`) and the
|
|
59
|
+
search ignores `results`, returning *every* (temporally diversified) match
|
|
60
|
+
scoring at or above the cutoff, best first. The result set is capped at 2000
|
|
61
|
+
for safety. Because the candidate pool is the top `prefilter` FAISS matches,
|
|
62
|
+
raise `prefilter` to surface more low-cutoff hits.
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# every frame at least 0.9 cosine-similar to the query, not just the top 24
|
|
66
|
+
df = query("fsmi", "2015-03-18T06", 412, artifacts="data/artifacts",
|
|
67
|
+
min_score=0.9)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### From the command line
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
themis-query --site fsmi --datetime 2015-03-18T06 --frame 412 \
|
|
74
|
+
--artifacts data/artifacts --output results.csv
|
|
75
|
+
|
|
76
|
+
# threshold mode: every match scoring >= 0.9, instead of a fixed --results count
|
|
77
|
+
themis-query --site fsmi --datetime 2015-03-18T06 --frame 412 \
|
|
78
|
+
--artifacts data/artifacts --min-score 0.9 --output results.csv
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Output columns are `site, datetime, score, source_cdf` — identical to the
|
|
82
|
+
dashboard's CSV export.
|
|
83
|
+
|
|
84
|
+
## Build an index from scratch
|
|
85
|
+
|
|
86
|
+
Note that the full THEMIS ASI archive is ~1M CDFs (over 100 TB) and building the index takes on the order of GPU-days; the
|
|
87
|
+
prebuilt index (about 72 GB) is **not** currently downloadable. If you are interested in obtaining it please email me to discuss.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# 1. fetch the encoder weights (44 MB)
|
|
92
|
+
python -c "from themisim import fetch_weights; print(fetch_weights())"
|
|
93
|
+
|
|
94
|
+
# 2. one-shot pipeline (download + build)
|
|
95
|
+
SITES=fsmi START=2015-03 END=2015-03 ./scripts/run_pipeline.sh
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
or step by step:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
themis-download --data-root data/cdf --sites fsmi --start 2015-03 --end 2015-03
|
|
102
|
+
themis-build-index --data-root data/cdf --artifacts data/artifacts \
|
|
103
|
+
--checkpoint weights/aurora-fm-no-finetune.tar
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The equivalent Python API:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from themisim import download_archive, build_index
|
|
110
|
+
|
|
111
|
+
download_archive("data/cdf", sites=["fsmi"], start="2015-03", end="2015-03")
|
|
112
|
+
build_index("data/cdf", "data/artifacts",
|
|
113
|
+
"weights/aurora-fm-no-finetune.tar")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`build_index` runs inventory → embed → concat → train/build, resuming cleanly
|
|
117
|
+
if interrupted (already-embedded hours are skipped). `--nlist auto` scales the
|
|
118
|
+
IVF cell count to the dataset size.
|
|
119
|
+
|
|
120
|
+
## Model weights
|
|
121
|
+
|
|
122
|
+
`fetch_weights()` downloads and SHA-256-verifies the ~44 MB SimCLR checkpoint
|
|
123
|
+
into `./weights` (override with `$THEMIS_ASI_WEIGHTS`). It is pulled from the
|
|
124
|
+
public Hugging Face repo
|
|
125
|
+
[`Jwjohnson314/Aurora-FM`](https://huggingface.co/Jwjohnson314/Aurora-FM); override
|
|
126
|
+
the URL via `$THEMIS_ASI_WEIGHTS_URL` or pass `url=`. If you already have the
|
|
127
|
+
`.tar`, drop it in the weights directory and it will be verified and reused
|
|
128
|
+
without a network call.
|
|
129
|
+
|
|
130
|
+
## Paths / configuration
|
|
131
|
+
|
|
132
|
+
Resolved from explicit arguments, then environment variables, then defaults:
|
|
133
|
+
|
|
134
|
+
| what | env var | default |
|
|
135
|
+
|------|---------|---------|
|
|
136
|
+
| downloaded CDFs | `THEMIS_ASI_DATA_ROOT` | `./data/cdf` |
|
|
137
|
+
| index artifacts | `THEMIS_ASI_ARTIFACTS` | `./data/artifacts` |
|
|
138
|
+
| model weights | `THEMIS_ASI_WEIGHTS` | `./weights` |
|
|
139
|
+
|
|
140
|
+
An artifacts directory contains `index.faiss`, `manifest.parquet`,
|
|
141
|
+
`vectors.f16.dat`, and `vectors.meta.json`.
|
|
142
|
+
|
|
143
|
+
## License, data & citation
|
|
144
|
+
|
|
145
|
+
The **code** in this repository is MIT-licensed — see [LICENSE](LICENSE).
|
|
146
|
+
|
|
147
|
+
The assets this tool downloads carry their own terms, which you must honor when
|
|
148
|
+
publishing results:
|
|
149
|
+
|
|
150
|
+
- **Model weights** (`Jwjohnson314/Aurora-FM`) are released under
|
|
151
|
+
**CC-BY-4.0** — attribution required.
|
|
152
|
+
- **THEMIS ASI data** is provided by the THEMIS mission (UC Berkeley / NASA) and
|
|
153
|
+
is subject to the
|
|
154
|
+
[THEMIS data use & citation policy](https://themis.ssl.berkeley.edu/roadrules.shtml).
|
|
155
|
+
Acknowledge the mission and instrument teams in any publication.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "themisim"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Similarity search over THEMIS all-sky imager imagery using SimCLR encoder features and a FAISS index"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Jeremiah Johnson" }]
|
|
14
|
+
keywords = ["aurora", "THEMIS", "all-sky-imager", "similarity-search", "faiss", "self-supervised"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Astronomy",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Image Processing",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"torch>=2.0",
|
|
27
|
+
"torchvision>=0.15",
|
|
28
|
+
"numpy>=1.24,<2",
|
|
29
|
+
"pandas>=2.0",
|
|
30
|
+
"pyarrow>=11",
|
|
31
|
+
"Pillow>=9.4",
|
|
32
|
+
"cdflib>=1.2",
|
|
33
|
+
# CPU FAISS is sufficient: the query path is CPU-only (the index is
|
|
34
|
+
# memory-mapped and disk-paged). GPU users who already have a conda
|
|
35
|
+
# faiss build can install with --no-deps to keep it.
|
|
36
|
+
"faiss-cpu>=1.8",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
dev = ["pytest>=7.4", "pytest-cov>=4"]
|
|
41
|
+
notebook = ["jupyter", "matplotlib"]
|
|
42
|
+
docs = ["sphinx>=7", "furo>=2024.1"]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
themis-download = "themisim.cli.download:main"
|
|
46
|
+
themis-build-index = "themisim.cli.build_index:main"
|
|
47
|
+
themis-query = "themisim.cli.query:main"
|
|
48
|
+
|
|
49
|
+
[project.urls]
|
|
50
|
+
Homepage = "https://github.com/jwjohnson314/themisim"
|
|
51
|
+
Documentation = "https://jwjohnson314.github.io/themisim/"
|
|
52
|
+
Source = "https://github.com/jwjohnson314/themisim"
|
|
53
|
+
Issues = "https://github.com/jwjohnson314/themisim/issues"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.packages.find]
|
|
56
|
+
where = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
python_files = ["test_*.py"]
|
|
61
|
+
addopts = "-ra"
|
|
62
|
+
pythonpath = ["src"]
|
themisim-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""THEMIS all-sky imager similarity search.
|
|
2
|
+
|
|
3
|
+
A standalone, pip-installable extraction of the THEMIS similarity-search
|
|
4
|
+
engine: download the archive, build a FAISS index from the pretrained SimCLR
|
|
5
|
+
encoder, and query it by ``(site, datetime, frame)``.
|
|
6
|
+
|
|
7
|
+
Quick start (query an existing index)::
|
|
8
|
+
|
|
9
|
+
from themisim import query
|
|
10
|
+
df = query("fsmi", "2015-03-18T06", 412, artifacts="data/artifacts")
|
|
11
|
+
|
|
12
|
+
Build an index from scratch::
|
|
13
|
+
|
|
14
|
+
from themisim import download_archive, build_index
|
|
15
|
+
download_archive("data/cdf", sites=["fsmi"], start="2015-03", end="2015-03")
|
|
16
|
+
build_index("data/cdf", "data/artifacts", "weights/<checkpoint>.tar")
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
# Establish the torch-before-faiss import order before anything pulls in faiss
|
|
21
|
+
# (the query stack imports faiss). torch and faiss ship conflicting CUDA libs
|
|
22
|
+
# and break each other's loader if faiss is imported first; importing torch
|
|
23
|
+
# here (when present) is a no-op safety net. Absent torch (query-only installs)
|
|
24
|
+
# this is simply skipped and faiss loads alone, which is fine.
|
|
25
|
+
try: # pragma: no cover - environment dependent
|
|
26
|
+
import torch as _torch # noqa: F401
|
|
27
|
+
except Exception: # pragma: no cover
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
from themisim.export import ( # noqa: E402
|
|
31
|
+
hits_to_dataframe,
|
|
32
|
+
results_csv_filename,
|
|
33
|
+
)
|
|
34
|
+
from themisim.query import query, resolve_global_id # noqa: E402
|
|
35
|
+
from themisim.search import Hit, SearchEngine # noqa: E402
|
|
36
|
+
|
|
37
|
+
__version__ = "0.1.0"
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"query",
|
|
41
|
+
"resolve_global_id",
|
|
42
|
+
"SearchEngine",
|
|
43
|
+
"Hit",
|
|
44
|
+
"hits_to_dataframe",
|
|
45
|
+
"results_csv_filename",
|
|
46
|
+
"download_archive",
|
|
47
|
+
"build_index",
|
|
48
|
+
"fetch_weights",
|
|
49
|
+
"visualize_results",
|
|
50
|
+
"__version__",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def __getattr__(name: str):
|
|
55
|
+
"""Lazily expose the build pipeline + weights helper.
|
|
56
|
+
|
|
57
|
+
Kept out of the eager import path so ``import themisim`` stays
|
|
58
|
+
cheap (and torch-free) for query-only use; ``build_index`` /
|
|
59
|
+
``download_archive`` pull in the embed/index stack only when first used.
|
|
60
|
+
"""
|
|
61
|
+
if name in ("build_index", "download_archive"):
|
|
62
|
+
from themisim import pipeline
|
|
63
|
+
|
|
64
|
+
return getattr(pipeline, name)
|
|
65
|
+
if name == "fetch_weights":
|
|
66
|
+
from themisim.weights import fetch_weights
|
|
67
|
+
|
|
68
|
+
return fetch_weights
|
|
69
|
+
if name == "visualize_results":
|
|
70
|
+
from themisim.viz import visualize_results
|
|
71
|
+
|
|
72
|
+
return visualize_results
|
|
73
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|