thuban 0.0.4__tar.gz → 0.0.6__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.
- thuban-0.0.6/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- thuban-0.0.6/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- {thuban-0.0.4 → thuban-0.0.6}/.github/workflows/ci_fixed.yaml +1 -1
- {thuban-0.0.4 → thuban-0.0.6}/.pre-commit-config.yaml +6 -3
- thuban-0.0.6/CHANGELOG.md +32 -0
- {thuban-0.0.4/thuban.egg-info → thuban-0.0.6}/PKG-INFO +6 -4
- {thuban-0.0.4 → thuban-0.0.6}/README.md +1 -1
- {thuban-0.0.4 → thuban-0.0.6}/docs/conf.py +9 -1
- {thuban-0.0.4 → thuban-0.0.6}/pyproject.toml +2 -2
- {thuban-0.0.4 → thuban-0.0.6}/thuban/cli.py +37 -23
- {thuban-0.0.4 → thuban-0.0.6}/thuban/distortion.py +1 -1
- {thuban-0.0.4 → thuban-0.0.6}/thuban/pointing.py +60 -46
- {thuban-0.0.4 → thuban-0.0.6/thuban.egg-info}/PKG-INFO +6 -4
- {thuban-0.0.4 → thuban-0.0.6}/thuban.egg-info/SOURCES.txt +3 -1
- {thuban-0.0.4 → thuban-0.0.6}/thuban.egg-info/requires.txt +2 -1
- thuban-0.0.4/.github/workflows/docs.yaml +0 -36
- {thuban-0.0.4 → thuban-0.0.6}/.github/workflows/ci.yaml +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/.github/workflows/publish.yaml +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/.gitignore +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/.readthedocs.yaml +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/CITATION.cff +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/LICENSE +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/MANIFEST.in +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/codecov.yaml +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/docs/Makefile +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/docs/_static/favicon.ico +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/docs/_static/logo.png +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/docs/index.rst +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/docs/make.bat +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/scripts/prepare_reduced_hip.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/setup.cfg +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/tests/__init__.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/tests/test_catalog.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/tests/test_cli.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/tests/test_distortion.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/tests/test_pointing.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/tests/test_util.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/tests/test_visualize.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban/__init__.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban/catalog.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban/data/reduced_hip.csv +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban/error.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban/simulate.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban/util.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban/visualize.py +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban.egg-info/dependency_links.txt +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban.egg-info/entry_points.txt +0 -0
- {thuban-0.0.4 → thuban-0.0.6}/thuban.egg-info/top_level.txt +0 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Describe the bug**
|
11
|
+
A clear and concise description of what the bug is.
|
12
|
+
|
13
|
+
**To Reproduce**
|
14
|
+
Steps to reproduce the behavior:
|
15
|
+
1. Go to '...'
|
16
|
+
2. Click on '....'
|
17
|
+
3. Scroll down to '....'
|
18
|
+
4. See error
|
19
|
+
|
20
|
+
**Expected behavior**
|
21
|
+
A clear and concise description of what you expected to happen.
|
22
|
+
|
23
|
+
**Screenshots**
|
24
|
+
If applicable, add screenshots to help explain your problem.
|
25
|
+
|
26
|
+
**Desktop (please complete the following information):**
|
27
|
+
- OS: [e.g. iOS]
|
28
|
+
- Browser [e.g. chrome, safari]
|
29
|
+
- Version [e.g. 22]
|
30
|
+
|
31
|
+
**Smartphone (please complete the following information):**
|
32
|
+
- Device: [e.g. iPhone6]
|
33
|
+
- OS: [e.g. iOS8.1]
|
34
|
+
- Browser [e.g. stock browser, safari]
|
35
|
+
- Version [e.g. 22]
|
36
|
+
|
37
|
+
**Additional context**
|
38
|
+
Add any other context about the problem here.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea for this project
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Is your feature request related to a problem? Please describe.**
|
11
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
12
|
+
|
13
|
+
**Describe the solution you'd like**
|
14
|
+
A clear and concise description of what you want to happen.
|
15
|
+
|
16
|
+
**Describe alternatives you've considered**
|
17
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
18
|
+
|
19
|
+
**Additional context**
|
20
|
+
Add any other context or screenshots about the feature request here.
|
@@ -3,19 +3,19 @@ repos:
|
|
3
3
|
# This should be before any formatting hooks like isort
|
4
4
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
5
5
|
# Ruff version.
|
6
|
-
rev: v0.
|
6
|
+
rev: v0.11.4
|
7
7
|
hooks:
|
8
8
|
# Run the linter.
|
9
9
|
- id: ruff
|
10
10
|
types_or: [ python, pyi ]
|
11
11
|
args: [ --fix ]
|
12
12
|
- repo: https://github.com/PyCQA/isort
|
13
|
-
rev:
|
13
|
+
rev: 6.0.1
|
14
14
|
hooks:
|
15
15
|
- id: isort
|
16
16
|
exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|extern.*|sunpy/extern)$"
|
17
17
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
18
|
-
rev:
|
18
|
+
rev: v5.0.0
|
19
19
|
hooks:
|
20
20
|
- id: check-ast
|
21
21
|
- id: check-case-conflict
|
@@ -29,3 +29,6 @@ repos:
|
|
29
29
|
exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|.json)$|^CITATION.rst$"
|
30
30
|
- id: mixed-line-ending
|
31
31
|
exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*)$"
|
32
|
+
ci:
|
33
|
+
autofix_prs: false
|
34
|
+
autoupdate_schedule: "quarterly"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
[Also available through GitHub interface](https://github.com/punch-mission/thuban/releases)
|
4
|
+
|
5
|
+
## Version 0.0.6: May 22, 2025
|
6
|
+
|
7
|
+
* specify codecov path by @jmbhughes in https://github.com/punch-mission/thuban/pull/18
|
8
|
+
* Update issue templates by @jmbhughes in https://github.com/punch-mission/thuban/pull/19
|
9
|
+
* Support more PUNCH features in https://github.com/punch-mission/thuban/pull/25
|
10
|
+
|
11
|
+
## Version 0.0.5: Nov 13, 2024
|
12
|
+
|
13
|
+
- Fix version names in docs by @jmbhughes in #12
|
14
|
+
- add tolerances by @jmbhughes in #13
|
15
|
+
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in #14
|
16
|
+
|
17
|
+
## Version 0.0.4: Nov 1, 2024
|
18
|
+
|
19
|
+
- Add pinned environment ci by @jmbhughes in #10
|
20
|
+
- Create .readthedocs.yaml by @jmbhughes in #11
|
21
|
+
|
22
|
+
## Version 0.0.3: Aug 24, 2024
|
23
|
+
|
24
|
+
- incorporates masking and pv by @jmbhughes in #8
|
25
|
+
|
26
|
+
## Version 0.0.2: Aug 18, 2024
|
27
|
+
|
28
|
+
- add file manifest by @jmbhughes in #7
|
29
|
+
|
30
|
+
## Version 0.0.1: Aug 18, 2024
|
31
|
+
|
32
|
+
Initial release
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: thuban
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.6
|
4
4
|
Summary: High precision and accuracy astrometric image solving from a guess
|
5
5
|
Author-email: "J. Marcus Hughes" <hughes.jmb@gmail.com>
|
6
6
|
Maintainer-email: "J. Marcus Hughes" <hughes.jmb@gmail.com>
|
@@ -19,7 +19,7 @@ Requires-Dist: numpy
|
|
19
19
|
Requires-Dist: astropy
|
20
20
|
Requires-Dist: matplotlib
|
21
21
|
Requires-Dist: pandas
|
22
|
-
Requires-Dist: sep
|
22
|
+
Requires-Dist: sep
|
23
23
|
Requires-Dist: scipy
|
24
24
|
Requires-Dist: scikit-learn
|
25
25
|
Requires-Dist: lmfit
|
@@ -38,13 +38,15 @@ Requires-Dist: sphinx-automodapi; extra == "docs"
|
|
38
38
|
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
39
39
|
Requires-Dist: sphinx-favicon; extra == "docs"
|
40
40
|
Requires-Dist: ipython; extra == "docs"
|
41
|
+
Requires-Dist: packaging; extra == "docs"
|
42
|
+
Dynamic: license-file
|
41
43
|
|
42
44
|
# thuban
|
43
45
|
|
44
46
|
High precision astrometric image solving from a guess.
|
45
47
|
|
46
48
|
> [!WARNING]
|
47
|
-
> This package
|
49
|
+
> This package may still have significant changes until v1.
|
48
50
|
|
49
51
|
|
50
52
|
## To-do
|
@@ -2,6 +2,9 @@
|
|
2
2
|
#
|
3
3
|
# For the full list of built-in configuration values, see the documentation:
|
4
4
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
5
|
+
from importlib.metadata import version as get_version
|
6
|
+
|
7
|
+
from packaging.version import Version
|
5
8
|
|
6
9
|
# -- Project information -----------------------------------------------------
|
7
10
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
@@ -9,7 +12,12 @@
|
|
9
12
|
project = "thuban"
|
10
13
|
copyright = "2024, PUNCH Science Operations Center"
|
11
14
|
author = "PUNCH Science Operations Center"
|
12
|
-
|
15
|
+
|
16
|
+
release: str = get_version("thuban")
|
17
|
+
version: str = release
|
18
|
+
_version = Version(release)
|
19
|
+
if _version.is_devrelease:
|
20
|
+
version = release = f"{_version.base_version}.dev{_version.dev}"
|
13
21
|
|
14
22
|
# -- General configuration ---------------------------------------------------
|
15
23
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
@@ -10,7 +10,7 @@ dependencies = ["numpy",
|
|
10
10
|
"astropy",
|
11
11
|
"matplotlib",
|
12
12
|
"pandas",
|
13
|
-
"sep
|
13
|
+
"sep",
|
14
14
|
"scipy",
|
15
15
|
"scikit-learn",
|
16
16
|
"lmfit",
|
@@ -35,7 +35,7 @@ classifiers = [
|
|
35
35
|
|
36
36
|
[project.optional-dependencies]
|
37
37
|
test = ["pytest", "pytest-doctestplus", "pytest-cov", "ruff", "coverage"]
|
38
|
-
docs = ["sphinx", "sphinx-autoapi", "sphinx-automodapi", "pydata-sphinx-theme", "sphinx-favicon", "ipython"]
|
38
|
+
docs = ["sphinx", "sphinx-autoapi", "sphinx-automodapi", "pydata-sphinx-theme", "sphinx-favicon", "ipython", "packaging"]
|
39
39
|
|
40
40
|
[project.scripts]
|
41
41
|
thuban = "thuban.cli:determine_pointing_and_distortion"
|
@@ -5,7 +5,7 @@ from pathlib import Path
|
|
5
5
|
|
6
6
|
import click
|
7
7
|
import numpy as np
|
8
|
-
import
|
8
|
+
import sep
|
9
9
|
from astropy.io import fits
|
10
10
|
from astropy.wcs import WCS
|
11
11
|
from tqdm import tqdm
|
@@ -38,9 +38,8 @@ def open_files(paths: [Path], byte_swap=True) -> (np.ndarray, [fits.Header]):
|
|
38
38
|
for filename in tqdm(paths):
|
39
39
|
with fits.open(filename) as hdul:
|
40
40
|
if byte_swap:
|
41
|
-
|
42
|
-
|
43
|
-
data = hdul[data_hdu_num].data.astype(float)
|
41
|
+
raise NotImplementedError()
|
42
|
+
data = hdul[data_hdu_num].data.astype(float)
|
44
43
|
head = hdul[data_hdu_num].header
|
45
44
|
all_wcses.append(WCS(head, hdul, key=celestial_wcs_key))
|
46
45
|
all_data.append(data)
|
@@ -79,8 +78,6 @@ def determine_pointing_and_distortion(directory, byte_swap=True, num_stars=20,
|
|
79
78
|
# data[:, :edge, :] = 0.0
|
80
79
|
# data[:, -edge:, :] = 0.0
|
81
80
|
# data[:, :, -edge:] = 0.0
|
82
|
-
|
83
|
-
print(headers)
|
84
81
|
current_wcses = [convert_cd_matrix_to_pc_matrix(w) for w in all_wcses]
|
85
82
|
|
86
83
|
# remove any SIP distortion model and make an empty table
|
@@ -91,7 +88,6 @@ def determine_pointing_and_distortion(directory, byte_swap=True, num_stars=20,
|
|
91
88
|
wcs.sip = None
|
92
89
|
wcs.cpdis1 = cpdis1
|
93
90
|
wcs.cpdis2 = cpdis2
|
94
|
-
print(current_wcses[0].wcs.cunit)
|
95
91
|
|
96
92
|
counts = []
|
97
93
|
for iteration in range(iterations):
|
@@ -110,13 +106,18 @@ def determine_pointing_and_distortion(directory, byte_swap=True, num_stars=20,
|
|
110
106
|
current_wcses[file_index],
|
111
107
|
file_index,
|
112
108
|
detection_threshold=threshold,
|
113
|
-
max_trials=
|
109
|
+
max_trials=10,
|
114
110
|
dimmest_magnitude=magnitude,
|
115
111
|
num_stars=num_stars,
|
116
112
|
background_width=background,
|
117
113
|
background_height=background,
|
118
|
-
chisqr_threshold=0.
|
119
|
-
|
114
|
+
chisqr_threshold=0.1,
|
115
|
+
max_error=150,
|
116
|
+
method='least_squares',
|
117
|
+
fix_crota=False,
|
118
|
+
fix_crval=False,
|
119
|
+
fix_pv=iteration == 0 or iteration == iterations - 1,
|
120
|
+
fix_cdelt=True or iteration == iterations - 1 or iteration % 2 == 1))
|
120
121
|
|
121
122
|
print("\tprocessing")
|
122
123
|
with tqdm(total=len(futures)) as pbar:
|
@@ -124,21 +125,28 @@ def determine_pointing_and_distortion(directory, byte_swap=True, num_stars=20,
|
|
124
125
|
|
125
126
|
updated_wcs, _, solution, num_trials, file_index = future.result()
|
126
127
|
current_wcses[file_index] = updated_wcs
|
128
|
+
pbar.update(1)
|
127
129
|
|
130
|
+
global_pv = np.mean([w.wcs.get_pv()[0][-1] for w in current_wcses])
|
131
|
+
global_cdelt1 = np.mean([w.wcs.cdelt[0] for w in current_wcses])
|
132
|
+
global_cdelt2 = np.mean([w.wcs.cdelt[1] for w in current_wcses])
|
128
133
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
134
|
+
for file_index in range(len(current_wcses)):
|
135
|
+
updated_wcs = current_wcses[file_index]
|
136
|
+
updated_wcs.wcs.cdelt = (global_cdelt1, global_cdelt2)
|
137
|
+
updated_wcs.wcs.set_pv([(2, 1, global_pv)])
|
133
138
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
139
|
+
bg = sep.Background(data[file_index], bw=background, bh=background)
|
140
|
+
data_sub = data[file_index] - bg
|
141
|
+
objects = sep.extract(data_sub, threshold, err=bg.globalrms)
|
142
|
+
observed_coords = np.stack([objects["x"], objects["y"]], axis=-1)
|
138
143
|
|
139
|
-
|
140
|
-
|
141
|
-
|
144
|
+
new_stars = find_catalog_in_image(
|
145
|
+
filter_for_visible_stars(load_hipparcos_catalog(), dimmest_magnitude=8.0),
|
146
|
+
updated_wcs, data.shape[1:], mode='wcs')
|
147
|
+
all_no_distortion.append(np.stack([new_stars['x_pix'], new_stars['y_pix']], axis=-1))
|
148
|
+
|
149
|
+
all_found_positions.append(observed_coords)
|
142
150
|
|
143
151
|
# log.append((all_corrected_positions, all_found_positions))
|
144
152
|
# TODO: move lower to fix counting of stars
|
@@ -149,7 +157,7 @@ def determine_pointing_and_distortion(directory, byte_swap=True, num_stars=20,
|
|
149
157
|
for i in range(len(all_no_distortion)):
|
150
158
|
observed_filtered, refined_filtered = remove_pairless_points(all_found_positions[i],
|
151
159
|
all_no_distortion[i],
|
152
|
-
max_distance=
|
160
|
+
max_distance=150)
|
153
161
|
if (observed_filtered.ndim == 2 and refined_filtered.ndim == 2
|
154
162
|
and len(observed_filtered) > 0 and len(refined_filtered) > 0):
|
155
163
|
final_observations.append(observed_filtered)
|
@@ -164,6 +172,12 @@ def determine_pointing_and_distortion(directory, byte_swap=True, num_stars=20,
|
|
164
172
|
final_observations,
|
165
173
|
final_refined,
|
166
174
|
num_bins=num_bins)
|
175
|
+
if iteration != iterations - 1:
|
176
|
+
center_x_val = cpdis1.data[num_bins//2, num_bins//2]
|
177
|
+
center_y_val = cpdis2.data[num_bins//2, num_bins//2]
|
178
|
+
|
179
|
+
cpdis1.data -= center_x_val
|
180
|
+
cpdis2.data -= center_y_val
|
167
181
|
|
168
182
|
for wcs in current_wcses:
|
169
183
|
wcs.cpdis1 = cpdis1
|
@@ -177,4 +191,4 @@ def determine_pointing_and_distortion(directory, byte_swap=True, num_stars=20,
|
|
177
191
|
_, extension = os.path.splitext(fn)
|
178
192
|
hdul = updated_wcs.to_fits() # improve the writing mechanism
|
179
193
|
hdul[0].data = img
|
180
|
-
hdul.writeto(str(fn).replace(extension, "_repoint.fits"), overwrite=True) # todo make postfix
|
194
|
+
hdul.writeto(str(fn).replace(extension, "_repoint.fits"), overwrite=True) # todo make postfix an option
|
@@ -131,7 +131,7 @@ def compute_distortion(
|
|
131
131
|
img_shape: (int, int),
|
132
132
|
catalog_positions: np.ndarray,
|
133
133
|
found_positions: np.ndarray,
|
134
|
-
distortion_limit: float =20, num_bins: int =75, blur_sigma: float =
|
134
|
+
distortion_limit: float =20, num_bins: int =75, blur_sigma: float = 1, med_filter_size: int = 1
|
135
135
|
) -> (DistortionLookupTable, DistortionLookupTable):
|
136
136
|
""" Given the derived catalog and actual star positions, determines the distortion
|
137
137
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import warnings
|
2
2
|
from typing import Callable
|
3
3
|
|
4
|
+
import astropy.units as u
|
4
5
|
import numpy as np
|
5
6
|
import pandas as pd
|
6
|
-
import
|
7
|
+
import sep
|
7
8
|
from astropy.wcs import WCS, utils
|
8
|
-
import astropy.units as u
|
9
9
|
from lmfit import Parameters, minimize
|
10
10
|
|
11
11
|
from thuban.catalog import (filter_for_visible_stars, find_catalog_in_image,
|
@@ -63,6 +63,7 @@ def _residual(params: Parameters,
|
|
63
63
|
image_shape: (int, int),
|
64
64
|
edge: int = 100,
|
65
65
|
sigma: float = 3.0,
|
66
|
+
max_error: float = 15,
|
66
67
|
mask: Callable = None):
|
67
68
|
"""Residual used when optimizing the pointing
|
68
69
|
|
@@ -83,18 +84,15 @@ def _residual(params: Parameters,
|
|
83
84
|
np.ndarray
|
84
85
|
residual
|
85
86
|
"""
|
86
|
-
refined_wcs =
|
87
|
-
refined_wcs.wcs.
|
88
|
-
refined_wcs.wcs.cunit = guess_wcs.wcs.cunit
|
89
|
-
refined_wcs.wcs.cdelt = guess_wcs.wcs.cdelt
|
90
|
-
refined_wcs.wcs.crpix = guess_wcs.wcs.crpix
|
87
|
+
refined_wcs = guess_wcs.deepcopy()
|
88
|
+
refined_wcs.wcs.cdelt = (params['cdelt1'].value, params['cdelt2'].value)
|
91
89
|
refined_wcs.wcs.crval = (params["crval1"].value, params["crval2"].value)
|
92
|
-
refined_wcs.wcs.pc = calculate_pc_matrix(params["crota"],
|
90
|
+
refined_wcs.wcs.pc = calculate_pc_matrix(params["crota"], (params['cdelt1'], params['cdelt2']))
|
93
91
|
refined_wcs.cpdis1 = guess_wcs.cpdis1
|
94
92
|
refined_wcs.cpdis2 = guess_wcs.cpdis2
|
95
|
-
refined_wcs.wcs.set_pv(
|
93
|
+
refined_wcs.wcs.set_pv([(2, 1, params['pv'].value)])
|
96
94
|
|
97
|
-
reduced_catalog = find_catalog_in_image(catalog, refined_wcs, image_shape=image_shape, mask=mask)
|
95
|
+
reduced_catalog = find_catalog_in_image(catalog, refined_wcs, image_shape=image_shape, mask=mask, mode='wcs')
|
98
96
|
refined_coords = np.stack([reduced_catalog['x_pix'], reduced_catalog['y_pix']], axis=-1)
|
99
97
|
|
100
98
|
image_bounds = (image_shape[0] - edge, image_shape[1] - edge)
|
@@ -111,20 +109,26 @@ def _residual(params: Parameters,
|
|
111
109
|
out = np.array([np.min(np.linalg.norm(observed_coords - coord, axis=-1)) for coord in refined_coords[:n]])
|
112
110
|
median, stdev = np.median(out), np.std(out)
|
113
111
|
out[out > median + (sigma * stdev)] = 0.0 # TODO: should this be zero?
|
112
|
+
out[out > max_error] = 0.0 # TODO: should this be zero?
|
114
113
|
return out
|
115
114
|
|
116
115
|
|
117
116
|
def refine_pointing_wrapper(image, guess_wcs, file_num, observed_coords=None, catalog=None,
|
118
117
|
background_width=16, background_height=16,
|
119
118
|
detection_threshold=5, num_stars=30, max_trials=15, chisqr_threshold=0.1,
|
120
|
-
dimmest_magnitude=6.0, method='
|
119
|
+
dimmest_magnitude=6.0, method='least_squares', ra_tolerance=10, dec_tolerance=5, max_error=15,
|
120
|
+
fix_crval=False, fix_cdelt=True, fix_crota=False, fix_pv=True):
|
121
121
|
new_wcs, observed_coords, solution, trial_num = refine_pointing(image,
|
122
122
|
guess_wcs,
|
123
123
|
observed_coords=observed_coords, catalog=catalog,
|
124
124
|
background_width=background_width, background_height=background_height,
|
125
125
|
detection_threshold=detection_threshold, num_stars=num_stars, max_trials=max_trials,
|
126
126
|
chisqr_threshold=chisqr_threshold,
|
127
|
-
dimmest_magnitude=dimmest_magnitude, method=method
|
127
|
+
dimmest_magnitude=dimmest_magnitude, method=method,
|
128
|
+
ra_tolerance=ra_tolerance,
|
129
|
+
dec_tolerance=dec_tolerance, max_error=max_error,
|
130
|
+
fix_crval=fix_crval, fix_cdelt=fix_cdelt,
|
131
|
+
fix_crota=fix_crota, fix_pv=fix_pv)
|
128
132
|
return new_wcs, observed_coords, solution, trial_num, file_num
|
129
133
|
|
130
134
|
|
@@ -137,29 +141,9 @@ def extract_crota_from_wcs(wcs: WCS) -> tuple[float, float]:
|
|
137
141
|
def refine_pointing(image, guess_wcs, observed_coords=None, catalog=None,
|
138
142
|
background_width=16, background_height=16,
|
139
143
|
detection_threshold=5, num_stars=30, max_trials=15, chisqr_threshold=0.1,
|
140
|
-
dimmest_magnitude=6.0, method='
|
141
|
-
|
142
|
-
|
143
|
-
Parameters
|
144
|
-
----------
|
145
|
-
image : np.ndarray
|
146
|
-
the brightnesses of the image, no preprocessing necessary
|
147
|
-
guess_wcs : WCS
|
148
|
-
initial guess for th world coordinate system, must overlap with the true WCS
|
149
|
-
file_index
|
150
|
-
observed_coords
|
151
|
-
catalog
|
152
|
-
background_width
|
153
|
-
background_height
|
154
|
-
detection_threshold
|
155
|
-
x_lim
|
156
|
-
y_lim
|
157
|
-
n
|
158
|
-
|
159
|
-
Returns
|
160
|
-
-------
|
161
|
-
|
162
|
-
"""
|
144
|
+
dimmest_magnitude=6.0, method='least_squares', edge=100, sigma=3.0, mask=None,
|
145
|
+
ra_tolerance=10, dec_tolerance=5, max_error=15,
|
146
|
+
fix_crval=False, fix_cdelt=True, fix_crota=False, fix_pv=True):
|
163
147
|
if catalog is None:
|
164
148
|
catalog = filter_for_visible_stars(load_hipparcos_catalog(), dimmest_magnitude=dimmest_magnitude)
|
165
149
|
|
@@ -172,21 +156,54 @@ def refine_pointing(image, guess_wcs, observed_coords=None, catalog=None,
|
|
172
156
|
observed_coords = np.stack([objects["x"], objects["y"]], axis=-1)
|
173
157
|
if mask is not None:
|
174
158
|
observed_coords = observed_coords[mask(objects['x'], objects['y'])]
|
159
|
+
|
160
|
+
image_shape = image.shape
|
161
|
+
reduced_catalog = find_catalog_in_image(catalog, guess_wcs, image_shape=image_shape, mask=mask)
|
162
|
+
refined_coords = np.stack([reduced_catalog['x_pix'], reduced_catalog['y_pix']], axis=-1)
|
163
|
+
# print("catalog found", len(refined_coords), refined_coords)
|
164
|
+
|
165
|
+
image_bounds = (image_shape[0] - edge, image_shape[1] - edge)
|
166
|
+
refined_coords = np.array([c for c in refined_coords
|
167
|
+
if (c[0] > edge) and (c[1] > edge) and (c[0] < image_bounds[0]) and (
|
168
|
+
c[1] < image_bounds[1])])
|
169
|
+
|
170
|
+
distances = np.array([np.min(np.linalg.norm(refined_coords - coord, axis=-1)) for coord in observed_coords])
|
171
|
+
observed_coords = observed_coords[distances < max_error]
|
175
172
|
observed_coords = observed_coords[-3*num_stars:]
|
176
173
|
# set up the optimization
|
177
174
|
params = Parameters()
|
178
175
|
initial_crota = extract_crota_from_wcs(guess_wcs)
|
179
|
-
params.add("crota", value=initial_crota.to(u.rad).value,
|
180
|
-
|
181
|
-
params.add("
|
182
|
-
|
176
|
+
params.add("crota", value=initial_crota.to(u.rad).value,
|
177
|
+
min=-np.pi, max=np.pi, vary=not fix_crota)
|
178
|
+
params.add("crval1", value=guess_wcs.wcs.crval[0],
|
179
|
+
min=guess_wcs.wcs.crval[0]-ra_tolerance,
|
180
|
+
max=guess_wcs.wcs.crval[0]+ra_tolerance, vary=not fix_crval)
|
181
|
+
params.add("crval2", value=guess_wcs.wcs.crval[1],
|
182
|
+
min=guess_wcs.wcs.crval[1]-dec_tolerance,
|
183
|
+
max=guess_wcs.wcs.crval[1]+dec_tolerance, vary=not fix_crval)
|
184
|
+
params.add("cdelt1", value=guess_wcs.wcs.cdelt[0],
|
185
|
+
min=guess_wcs.wcs.cdelt[0]-1,
|
186
|
+
max=guess_wcs.wcs.cdelt[0]+1, vary=not fix_cdelt)
|
187
|
+
params.add("cdelt2", value=guess_wcs.wcs.cdelt[1],
|
188
|
+
min=max(guess_wcs.wcs.cdelt[1]-0.1, 0),
|
189
|
+
max=guess_wcs.wcs.cdelt[1]+0.1, vary=not fix_cdelt)
|
190
|
+
# if guess_wcs.wcs.get_pv():
|
191
|
+
# pv = guess_wcs.wcs.get_pv()[0][-1]
|
192
|
+
# print(pv)
|
193
|
+
# else:
|
194
|
+
# pv = 0.0
|
195
|
+
# params.add("pv", value=pv, min=0.0, max=1.0, vary=not fix_pv)
|
196
|
+
|
197
|
+
# return guess_wcs, observed_coords, None, None
|
183
198
|
# optimize
|
184
199
|
trial_num = 0
|
185
200
|
result_wcses, result_minimizations = [], []
|
186
201
|
while trial_num < max_trials:
|
187
202
|
try:
|
188
203
|
out = minimize(_residual, params, method=method,
|
189
|
-
args=(observed_coords, catalog, guess_wcs,
|
204
|
+
args=(observed_coords, catalog, guess_wcs,
|
205
|
+
num_stars, image.shape, edge, sigma, max_error, mask),
|
206
|
+
max_nfev=500, calc_covar=False)
|
190
207
|
chisqr = out.chisqr
|
191
208
|
result_minimizations.append(out)
|
192
209
|
except IndexError:
|
@@ -196,16 +213,13 @@ def refine_pointing(image, guess_wcs, observed_coords=None, catalog=None,
|
|
196
213
|
ConvergenceWarning)
|
197
214
|
else:
|
198
215
|
# construct the result
|
199
|
-
result_wcs =
|
200
|
-
result_wcs.wcs.
|
201
|
-
result_wcs.wcs.cunit = guess_wcs.wcs.cunit
|
202
|
-
result_wcs.wcs.cdelt = guess_wcs.wcs.cdelt
|
203
|
-
result_wcs.wcs.crpix = guess_wcs.wcs.crpix
|
216
|
+
result_wcs = guess_wcs.deepcopy()
|
217
|
+
result_wcs.wcs.cdelt = (out.params["cdelt1"].value, out.params["cdelt2"].value)
|
204
218
|
result_wcs.wcs.crval = (out.params["crval1"].value, out.params["crval2"].value)
|
205
219
|
result_wcs.wcs.pc = calculate_pc_matrix(out.params["crota"], result_wcs.wcs.cdelt)
|
206
220
|
result_wcs.cpdis1 = guess_wcs.cpdis1 # TODO: what if there is no known distortion
|
207
221
|
result_wcs.cpdis2 = guess_wcs.cpdis2
|
208
|
-
result_wcs.wcs.set_pv(
|
222
|
+
result_wcs.wcs.set_pv([(2, 1, out.params['pv'].value)])
|
209
223
|
result_wcses.append(result_wcs)
|
210
224
|
trial_num += 1
|
211
225
|
if chisqr < chisqr_threshold:
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: thuban
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.6
|
4
4
|
Summary: High precision and accuracy astrometric image solving from a guess
|
5
5
|
Author-email: "J. Marcus Hughes" <hughes.jmb@gmail.com>
|
6
6
|
Maintainer-email: "J. Marcus Hughes" <hughes.jmb@gmail.com>
|
@@ -19,7 +19,7 @@ Requires-Dist: numpy
|
|
19
19
|
Requires-Dist: astropy
|
20
20
|
Requires-Dist: matplotlib
|
21
21
|
Requires-Dist: pandas
|
22
|
-
Requires-Dist: sep
|
22
|
+
Requires-Dist: sep
|
23
23
|
Requires-Dist: scipy
|
24
24
|
Requires-Dist: scikit-learn
|
25
25
|
Requires-Dist: lmfit
|
@@ -38,13 +38,15 @@ Requires-Dist: sphinx-automodapi; extra == "docs"
|
|
38
38
|
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
39
39
|
Requires-Dist: sphinx-favicon; extra == "docs"
|
40
40
|
Requires-Dist: ipython; extra == "docs"
|
41
|
+
Requires-Dist: packaging; extra == "docs"
|
42
|
+
Dynamic: license-file
|
41
43
|
|
42
44
|
# thuban
|
43
45
|
|
44
46
|
High precision astrometric image solving from a guess.
|
45
47
|
|
46
48
|
> [!WARNING]
|
47
|
-
> This package
|
49
|
+
> This package may still have significant changes until v1.
|
48
50
|
|
49
51
|
|
50
52
|
## To-do
|
@@ -1,15 +1,17 @@
|
|
1
1
|
.gitignore
|
2
2
|
.pre-commit-config.yaml
|
3
3
|
.readthedocs.yaml
|
4
|
+
CHANGELOG.md
|
4
5
|
CITATION.cff
|
5
6
|
LICENSE
|
6
7
|
MANIFEST.in
|
7
8
|
README.md
|
8
9
|
codecov.yaml
|
9
10
|
pyproject.toml
|
11
|
+
.github/ISSUE_TEMPLATE/bug_report.md
|
12
|
+
.github/ISSUE_TEMPLATE/feature_request.md
|
10
13
|
.github/workflows/ci.yaml
|
11
14
|
.github/workflows/ci_fixed.yaml
|
12
|
-
.github/workflows/docs.yaml
|
13
15
|
.github/workflows/publish.yaml
|
14
16
|
docs/Makefile
|
15
17
|
docs/conf.py
|
@@ -1,36 +0,0 @@
|
|
1
|
-
name: deploy-docs
|
2
|
-
|
3
|
-
# Only run this when the master branch changes
|
4
|
-
on:
|
5
|
-
push:
|
6
|
-
branches:
|
7
|
-
- main
|
8
|
-
|
9
|
-
# This job installs dependencies, builds the book, and pushes it to `gh-pages`
|
10
|
-
jobs:
|
11
|
-
deploy-docs:
|
12
|
-
runs-on: ubuntu-latest
|
13
|
-
steps:
|
14
|
-
- uses: actions/checkout@v2
|
15
|
-
|
16
|
-
# Install dependencies
|
17
|
-
- name: Set up Python 3.10
|
18
|
-
uses: actions/setup-python@v2
|
19
|
-
with:
|
20
|
-
python-version: "3.10"
|
21
|
-
|
22
|
-
- name: Install dependencies
|
23
|
-
run: |
|
24
|
-
pip install ".[docs]"
|
25
|
-
|
26
|
-
# Build the book
|
27
|
-
- name: Sphinx build
|
28
|
-
run: |
|
29
|
-
cd ./docs; make html; cd ..
|
30
|
-
|
31
|
-
# Push the book's HTML to github-pages
|
32
|
-
- name: GitHub Pages action
|
33
|
-
uses: peaceiris/actions-gh-pages@v3.6.1
|
34
|
-
with:
|
35
|
-
github_token: ${{ secrets.GITHUB_TOKEN }}
|
36
|
-
publish_dir: ./docs/_build/html
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|