thuban 0.0.2__tar.gz → 0.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.
Files changed (28) hide show
  1. {thuban-0.0.2 → thuban-0.0.3}/PKG-INFO +1 -1
  2. {thuban-0.0.2 → thuban-0.0.3}/pyproject.toml +1 -1
  3. {thuban-0.0.2 → thuban-0.0.3}/thuban/catalog.py +6 -1
  4. {thuban-0.0.2 → thuban-0.0.3}/thuban/pointing.py +28 -17
  5. {thuban-0.0.2 → thuban-0.0.3}/thuban.egg-info/PKG-INFO +1 -1
  6. {thuban-0.0.2 → thuban-0.0.3}/LICENSE +0 -0
  7. {thuban-0.0.2 → thuban-0.0.3}/MANIFEST.in +0 -0
  8. {thuban-0.0.2 → thuban-0.0.3}/README.md +0 -0
  9. {thuban-0.0.2 → thuban-0.0.3}/setup.cfg +0 -0
  10. {thuban-0.0.2 → thuban-0.0.3}/tests/test_catalog.py +0 -0
  11. {thuban-0.0.2 → thuban-0.0.3}/tests/test_cli.py +0 -0
  12. {thuban-0.0.2 → thuban-0.0.3}/tests/test_distortion.py +0 -0
  13. {thuban-0.0.2 → thuban-0.0.3}/tests/test_pointing.py +0 -0
  14. {thuban-0.0.2 → thuban-0.0.3}/tests/test_util.py +0 -0
  15. {thuban-0.0.2 → thuban-0.0.3}/tests/test_visualize.py +0 -0
  16. {thuban-0.0.2 → thuban-0.0.3}/thuban/__init__.py +0 -0
  17. {thuban-0.0.2 → thuban-0.0.3}/thuban/cli.py +0 -0
  18. {thuban-0.0.2 → thuban-0.0.3}/thuban/data/reduced_hip.csv +0 -0
  19. {thuban-0.0.2 → thuban-0.0.3}/thuban/distortion.py +0 -0
  20. {thuban-0.0.2 → thuban-0.0.3}/thuban/error.py +0 -0
  21. {thuban-0.0.2 → thuban-0.0.3}/thuban/simulate.py +0 -0
  22. {thuban-0.0.2 → thuban-0.0.3}/thuban/util.py +0 -0
  23. {thuban-0.0.2 → thuban-0.0.3}/thuban/visualize.py +0 -0
  24. {thuban-0.0.2 → thuban-0.0.3}/thuban.egg-info/SOURCES.txt +0 -0
  25. {thuban-0.0.2 → thuban-0.0.3}/thuban.egg-info/dependency_links.txt +0 -0
  26. {thuban-0.0.2 → thuban-0.0.3}/thuban.egg-info/entry_points.txt +0 -0
  27. {thuban-0.0.2 → thuban-0.0.3}/thuban.egg-info/requires.txt +0 -0
  28. {thuban-0.0.2 → thuban-0.0.3}/thuban.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: thuban
3
- Version: 0.0.2
3
+ Version: 0.0.3
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>
@@ -5,7 +5,7 @@ requires = ["setuptools",
5
5
 
6
6
  [project]
7
7
  name = "thuban"
8
- version = "0.0.2"
8
+ version = "0.0.3"
9
9
  dependencies = ["numpy",
10
10
  "astropy",
11
11
  "matplotlib",
@@ -1,4 +1,5 @@
1
1
  import os
2
+ from typing import Callable
2
3
 
3
4
  import astropy.units as u
4
5
  import numpy as np
@@ -163,7 +164,7 @@ def filter_for_visible_stars(catalog: pd.DataFrame, dimmest_magnitude: float = 6
163
164
 
164
165
 
165
166
  def find_catalog_in_image(
166
- catalog: pd.DataFrame, wcs: WCS, image_shape: (int, int),
167
+ catalog: pd.DataFrame, wcs: WCS, image_shape: (int, int), mask: Callable = None,
167
168
  mode: str = "all"
168
169
  ) -> np.ndarray:
169
170
  """Using the provided WCS converts the RA/DEC catalog into pixel coordinates
@@ -195,6 +196,10 @@ def find_catalog_in_image(
195
196
  except NoConvergence as e:
196
197
  xs, ys = e.best_solution[:, 0], e.best_solution[:, 1]
197
198
  bounds_mask = (0 <= xs) * (xs < image_shape[0]) * (0 <= ys) * (ys < image_shape[1])
199
+
200
+ if mask is not None:
201
+ bounds_mask *= mask(xs, ys)
202
+
198
203
  reduced_catalog = catalog[bounds_mask].copy()
199
204
  reduced_catalog["x_pix"] = xs[bounds_mask]
200
205
  reduced_catalog['y_pix'] = ys[bounds_mask]
@@ -1,9 +1,11 @@
1
1
  import warnings
2
+ from typing import Callable
2
3
 
3
4
  import numpy as np
4
5
  import pandas as pd
5
6
  import sep_pjw as sep
6
7
  from astropy.wcs import WCS, utils
8
+ import astropy.units as u
7
9
  from lmfit import Parameters, minimize
8
10
 
9
11
  from thuban.catalog import (filter_for_visible_stars, find_catalog_in_image,
@@ -47,19 +49,21 @@ def calculate_pc_matrix(crota: float, cdelt: (float, float)) -> np.ndarray:
47
49
  """
48
50
  return np.array(
49
51
  [
50
- [np.cos(crota), np.sin(crota) * (cdelt[0] / cdelt[1])],
51
- [-np.sin(crota) * (cdelt[1] / cdelt[0]), np.cos(crota)],
52
+ [np.cos(crota), -np.sin(crota) * (cdelt[0] / cdelt[1])],
53
+ [np.sin(crota) * (cdelt[1] / cdelt[0]), np.cos(crota)],
52
54
  ],
53
55
  )
54
56
 
55
57
 
56
-
57
58
  def _residual(params: Parameters,
58
59
  observed_coords: np.ndarray,
59
60
  catalog: pd.DataFrame,
60
61
  guess_wcs: WCS,
61
62
  n: int,
62
- image_shape: (int, int)):
63
+ image_shape: (int, int),
64
+ edge: int = 100,
65
+ sigma: float = 3.0,
66
+ mask: Callable = None):
63
67
  """Residual used when optimizing the pointing
64
68
 
65
69
  Parameters
@@ -86,13 +90,13 @@ def _residual(params: Parameters,
86
90
  refined_wcs.wcs.crpix = guess_wcs.wcs.crpix
87
91
  refined_wcs.wcs.crval = (params["crval1"].value, params["crval2"].value)
88
92
  refined_wcs.wcs.pc = calculate_pc_matrix(params["crota"], refined_wcs.wcs.cdelt)
89
- refined_wcs.cpdis1 = guess_wcs.cpdis1 # TODO what if there is no distortion?
93
+ refined_wcs.cpdis1 = guess_wcs.cpdis1
90
94
  refined_wcs.cpdis2 = guess_wcs.cpdis2
95
+ refined_wcs.wcs.set_pv(guess_wcs.wcs.get_pv())
91
96
 
92
- reduced_catalog = find_catalog_in_image(catalog, refined_wcs, image_shape=image_shape)
97
+ reduced_catalog = find_catalog_in_image(catalog, refined_wcs, image_shape=image_shape, mask=mask)
93
98
  refined_coords = np.stack([reduced_catalog['x_pix'], reduced_catalog['y_pix']], axis=-1)
94
99
 
95
- edge = 300
96
100
  image_bounds = (image_shape[0] - edge, image_shape[1] - edge)
97
101
  refined_coords = np.array([c for c in refined_coords
98
102
  if (c[0] > edge) and (c[1] > edge) and (c[0] < image_bounds[0]) and (c[1] < image_bounds[1])])
@@ -104,10 +108,9 @@ def _residual(params: Parameters,
104
108
  "Try decreasing `num_stars` or increasing `dimmest_magnitude`.",
105
109
  RepeatedStarWarning)
106
110
 
107
- sigma = 3
108
111
  out = np.array([np.min(np.linalg.norm(observed_coords - coord, axis=-1)) for coord in refined_coords[:n]])
109
- mean, stdev = np.mean(out), np.std(out)
110
- out[out > mean + sigma * stdev] = 0.0
112
+ median, stdev = np.median(out), np.std(out)
113
+ out[out > median + (sigma * stdev)] = 0.0 # TODO: should this be zero?
111
114
  return out
112
115
 
113
116
 
@@ -125,10 +128,16 @@ def refine_pointing_wrapper(image, guess_wcs, file_num, observed_coords=None, ca
125
128
  return new_wcs, observed_coords, solution, trial_num, file_num
126
129
 
127
130
 
131
+ def extract_crota_from_wcs(wcs: WCS) -> tuple[float, float]:
132
+ """Extract CROTA from a WCS."""
133
+ delta_ratio = wcs.wcs.cdelt[1] / wcs.wcs.cdelt[0]
134
+ return np.arctan2(wcs.wcs.pc[1, 0]/delta_ratio, wcs.wcs.pc[0, 0]) * u.rad
135
+
136
+
128
137
  def refine_pointing(image, guess_wcs, observed_coords=None, catalog=None,
129
138
  background_width=16, background_height=16,
130
139
  detection_threshold=5, num_stars=30, max_trials=15, chisqr_threshold=0.1,
131
- dimmest_magnitude=6.0, method='leastsq'):
140
+ dimmest_magnitude=6.0, method='leastsq', edge=100, sigma=3.0, mask=None):
132
141
  """ Refine the pointing for an image
133
142
 
134
143
  Parameters
@@ -159,14 +168,15 @@ def refine_pointing(image, guess_wcs, observed_coords=None, catalog=None,
159
168
  background = sep.Background(image, bw=background_width, bh=background_height)
160
169
  data_sub = image - background
161
170
  objects = sep.extract(data_sub, detection_threshold, err=background.globalrms)
162
- objects = pd.DataFrame(objects).sort_values('flux')[-3*num_stars:]
171
+ objects = pd.DataFrame(objects).sort_values('flux')
163
172
  observed_coords = np.stack([objects["x"], objects["y"]], axis=-1)
164
-
173
+ if mask is not None:
174
+ observed_coords = observed_coords[mask(objects['x'], objects['y'])]
175
+ observed_coords = observed_coords[-3*num_stars:]
165
176
  # set up the optimization
166
177
  params = Parameters()
167
- delta_ratio = guess_wcs.wcs.cdelt[0] / guess_wcs.wcs.cdelt[1]
168
- initial_crota = np.arctan2(guess_wcs.wcs.pc[0, 1]/delta_ratio, guess_wcs.wcs.pc[0, 0])
169
- params.add("crota", value=initial_crota, min=-np.pi, max=np.pi)
178
+ initial_crota = extract_crota_from_wcs(guess_wcs)
179
+ params.add("crota", value=initial_crota.to(u.rad).value, min=-np.pi, max=np.pi)
170
180
  params.add("crval1", value=guess_wcs.wcs.crval[0], min=-180, max=180, vary=True)
171
181
  params.add("crval2", value=guess_wcs.wcs.crval[1], min=-90, max=90, vary=True)
172
182
 
@@ -176,7 +186,7 @@ def refine_pointing(image, guess_wcs, observed_coords=None, catalog=None,
176
186
  while trial_num < max_trials:
177
187
  try:
178
188
  out = minimize(_residual, params, method=method,
179
- args=(observed_coords, catalog, guess_wcs, num_stars, image.shape))
189
+ args=(observed_coords, catalog, guess_wcs, num_stars, image.shape, edge, sigma, mask))
180
190
  chisqr = out.chisqr
181
191
  result_minimizations.append(out)
182
192
  except IndexError:
@@ -195,6 +205,7 @@ def refine_pointing(image, guess_wcs, observed_coords=None, catalog=None,
195
205
  result_wcs.wcs.pc = calculate_pc_matrix(out.params["crota"], result_wcs.wcs.cdelt)
196
206
  result_wcs.cpdis1 = guess_wcs.cpdis1 # TODO: what if there is no known distortion
197
207
  result_wcs.cpdis2 = guess_wcs.cpdis2
208
+ result_wcs.wcs.set_pv(guess_wcs.wcs.get_pv())
198
209
  result_wcses.append(result_wcs)
199
210
  trial_num += 1
200
211
  if chisqr < chisqr_threshold:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: thuban
3
- Version: 0.0.2
3
+ Version: 0.0.3
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>
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