drizzle 2.0.0__cp310-cp310-win_amd64.whl → 2.0.1__cp310-cp310-win_amd64.whl

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.

Potentially problematic release.


This version of drizzle might be problematic. Click here for more details.

Binary file
drizzle/resample.py CHANGED
@@ -6,7 +6,7 @@ import numpy as np
6
6
 
7
7
  from drizzle import cdrizzle
8
8
 
9
- __all__ = ["blot_image", "Drizzle"]
9
+ __all__ = ["Drizzle", "blot_image"]
10
10
 
11
11
  SUPPORTED_DRIZZLE_KERNELS = [
12
12
  "square",
@@ -0,0 +1,190 @@
1
+ import os
2
+
3
+ import gwcs
4
+ import numpy as np
5
+ from gwcs.coordinate_frames import CelestialFrame, Frame2D
6
+
7
+ from astropy import coordinates as coord
8
+ from astropy import units
9
+ from astropy import wcs as fits_wcs
10
+ from astropy.io import fits
11
+ from astropy.modeling.models import (
12
+ Mapping,
13
+ Pix2Sky_TAN,
14
+ Polynomial2D,
15
+ RotateNative2Celestial,
16
+ Shift,
17
+ )
18
+ from astropy.modeling.projections import AffineTransformation2D
19
+
20
+ __all__ = ["wcs_from_file"]
21
+
22
+ TEST_DIR = os.path.abspath(os.path.dirname(__file__))
23
+ DATA_DIR = os.path.join(TEST_DIR, 'data')
24
+
25
+
26
+ def wcs_from_file(filename, ext=None, return_data=False, crpix_shift=None,
27
+ wcs_type="fits"):
28
+ """
29
+ Read the WCS from a ".fits" file.
30
+
31
+ Parameters
32
+ ----------
33
+ filename : str
34
+ Name of the file to load WCS from.
35
+
36
+ ext : int, None, optional
37
+ Extension number to load the WCS from. When `None`, the WCS will be
38
+ loaded from the first extension containing a WCS.
39
+
40
+ return_data : bool, optional
41
+ When `True`, this function will return a tuple with first item
42
+ being the WCS and the second item being the image data array.
43
+
44
+ crpix_shift : tuple, None, optional
45
+ A tuple of two values to be added to header CRPIX values before
46
+ creating the WCS. This effectively introduces a constant shift
47
+ in the image coordinate system.
48
+
49
+ wcs_type : {"fits", "gwcs"}, optional
50
+ Return either a FITS WCS or a gwcs.
51
+
52
+ Returns
53
+ -------
54
+ WCS or tuple of WCS and image data
55
+
56
+ """
57
+ full_file_name = os.path.join(DATA_DIR, filename)
58
+ path = os.path.join(DATA_DIR, full_file_name)
59
+ with fits.open(path) as hdu:
60
+ if ext is None:
61
+ for k, u in enumerate(hdu):
62
+ if "CTYPE1" in u.header:
63
+ ext = k
64
+ break
65
+
66
+ hdr = hdu[ext].header
67
+ naxis1 = hdr.get("WCSNAX1", hdr.get("NAXIS1"))
68
+ naxis2 = hdr.get("WCSNAX2", hdr.get("NAXIS2"))
69
+ if naxis1 is not None and naxis2 is not None:
70
+ shape = (naxis2, naxis1)
71
+ if hdu[ext].data is None:
72
+ hdu[ext].data = np.zeros(shape, dtype=np.float32)
73
+ else:
74
+ shape = None
75
+
76
+ if crpix_shift is not None and "CRPIX1" in hdr:
77
+ hdr["CRPIX1"] += crpix_shift[0]
78
+ hdr["CRPIX2"] += crpix_shift[1]
79
+
80
+ result = fits_wcs.WCS(hdr, hdu)
81
+ result.array_shape = shape
82
+
83
+ if wcs_type == "gwcs":
84
+ result = _gwcs_from_hst_fits_wcs(result)
85
+
86
+ if return_data:
87
+ result = (result, )
88
+ if not isinstance(return_data, (list, tuple)):
89
+ return_data = [ext]
90
+ for ext in return_data:
91
+ data = (hdu[ext].data, )
92
+ result = result + data
93
+
94
+ return result
95
+
96
+
97
+ def _gwcs_from_hst_fits_wcs(w):
98
+ # NOTE: this function ignores table distortions
99
+ def coeffs_to_poly(mat, degree):
100
+ pol = Polynomial2D(degree=degree)
101
+ for i in range(mat.shape[0]):
102
+ for j in range(mat.shape[1]):
103
+ if 0 < i + j <= degree:
104
+ setattr(pol, f'c{i}_{j}', mat[i, j])
105
+ return pol
106
+
107
+ nx, ny = w.pixel_shape
108
+ x0, y0 = w.wcs.crpix - 1
109
+
110
+ cd = w.wcs.piximg_matrix
111
+
112
+ if w.sip is None:
113
+ # construct GWCS:
114
+ det2sky = (
115
+ (Shift(-x0) & Shift(-y0)) |
116
+ Pix2Sky_TAN() | RotateNative2Celestial(*w.wcs.crval, 180)
117
+ )
118
+ else:
119
+ cfx, cfy = np.dot(cd, [w.sip.a.ravel(), w.sip.b.ravel()])
120
+ a = np.reshape(cfx, w.sip.a.shape)
121
+ b = np.reshape(cfy, w.sip.b.shape)
122
+ a[1, 0] = cd[0, 0]
123
+ a[0, 1] = cd[0, 1]
124
+ b[1, 0] = cd[1, 0]
125
+ b[0, 1] = cd[1, 1]
126
+
127
+ polx = coeffs_to_poly(a, w.sip.a_order)
128
+ poly = coeffs_to_poly(b, w.sip.b_order)
129
+
130
+ sip = Mapping((0, 1, 0, 1)) | (polx & poly)
131
+
132
+ # construct GWCS:
133
+ det2sky = (
134
+ (Shift(-x0) & Shift(-y0)) | sip |
135
+ Pix2Sky_TAN() | RotateNative2Celestial(*w.wcs.crval, 180)
136
+ )
137
+
138
+ detector_frame = Frame2D(
139
+ name="detector",
140
+ axes_names=("x", "y"),
141
+ unit=(units.pix, units.pix)
142
+ )
143
+ sky_frame = CelestialFrame(
144
+ reference_frame=getattr(coord, w.wcs.radesys).__call__(),
145
+ name=w.wcs.radesys,
146
+ unit=(units.deg, units.deg)
147
+ )
148
+ pipeline = [(detector_frame, det2sky), (sky_frame, None)]
149
+ gw = gwcs.wcs.WCS(pipeline)
150
+ gw.array_shape = w.array_shape
151
+ gw.bounding_box = ((-0.5, nx - 0.5), (-0.5, ny - 0.5))
152
+
153
+ if w.sip is not None:
154
+ # compute inverse SIP and re-create output GWCS
155
+
156
+ # compute inverse SIP:
157
+ hdr = gw.to_fits_sip(
158
+ max_inv_pix_error=1e-5,
159
+ inv_degree=None,
160
+ npoints=64,
161
+ crpix=w.wcs.crpix,
162
+ projection='TAN',
163
+ verbose=False
164
+ )
165
+ winv = fits_wcs.WCS(hdr)
166
+ ap = winv.sip.ap.copy()
167
+ bp = winv.sip.bp.copy()
168
+ ap[1, 0] += 1
169
+ bp[0, 1] += 1
170
+ polx_inv = coeffs_to_poly(ap, winv.sip.ap_order)
171
+ poly_inv = coeffs_to_poly(bp, winv.sip.bp_order)
172
+ af = AffineTransformation2D(
173
+ matrix=np.linalg.inv(winv.wcs.piximg_matrix)
174
+ )
175
+
176
+ # set analytical inverses:
177
+ sip.inverse = af | Mapping((0, 1, 0, 1)) | (polx_inv & poly_inv)
178
+
179
+ # construct GWCS:
180
+ det2sky = (
181
+ (Shift(-x0) & Shift(-y0)) | sip |
182
+ Pix2Sky_TAN() | RotateNative2Celestial(*w.wcs.crval, 180)
183
+ )
184
+
185
+ pipeline = [(detector_frame, det2sky), (sky_frame, None)]
186
+ gw = gwcs.wcs.WCS(pipeline)
187
+ gw.array_shape = w.array_shape
188
+ gw.bounding_box = ((-0.5, nx - 0.5), (-0.5, ny - 0.5))
189
+
190
+ return gw
@@ -5,9 +5,10 @@ import numpy as np
5
5
  import pytest
6
6
 
7
7
  from astropy import wcs
8
- from astropy.io import fits
9
8
  from drizzle import cdrizzle, resample, utils
10
9
 
10
+ from .helpers import wcs_from_file
11
+
11
12
  TEST_DIR = os.path.abspath(os.path.dirname(__file__))
12
13
  DATA_DIR = os.path.join(TEST_DIR, 'data')
13
14
 
@@ -166,20 +167,20 @@ def centroid_statistics(title, fname, image1, image2, amp, size):
166
167
  return tuple(diff)
167
168
 
168
169
 
169
- def make_point_image(input_image, point, value):
170
+ def make_point_image(shape, point, value):
170
171
  """
171
172
  Create an image with a single point set
172
173
  """
173
- output_image = np.zeros(input_image.shape, dtype=input_image.dtype)
174
+ output_image = np.zeros(shape, dtype=np.float32)
174
175
  output_image[point] = value
175
176
  return output_image
176
177
 
177
178
 
178
- def make_grid_image(input_image, spacing, value):
179
+ def make_grid_image(shape, spacing, value):
179
180
  """
180
181
  Create an image with points on a grid set
181
182
  """
182
- output_image = np.zeros(input_image.shape, dtype=input_image.dtype)
183
+ output_image = np.zeros(shape, dtype=np.float32)
183
184
 
184
185
  shape = output_image.shape
185
186
  half_space = int(spacing / 2)
@@ -190,29 +191,6 @@ def make_grid_image(input_image, spacing, value):
190
191
  return output_image
191
192
 
192
193
 
193
- def read_image(filename):
194
- """
195
- Read the image from a fits file
196
- """
197
- path = os.path.join(DATA_DIR, filename)
198
- hdu = fits.open(path)
199
-
200
- image = hdu[1].data
201
- hdu.close()
202
- return image
203
-
204
-
205
- def read_wcs(filename):
206
- """
207
- Read the wcs of a fits file
208
- """
209
- path = os.path.join(DATA_DIR, filename)
210
- hdu = fits.open(path)
211
- the_wcs = wcs.WCS(hdu[1].header)
212
- hdu.close()
213
- return the_wcs
214
-
215
-
216
194
  def test_drizzle_defaults():
217
195
  n = 200
218
196
  in_shape = (n, n)
@@ -256,52 +234,86 @@ def test_drizzle_defaults():
256
234
  assert driz.out_img[1, 2] == 1
257
235
  assert (driz.out_img[2, 1] - 2.0) < 1.0e-14
258
236
 
259
-
260
- def test_square_with_point(tmpdir):
237
+ @pytest.mark.parametrize(
238
+ 'kernel,test_image_type,max_diff_atol',
239
+ [
240
+ ("square", "point", 1.0e-5),
241
+ ("square", "grid", 1.0e-5),
242
+ ('point', "grid", 1.0e-5),
243
+ ("turbo", "grid", 1.0e-5),
244
+ ('lanczos3', "grid", 1.0e-5),
245
+ ("gaussian", "grid", 2.0e-5),
246
+ ],
247
+ )
248
+ def test_resample_kernel(tmpdir, kernel, test_image_type, max_diff_atol):
261
249
  """
262
250
  Test do_driz square kernel with point
263
251
  """
264
- output_difference = str(tmpdir.join('difference_square_point.txt'))
265
-
266
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
267
- output_template = os.path.join(DATA_DIR, 'reference_square_point.fits')
252
+ output_difference = str(
253
+ tmpdir.join(f"difference_{kernel}_{test_image_type}.txt")
254
+ )
268
255
 
269
- insci = read_image(input_file)
270
- inwcs = read_wcs(input_file)
271
- insci = make_point_image(insci, (500, 200), 100.0)
272
- inwht = np.ones(insci.shape, dtype=insci.dtype)
273
- output_wcs = read_wcs(output_template)
256
+ inwcs = wcs_from_file("j8bt06nyq_flt.fits", ext=1)
257
+ if test_image_type == "point":
258
+ insci = make_point_image(inwcs.array_shape, (500, 200), 100.0)
259
+ else:
260
+ insci = make_grid_image(inwcs.array_shape, 64, 100.0)
261
+ inwht = np.ones_like(insci)
262
+ output_wcs, template_data = wcs_from_file(
263
+ f"reference_{kernel}_{test_image_type}.fits",
264
+ ext=1,
265
+ return_data=True
266
+ )
274
267
 
275
268
  pixmap = utils.calc_pixmap(
276
269
  inwcs,
277
270
  output_wcs,
278
271
  )
279
272
 
280
- # ignore previous pscale and compute it the old way (only to make
281
- # tests work with old truth files and thus to show that new API gives
282
- # same results when equal definitions of the pixel scale is used):
283
- pscale = np.sqrt(
284
- np.sum(output_wcs.wcs.pc**2, axis=0)[0] /
285
- np.sum(inwcs.wcs.cd**2, axis=0)[0]
286
- )
273
+ if kernel == "point":
274
+ pscale_ratio = 1.0
275
+ else:
276
+ pscale_ratio = utils.estimate_pixel_scale_ratio(
277
+ inwcs,
278
+ output_wcs,
279
+ refpix_from=inwcs.wcs.crpix,
280
+ refpix_to=output_wcs.wcs.crpix,
281
+ )
282
+
283
+ # ignore previous pscale and compute it the old way (only to make
284
+ # tests work with old truth files and thus to show that new API gives
285
+ # same results when equal definitions of the pixel scale is used):
286
+ pscale_ratio = np.sqrt(
287
+ np.sum(output_wcs.wcs.pc**2, axis=0)[0] /
288
+ np.sum(inwcs.wcs.cd**2, axis=0)[0]
289
+ )
287
290
 
288
291
  driz = resample.Drizzle(
289
- kernel='square',
292
+ kernel=kernel,
290
293
  out_shape=output_wcs.array_shape,
291
294
  fillval=0.0,
292
295
  )
293
- driz.add_image(
294
- insci,
295
- exptime=1.0,
296
- pixmap=pixmap,
297
- weight_map=inwht,
298
- scale=pscale,
299
- )
300
296
 
301
- template_data = read_image(output_template)
297
+ if kernel in ["square", "turbo", "point"]:
298
+ driz.add_image(
299
+ insci,
300
+ exptime=1.0,
301
+ pixmap=pixmap,
302
+ weight_map=inwht,
303
+ scale=pscale_ratio,
304
+ )
305
+ else:
306
+ with pytest.warns(Warning):
307
+ driz.add_image(
308
+ insci,
309
+ exptime=1.0,
310
+ pixmap=pixmap,
311
+ weight_map=inwht,
312
+ scale=pscale_ratio,
313
+ )
302
314
 
303
315
  _, med_diff, max_diff = centroid_statistics(
304
- "square with point",
316
+ f"{kernel} with {test_image_type}",
305
317
  output_difference,
306
318
  driz.out_img,
307
319
  template_data,
@@ -310,7 +322,66 @@ def test_square_with_point(tmpdir):
310
322
  )
311
323
 
312
324
  assert med_diff < 1.0e-6
313
- assert max_diff < 1.0e-5
325
+ assert max_diff < max_diff_atol
326
+
327
+
328
+ @pytest.mark.parametrize(
329
+ 'kernel,max_diff_atol',
330
+ [
331
+ ("square", 1.0e-5),
332
+ ("turbo", 1.0e-5),
333
+ ],
334
+ )
335
+ def test_resample_kernel_image(tmpdir, kernel, max_diff_atol):
336
+ """
337
+ Test do_driz square kernel with point
338
+ """
339
+ inwcs, insci = wcs_from_file(
340
+ "j8bt06nyq_flt.fits",
341
+ ext=1,
342
+ return_data=True
343
+ )
344
+ inwht = np.ones_like(insci)
345
+
346
+ outwcs, ref_sci, ref_ctx, ref_wht = wcs_from_file(
347
+ f"reference_{kernel}_image.fits",
348
+ ext=1,
349
+ return_data=["SCI", "CTX", "WHT"]
350
+ )
351
+ ref_ctx = np.array(ref_ctx, dtype=np.int32)
352
+
353
+ pixmap = utils.calc_pixmap(
354
+ inwcs,
355
+ outwcs,
356
+ )
357
+
358
+ pscale_ratio = np.sqrt(
359
+ np.sum(outwcs.wcs.cd**2, axis=0)[0] /
360
+ np.sum(inwcs.wcs.cd**2, axis=0)[0]
361
+ )
362
+
363
+ driz = resample.Drizzle(
364
+ kernel=kernel,
365
+ out_shape=ref_sci.shape,
366
+ fillval=0.0,
367
+ )
368
+
369
+ driz.add_image(
370
+ insci,
371
+ exptime=1.0,
372
+ pixmap=pixmap,
373
+ weight_map=inwht,
374
+ scale=pscale_ratio,
375
+ )
376
+ outctx = driz.out_ctx[0]
377
+
378
+ # in order to avoid small differences in the staircase in the outline
379
+ # of the input image in the output grid, select a subset:
380
+ sl = np.s_[125: -125, 5: -5]
381
+
382
+ assert np.allclose(driz.out_img[sl], ref_sci[sl], atol=0, rtol=1.0e-6)
383
+ assert np.allclose(driz.out_wht[sl], ref_wht[sl], atol=0, rtol=1.0e-6)
384
+ assert np.all(outctx[sl] == ref_ctx[sl])
314
385
 
315
386
 
316
387
  @pytest.mark.parametrize(
@@ -389,472 +460,64 @@ def test_zero_input_weight(kernel, fc):
389
460
  assert np.sum(np.abs(outsci[(outwht == 0)])) == 0.0
390
461
 
391
462
 
392
- def test_square_with_grid(tmpdir):
393
- """
394
- Test do_driz square kernel with grid
395
- """
396
- output_difference = str(tmpdir.join('difference_square_grid.txt'))
397
-
398
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
399
- output_template = os.path.join(DATA_DIR, 'reference_square_grid.fits')
400
-
401
- insci = read_image(input_file)
402
- inwcs = read_wcs(input_file)
403
- insci = make_grid_image(insci, 64, 100.0)
404
-
405
- inwht = np.ones(insci.shape, dtype=insci.dtype)
406
- output_wcs = read_wcs(output_template)
407
-
408
- pixmap = utils.calc_pixmap(
409
- inwcs,
410
- output_wcs,
411
- )
412
- pscale = utils.estimate_pixel_scale_ratio(
413
- inwcs,
414
- output_wcs,
415
- refpix_from=inwcs.wcs.crpix,
416
- refpix_to=output_wcs.wcs.crpix,
417
- )
418
- # ignore previous pscale and compute it the old way (only to make
419
- # tests work with old truth files and thus to show that new API gives
420
- # same results when equal definitions of the pixel scale is used):
421
- pscale = np.sqrt(
422
- np.sum(output_wcs.wcs.pc**2, axis=0)[0] /
423
- np.sum(inwcs.wcs.cd**2, axis=0)[0]
424
- )
425
-
426
- driz = resample.Drizzle(
427
- kernel='square',
428
- out_shape=output_wcs.array_shape,
429
- fillval=0.0,
430
- )
431
- driz.add_image(
432
- insci,
433
- exptime=1.0,
434
- pixmap=pixmap,
435
- weight_map=inwht,
436
- scale=pscale,
437
- )
438
- template_data = read_image(output_template)
439
-
440
- _, med_diff, max_diff = centroid_statistics(
441
- "square with grid",
442
- output_difference,
443
- driz.out_img,
444
- template_data,
445
- 20.0,
446
- 8,
447
- )
448
- assert med_diff < 1.0e-6
449
- assert max_diff < 1.0e-5
450
-
451
-
452
- def test_turbo_with_grid(tmpdir):
453
- """
454
- Test do_driz turbo kernel with grid
455
- """
456
- output_difference = str(tmpdir.join('difference_turbo_grid.txt'))
457
-
458
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
459
- output_template = os.path.join(DATA_DIR, 'reference_turbo_grid.fits')
460
-
461
- insci = read_image(input_file)
462
- inwcs = read_wcs(input_file)
463
- insci = make_grid_image(insci, 64, 100.0)
464
- inwht = np.ones(insci.shape, dtype=insci.dtype)
465
- output_wcs = read_wcs(output_template)
466
-
467
- pixmap = utils.calc_pixmap(
468
- inwcs,
469
- output_wcs,
470
- )
471
- pscale = utils.estimate_pixel_scale_ratio(
472
- inwcs,
473
- output_wcs,
474
- refpix_from=inwcs.wcs.crpix,
475
- refpix_to=output_wcs.wcs.crpix,
476
- )
477
-
478
- # ignore previous pscale and compute it the old way (only to make
479
- # tests work with old truth files and thus to show that new API gives
480
- # same results when equal definitions of the pixel scale is used):
481
- pscale = np.sqrt(
482
- np.sum(output_wcs.wcs.pc**2, axis=0)[0] /
483
- np.sum(inwcs.wcs.cd**2, axis=0)[0]
484
- )
485
-
486
- driz = resample.Drizzle(
487
- kernel='turbo',
488
- out_shape=output_wcs.array_shape,
489
- fillval=0.0,
490
- )
491
- driz.add_image(
492
- insci,
493
- exptime=1.0,
494
- pixmap=pixmap,
495
- weight_map=inwht,
496
- scale=pscale,
497
- )
498
-
499
- template_data = read_image(output_template)
500
-
501
- _, med_diff, max_diff = centroid_statistics(
502
- "turbo with grid",
503
- output_difference,
504
- driz.out_img,
505
- template_data,
506
- 20.0,
507
- 8,
508
- )
509
-
510
- assert med_diff < 1.0e-6
511
- assert max_diff < 1.0e-5
512
-
513
-
514
- def test_gaussian_with_grid(tmpdir):
515
- """
516
- Test do_driz gaussian kernel with grid
517
- """
518
- output_difference = str(tmpdir.join('difference_gaussian_grid.txt'))
519
-
520
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
521
- output_template = os.path.join(DATA_DIR, 'reference_gaussian_grid.fits')
522
-
523
- insci = read_image(input_file)
524
- inwcs = read_wcs(input_file)
525
- insci = make_grid_image(insci, 64, 100.0)
526
- inwht = np.ones(insci.shape, dtype=insci.dtype)
527
- output_wcs = read_wcs(output_template)
528
-
529
- pixmap = utils.calc_pixmap(
530
- inwcs,
531
- output_wcs,
532
- )
533
- pscale = utils.estimate_pixel_scale_ratio(
534
- inwcs,
535
- output_wcs,
536
- refpix_from=inwcs.wcs.crpix,
537
- refpix_to=output_wcs.wcs.crpix,
538
- )
539
-
540
- # ignore previous pscale and compute it the old way (only to make
541
- # tests work with old truth files and thus to show that new API gives
542
- # same results when equal definitions of the pixel scale is used):
543
- pscale = np.sqrt(
544
- np.sum(output_wcs.wcs.pc**2, axis=0)[0] /
545
- np.sum(inwcs.wcs.cd**2, axis=0)[0]
546
- )
547
-
548
- driz = resample.Drizzle(
549
- kernel='gaussian',
550
- out_shape=output_wcs.array_shape,
551
- fillval=0.0,
552
- )
553
- with pytest.warns(Warning):
554
- driz.add_image(
555
- insci,
556
- exptime=1.0,
557
- pixmap=pixmap,
558
- weight_map=inwht,
559
- scale=pscale,
560
- )
561
-
562
- template_data = read_image(output_template)
563
-
564
- _, med_diff, max_diff = centroid_statistics(
565
- "gaussian with grid",
566
- output_difference,
567
- driz.out_img,
568
- template_data,
569
- 20.0,
570
- 8,
571
- )
572
-
573
- assert med_diff < 1.0e-6
574
- assert max_diff < 2.0e-5
575
-
576
-
577
- def test_lanczos_with_grid(tmpdir):
578
- """
579
- Test do_driz lanczos kernel with grid
580
- """
581
- output_difference = str(tmpdir.join('difference_lanczos_grid.txt'))
582
-
583
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
584
- output_template = os.path.join(DATA_DIR, 'reference_lanczos_grid.fits')
585
-
586
- insci = read_image(input_file)
587
- inwcs = read_wcs(input_file)
588
- insci = make_grid_image(insci, 64, 100.0)
589
- inwht = np.ones(insci.shape, dtype=insci.dtype)
590
- output_wcs = read_wcs(output_template)
591
-
592
- pixmap = utils.calc_pixmap(
593
- inwcs,
594
- output_wcs,
595
- )
596
- pscale = utils.estimate_pixel_scale_ratio(
597
- inwcs,
598
- output_wcs,
599
- refpix_from=inwcs.wcs.crpix,
600
- refpix_to=output_wcs.wcs.crpix,
601
- )
602
-
603
- # ignore previous pscale and compute it the old way (only to make
604
- # tests work with old truth files and thus to show that new API gives
605
- # same results when equal definitions of the pixel scale is used):
606
- pscale = np.sqrt(
607
- np.sum(output_wcs.wcs.pc**2, axis=0)[0] /
608
- np.sum(inwcs.wcs.cd**2, axis=0)[0]
609
- )
610
-
611
- driz = resample.Drizzle(
612
- kernel='lanczos3',
613
- out_shape=output_wcs.array_shape,
614
- fillval=0.0,
615
- )
616
- with pytest.warns(Warning):
617
- driz.add_image(
618
- insci,
619
- exptime=1.0,
620
- pixmap=pixmap,
621
- weight_map=inwht,
622
- scale=pscale,
623
- )
624
-
625
- template_data = read_image(output_template)
626
-
627
- _, med_diff, max_diff = centroid_statistics(
628
- "lanczos with grid",
629
- output_difference,
630
- driz.out_img,
631
- template_data,
632
- 20.0,
633
- 8,
634
- )
635
- assert med_diff < 1.0e-6
636
- assert max_diff < 1.0e-5
637
-
638
-
639
- def test_point_with_grid(tmpdir):
640
- """
641
- Test do_driz point kernel with grid
642
- """
643
- output_difference = str(tmpdir.join('difference_point_grid.txt'))
644
-
645
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
646
- output_template = os.path.join(DATA_DIR, 'reference_point_grid.fits')
647
-
648
- insci = read_image(input_file)
649
- inwcs = read_wcs(input_file)
650
- insci = make_grid_image(insci, 64, 100.0)
651
- inwht = np.ones(insci.shape, dtype=insci.dtype)
652
- output_wcs = read_wcs(output_template)
653
-
654
- pixmap = utils.calc_pixmap(inwcs, output_wcs)
655
-
656
- driz = resample.Drizzle(kernel='point', out_shape=output_wcs.array_shape, fillval=0.0)
657
- driz.add_image(insci, exptime=1.0, pixmap=pixmap, weight_map=inwht)
658
-
659
- template_data = read_image(output_template)
660
-
661
- _, med_diff, max_diff = centroid_statistics(
662
- "point with grid",
663
- output_difference,
664
- driz.out_img,
665
- template_data,
666
- 20.0,
667
- 8,
668
- )
669
- assert med_diff < 1.0e-6
670
- assert max_diff < 1.0e-5
671
-
672
-
673
- def test_blot_with_point(tmpdir):
674
- """
675
- Test do_blot with point image
676
- """
677
- output_difference = str(tmpdir.join('difference_blot_point.txt'))
678
-
679
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
680
- output_template = os.path.join(DATA_DIR, 'reference_blot_point.fits')
681
-
682
- outsci = read_image(input_file)
683
- outwcs = read_wcs(input_file)
684
- outsci = make_point_image(outsci, (500, 200), 40.0)
685
- inwcs = read_wcs(output_template)
686
-
687
- pixmap = utils.calc_pixmap(inwcs, outwcs)
688
-
689
- # compute pscale the old way (only to make
690
- # tests work with old truth files and thus to show that new API gives
691
- # same results when equal definitions of the pixel scale is used):
692
- pscale = np.sqrt(
693
- np.sum(inwcs.wcs.pc**2, axis=0)[0] /
694
- np.sum(outwcs.wcs.cd**2, axis=0)[0]
695
- )
696
-
697
- blotted_image = resample.blot_image(
698
- outsci,
699
- pixmap=pixmap,
700
- pix_ratio=pscale,
701
- exptime=1.0,
702
- output_pixel_shape=inwcs.pixel_shape,
703
- )
704
-
705
- template_data = read_image(output_template)
706
-
707
- _, med_diff, max_diff = centroid_statistics(
708
- "blot with point",
709
- output_difference,
710
- blotted_image,
711
- template_data,
712
- 20.0,
713
- 16,
714
- )
715
- assert med_diff < 1.0e-6
716
- assert max_diff < 1.0e-5
717
-
718
-
719
- def test_blot_with_default(tmpdir):
463
+ @pytest.mark.parametrize(
464
+ 'interpolator,test_image_type',
465
+ [
466
+ ("poly5", "point"),
467
+ ("default", "grid"),
468
+ ('lan3', "grid"),
469
+ ("lan5", "grid"),
470
+ ],
471
+ )
472
+ def test_blot_interpolation(tmpdir, interpolator, test_image_type):
720
473
  """
721
- Test do_blot with default grid image
474
+ Test do_driz square kernel with point
722
475
  """
723
- output_difference = str(tmpdir.join('difference_blot_default.txt'))
724
-
725
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
726
- output_template = os.path.join(DATA_DIR, 'reference_blot_default.fits')
727
-
728
- outsci = read_image(input_file)
729
- outsci = make_grid_image(outsci, 64, 100.0)
730
- outwcs = read_wcs(input_file)
731
- inwcs = read_wcs(output_template)
732
-
733
- pixmap = utils.calc_pixmap(inwcs, outwcs)
734
-
735
- # compute pscale the old way (only to make
736
- # tests work with old truth files and thus to show that new API gives
737
- # same results when equal definitions of the pixel scale is used):
738
- pscale = np.sqrt(
739
- np.sum(inwcs.wcs.pc**2, axis=0)[0] /
740
- np.sum(outwcs.wcs.cd**2, axis=0)[0]
476
+ output_difference = str(
477
+ tmpdir.join(f"difference_blot_{interpolator}_{test_image_type}.txt")
741
478
  )
742
479
 
743
- blotted_image = resample.blot_image(
744
- outsci,
745
- pixmap=pixmap,
746
- pix_ratio=pscale,
747
- exptime=1.0,
748
- output_pixel_shape=inwcs.pixel_shape,
749
- )
750
-
751
- template_data = read_image(output_template)
752
-
753
- _, med_diff, max_diff = centroid_statistics(
754
- "blot with defaults",
755
- output_difference,
756
- blotted_image,
757
- template_data,
758
- 20.0,
759
- 16,
760
- )
761
-
762
- assert med_diff < 1.0e-6
763
- assert max_diff < 1.0e-5
764
-
765
-
766
- def test_blot_with_lan3(tmpdir):
767
- """
768
- Test do_blot with lan3 grid image
769
- """
770
- output_difference = str(tmpdir.join('difference_blot_lan3.txt'))
771
-
772
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
773
- output_template = os.path.join(DATA_DIR, 'reference_blot_lan3.fits')
774
-
775
- outsci = read_image(input_file)
776
- outsci = make_grid_image(outsci, 64, 100.0)
777
- outwcs = read_wcs(input_file)
778
- inwcs = read_wcs(output_template)
480
+ outwcs = wcs_from_file("j8bt06nyq_flt.fits", ext=1)
481
+ if test_image_type == "point":
482
+ outsci = make_point_image(outwcs.array_shape, (500, 200), 40.0)
483
+ ref_fname = "reference_blot_point.fits"
484
+ else:
485
+ outsci = make_grid_image(outwcs.array_shape, 64, 100.0)
486
+ ref_fname = f"reference_blot_{interpolator}.fits"
487
+ inwcs, template_data = wcs_from_file(ref_fname, ext=1, return_data=True)
779
488
 
780
489
  pixmap = utils.calc_pixmap(inwcs, outwcs)
781
490
 
782
491
  # compute pscale the old way (only to make
783
492
  # tests work with old truth files and thus to show that new API gives
784
493
  # same results when equal definitions of the pixel scale is used):
785
- pscale = np.sqrt(
494
+ pscale_ratio = np.sqrt(
786
495
  np.sum(inwcs.wcs.pc**2, axis=0)[0] /
787
496
  np.sum(outwcs.wcs.cd**2, axis=0)[0]
788
497
  )
789
498
 
790
- blotted_image = resample.blot_image(
791
- outsci,
792
- pixmap=pixmap,
793
- pix_ratio=pscale,
794
- exptime=1.0,
795
- output_pixel_shape=inwcs.pixel_shape,
796
- interp="lan3",
797
- )
798
-
799
- template_data = read_image(output_template)
800
-
801
- _, med_diff, max_diff = centroid_statistics(
802
- "blot with lan3",
803
- output_difference,
804
- blotted_image,
805
- template_data,
806
- 20.0,
807
- 16,
808
- )
809
-
810
- assert med_diff < 1.0e-6
811
- assert max_diff < 1.0e-5
812
-
813
-
814
- def test_blot_with_lan5(tmpdir):
815
- """
816
- Test do_blot with lan5 grid image
817
- """
818
- output_difference = str(tmpdir.join('difference_blot_lan5.txt'))
819
-
820
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
821
- output_template = os.path.join(DATA_DIR, 'reference_blot_lan5.fits')
822
-
823
- outsci = read_image(input_file)
824
- outsci = make_grid_image(outsci, 64, 100.0)
825
- outwcs = read_wcs(input_file)
826
- inwcs = read_wcs(output_template)
827
-
828
- pixmap = utils.calc_pixmap(inwcs, outwcs)
829
-
830
- # compute pscale the old way (only to make
831
- # tests work with old truth files and thus to show that new API gives
832
- # same results when equal definitions of the pixel scale is used):
833
- pscale = np.sqrt(
834
- np.sum(inwcs.wcs.pc**2, axis=0)[0] /
835
- np.sum(outwcs.wcs.cd**2, axis=0)[0]
836
- )
499
+ if interpolator == "default":
500
+ kwargs = {}
501
+ else:
502
+ kwargs = {"interp": interpolator}
837
503
 
838
504
  blotted_image = resample.blot_image(
839
505
  outsci,
840
506
  pixmap=pixmap,
841
- pix_ratio=pscale,
507
+ pix_ratio=pscale_ratio,
842
508
  exptime=1.0,
843
509
  output_pixel_shape=inwcs.pixel_shape,
844
- interp="lan5",
510
+ **kwargs
845
511
  )
846
512
 
847
- template_data = read_image(output_template)
848
-
849
513
  _, med_diff, max_diff = centroid_statistics(
850
- "blot with lan5",
514
+ "blot with '{interpolator}' and '{test_image_type}'",
851
515
  output_difference,
852
516
  blotted_image,
853
517
  template_data,
854
518
  20.0,
855
519
  16,
856
520
  )
857
-
858
521
  assert med_diff < 1.0e-6
859
522
  assert max_diff < 1.0e-5
860
523
 
@@ -1,11 +1,7 @@
1
- import os
2
-
3
1
  import numpy as np
4
2
  import pytest
5
3
  from numpy.testing import assert_almost_equal, assert_equal
6
4
 
7
- from astropy import wcs
8
- from astropy.io import fits
9
5
  from drizzle.utils import (
10
6
  _estimate_pixel_scale,
11
7
  calc_pixmap,
@@ -13,8 +9,7 @@ from drizzle.utils import (
13
9
  estimate_pixel_scale_ratio,
14
10
  )
15
11
 
16
- TEST_DIR = os.path.abspath(os.path.dirname(__file__))
17
- DATA_DIR = os.path.join(TEST_DIR, 'data')
12
+ from .helpers import wcs_from_file
18
13
 
19
14
 
20
15
  def test_map_rectangular():
@@ -30,18 +25,17 @@ def test_map_rectangular():
30
25
  assert_equal(pixmap[5, 500], (500, 5))
31
26
 
32
27
 
33
- def test_map_to_self():
28
+ @pytest.mark.parametrize(
29
+ "wcs_type", ["fits", "gwcs"]
30
+ )
31
+ def test_map_to_self(wcs_type):
34
32
  """
35
33
  Map a pixel array to itself. Should return the same array.
36
34
  """
37
- input_file = os.path.join(DATA_DIR, 'input1.fits')
38
- input_hdu = fits.open(input_file)
39
-
40
- input_wcs = wcs.WCS(input_hdu[1].header)
41
- naxis1, naxis2 = input_wcs.pixel_shape
42
- input_hdu.close()
35
+ input_wcs = wcs_from_file("j8bt06nyq_sip_flt.fits", ext=1, wcs_type=wcs_type)
36
+ shape = input_wcs.array_shape
43
37
 
44
- ok_pixmap = np.indices((naxis1, naxis2), dtype='float32')
38
+ ok_pixmap = np.indices(shape, dtype='float64')
45
39
  ok_pixmap = ok_pixmap.transpose()
46
40
 
47
41
  pixmap = calc_pixmap(input_wcs, input_wcs)
@@ -56,9 +50,10 @@ def test_map_to_self():
56
50
  pixmap = calc_pixmap(input_wcs, input_wcs, (12, 34))
57
51
  assert_equal(pixmap.shape, (12, 34, 2))
58
52
 
59
- # Check that an exception is raised for WCS without pixel_shape or
53
+ # Check that an exception is raised for WCS without pixel_shape and
60
54
  # bounding_box:
61
55
  input_wcs.pixel_shape = None
56
+ input_wcs.bounding_box = None
62
57
  with pytest.raises(ValueError):
63
58
  calc_pixmap(input_wcs, input_wcs)
64
59
 
@@ -72,31 +67,31 @@ def test_map_to_self():
72
67
  assert_equal(pixmap.shape, (12, 34, 2))
73
68
 
74
69
  # from bounding box and pixel_shape (the later takes precedence):
75
- input_wcs.pixel_shape = (naxis1, naxis2)
70
+ input_wcs.array_shape = shape
76
71
  pixmap = calc_pixmap(input_wcs, input_wcs)
77
72
  assert_equal(pixmap.shape, ok_pixmap.shape)
78
73
 
79
74
 
80
- def test_translated_map():
75
+ @pytest.mark.parametrize(
76
+ "wcs_type", ["fits", "gwcs"]
77
+ )
78
+ def test_translated_map(wcs_type):
81
79
  """
82
80
  Map a pixel array to at translated array.
83
81
  """
84
- first_file = os.path.join(DATA_DIR, 'input1.fits')
85
- first_hdu = fits.open(first_file)
86
- first_header = first_hdu[1].header
87
-
88
- first_wcs = wcs.WCS(first_header)
89
- naxis1, naxis2 = first_wcs.pixel_shape
90
- first_hdu.close()
91
-
92
- second_file = os.path.join(DATA_DIR, 'input3.fits')
93
- second_hdu = fits.open(second_file)
94
- second_header = second_hdu[1].header
95
-
96
- second_wcs = wcs.WCS(second_header)
97
- second_hdu.close()
82
+ first_wcs = wcs_from_file(
83
+ "j8bt06nyq_sip_flt.fits",
84
+ ext=1,
85
+ wcs_type=wcs_type
86
+ )
87
+ second_wcs = wcs_from_file(
88
+ "j8bt06nyq_sip_flt.fits",
89
+ ext=1,
90
+ crpix_shift=(-2, -2), # shift loaded WCS by adding this to CRPIX
91
+ wcs_type=wcs_type
92
+ )
98
93
 
99
- ok_pixmap = np.indices((naxis1, naxis2), dtype='float32') - 2.0
94
+ ok_pixmap = np.indices(first_wcs.array_shape, dtype='float32') - 2.0
100
95
  ok_pixmap = ok_pixmap.transpose()
101
96
 
102
97
  pixmap = calc_pixmap(first_wcs, second_wcs)
@@ -104,31 +99,81 @@ def test_translated_map():
104
99
  # Got x-y transpose right
105
100
  assert_equal(pixmap.shape, ok_pixmap.shape)
106
101
  # Mapping an array to a translated array
107
- assert_almost_equal(pixmap, ok_pixmap, decimal=5)
102
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
108
103
 
109
104
 
110
- def test_estimate_pixel_scale_ratio():
111
- input_file = os.path.join(DATA_DIR, 'j8bt06nyq_flt.fits')
105
+ def test_disable_gwcs_bbox():
106
+ """
107
+ Map a pixel array to a translated version ofitself.
108
+ """
109
+ first_wcs = wcs_from_file(
110
+ "j8bt06nyq_sip_flt.fits",
111
+ ext=1,
112
+ wcs_type="gwcs"
113
+ )
114
+ second_wcs = wcs_from_file(
115
+ "j8bt06nyq_sip_flt.fits",
116
+ ext=1,
117
+ crpix_shift=(-2, -2), # shift loaded WCS by adding this to CRPIX
118
+ wcs_type="gwcs"
119
+ )
112
120
 
113
- with fits.open(input_file) as h:
114
- w = wcs.WCS(h[1].header)
121
+ ok_pixmap = np.indices(first_wcs.array_shape, dtype='float64') - 2.0
122
+ ok_pixmap = ok_pixmap.transpose()
123
+
124
+ # Mapping an array to a translated array
125
+
126
+ # disable both bounding boxes:
127
+ pixmap = calc_pixmap(first_wcs, second_wcs, disable_bbox="both")
128
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
129
+ assert np.all(np.isfinite(pixmap[:2, :2]))
130
+ assert np.all(np.isfinite(pixmap[-2:, -2:]))
131
+ # check bbox was restored
132
+ assert first_wcs.bounding_box is not None
133
+ assert second_wcs.bounding_box is not None
134
+
135
+ # disable "from" bounding box:
136
+ pixmap = calc_pixmap(second_wcs, first_wcs, disable_bbox="from")
137
+ assert_almost_equal(pixmap[:-2, :-2], ok_pixmap[:-2, :-2] + 4.0, decimal=5)
138
+ assert np.all(np.logical_not(np.isfinite(pixmap[-2:, -2:])))
139
+ # check bbox was restored
140
+ assert first_wcs.bounding_box is not None
141
+ assert second_wcs.bounding_box is not None
142
+
143
+ # disable "to" bounding boxes:
144
+ pixmap = calc_pixmap(first_wcs, second_wcs, disable_bbox="to")
145
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
146
+ assert np.all(np.isfinite(pixmap[:2, :2]))
147
+ assert np.all(pixmap[:2, :2] < 0.0)
148
+ assert np.all(np.isfinite(pixmap[-2:, -2:]))
149
+ # check bbox was restored
150
+ assert first_wcs.bounding_box is not None
151
+ assert second_wcs.bounding_box is not None
152
+
153
+ # enable all bounding boxes:
154
+ pixmap = calc_pixmap(first_wcs, second_wcs, disable_bbox="none")
155
+ assert_almost_equal(pixmap[2:, 2:], ok_pixmap[2:, 2:], decimal=5)
156
+ assert np.all(np.logical_not(np.isfinite(pixmap[:2, :2])))
157
+ # check bbox was restored
158
+ assert first_wcs.bounding_box is not None
159
+ assert second_wcs.bounding_box is not None
115
160
 
116
- pscale = estimate_pixel_scale_ratio(w, w, w.wcs.crpix, (0, 0))
117
161
 
162
+ def test_estimate_pixel_scale_ratio():
163
+ w = wcs_from_file("j8bt06nyq_flt.fits", ext=1)
164
+ pscale = estimate_pixel_scale_ratio(w, w, w.wcs.crpix, (0, 0))
118
165
  assert abs(pscale - 0.9999999916964737) < 1.0e-9
119
166
 
120
167
 
121
168
  def test_estimate_pixel_scale_no_refpix():
122
169
  # create a WCS without higher order (polynomial) distortions:
123
- fits_file = os.path.join(DATA_DIR, 'input1.fits')
124
- with fits.open(fits_file) as h:
125
- w = wcs.WCS(h[1].header, h)
126
- w.sip = None
127
- w.det2im1 = None
128
- w.det2im2 = None
129
- w.cpdis1 = None
130
- w.cpdis2 = None
131
- pixel_shape = w.pixel_shape[:]
170
+ w = wcs_from_file("j8bt06nyq_sip_flt.fits", ext=1)
171
+ w.sip = None
172
+ w.det2im1 = None
173
+ w.det2im2 = None
174
+ w.cpdis1 = None
175
+ w.cpdis2 = None
176
+ pixel_shape = w.pixel_shape[:]
132
177
 
133
178
  ref_pscale = _estimate_pixel_scale(w, w.wcs.crpix)
134
179
 
drizzle/utils.py CHANGED
@@ -7,7 +7,7 @@ __all__ = ["calc_pixmap", "decode_context", "estimate_pixel_scale_ratio"]
7
7
  _DEG2RAD = math.pi / 180.0
8
8
 
9
9
 
10
- def calc_pixmap(wcs_from, wcs_to, shape=None):
10
+ def calc_pixmap(wcs_from, wcs_to, shape=None, disable_bbox="to"):
11
11
  """
12
12
  Calculate a discretized on a grid mapping between the pixels of two images
13
13
  using provided WCS of the original ("from") image and the destination ("to")
@@ -35,6 +35,14 @@ def calc_pixmap(wcs_from, wcs_to, shape=None):
35
35
  ``numpy.ndarray`` order. When provided, it takes precedence over the
36
36
  ``wcs_from.array_shape`` property.
37
37
 
38
+ disable_bbox : {"to", "from", "both", "none"}, optional
39
+ Indicates whether to use or not to use the bounding box of either
40
+ (both) ``wcs_from`` or (and) ``wcs_to`` when computing pixel map. When
41
+ ``disable_bbox`` is "none", pixel coordinates outside of the bounding
42
+ box are set to `NaN` only if ``wcs_from`` or (and) ``wcs_to`` sets
43
+ world coordinates to NaN when input pixel coordinates are outside of
44
+ the bounding box.
45
+
38
46
  Returns
39
47
  -------
40
48
  pixmap : numpy.ndarray
@@ -57,16 +65,39 @@ def calc_pixmap(wcs_from, wcs_to, shape=None):
57
65
  If ``bounding_box`` is not available, a `ValueError` will be raised.
58
66
 
59
67
  """
68
+ if (bbox_from := getattr(wcs_from, "bounding_box", None)) is not None:
69
+ try:
70
+ # to avoid dependency on astropy just to check whether
71
+ # the bounding box is an instance of
72
+ # modeling.bounding_box.ModelBoundingBox, we try to
73
+ # directly use and bounding_box(order='F') and if it fails,
74
+ # fall back to converting the bounding box to a tuple
75
+ # (of intervals):
76
+ bbox_from = bbox_from.bounding_box(order='F')
77
+ except AttributeError:
78
+ bbox_from = tuple(bbox_from)
79
+
80
+ if (bbox_to := getattr(wcs_to, "bounding_box", None)) is not None:
81
+ try:
82
+ # to avoid dependency on astropy just to check whether
83
+ # the bounding box is an instance of
84
+ # modeling.bounding_box.ModelBoundingBox, we try to
85
+ # directly use and bounding_box(order='F') and if it fails,
86
+ # fall back to converting the bounding box to a tuple
87
+ # (of intervals):
88
+ bbox_to = bbox_to.bounding_box(order='F')
89
+ except AttributeError:
90
+ bbox_to = tuple(bbox_to)
91
+
60
92
  if shape is None:
61
93
  shape = wcs_from.array_shape
62
- if shape is None:
63
- if (bbox := getattr(wcs_from, "bounding_box", None)) is not None:
64
- if (nd := np.ndim(bbox)) == 1:
65
- bbox = (bbox, )
66
- if nd > 1:
67
- shape = tuple(
68
- int(math.ceil(lim[1] + 0.5)) for lim in bbox[::-1]
69
- )
94
+ if shape is None and bbox_from is not None:
95
+ if (nd := np.ndim(bbox_from)) == 1:
96
+ bbox_from = (bbox_from, )
97
+ if nd > 1:
98
+ shape = tuple(
99
+ int(math.ceil(lim[1] + 0.5)) for lim in bbox_from[::-1]
100
+ )
70
101
 
71
102
  if shape is None:
72
103
  raise ValueError(
@@ -74,7 +105,22 @@ def calc_pixmap(wcs_from, wcs_to, shape=None):
74
105
  )
75
106
 
76
107
  y, x = np.indices(shape, dtype=np.float64)
77
- x, y = wcs_to.world_to_pixel_values(*wcs_from.pixel_to_world_values(x, y))
108
+
109
+ # temporarily disable the bounding box for the "from" WCS:
110
+ if disable_bbox in ["from", "both"] and bbox_from is not None:
111
+ wcs_from.bounding_box = None
112
+ if disable_bbox in ["to", "both"] and bbox_to is not None:
113
+ wcs_to.bounding_box = None
114
+ try:
115
+ x, y = wcs_to.world_to_pixel_values(
116
+ *wcs_from.pixel_to_world_values(x, y)
117
+ )
118
+ finally:
119
+ if bbox_from is not None:
120
+ wcs_from.bounding_box = bbox_from
121
+ if bbox_to is not None:
122
+ wcs_to.bounding_box = bbox_to
123
+
78
124
  pixmap = np.dstack([x, y])
79
125
  return pixmap
80
126
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: drizzle
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: A package for combining dithered images into a single image
5
5
  Author-email: STScI <help@stsci.edu>
6
6
  License: Copyright (C) 2011,2014 Association of Universities for Research in
@@ -43,18 +43,19 @@ Requires-Python: >=3.10
43
43
  Description-Content-Type: text/x-rst
44
44
  License-File: LICENSE.rst
45
45
  Requires-Dist: numpy
46
- Requires-Dist: astropy
47
- Provides-Extra: docs
48
- Requires-Dist: sphinx ; extra == 'docs'
49
- Requires-Dist: sphinx-automodapi ; extra == 'docs'
50
- Requires-Dist: sphinx-rtd-theme ; extra == 'docs'
51
- Requires-Dist: matplotlib ; extra == 'docs'
52
- Requires-Dist: pytest-doctestplus ; extra == 'docs'
53
- Requires-Dist: tomli ; (python_version < "3.11") and extra == 'docs'
54
46
  Provides-Extra: test
55
- Requires-Dist: pytest ; extra == 'test'
56
- Requires-Dist: pytest-cov ; extra == 'test'
57
- Requires-Dist: pytest-doctestplus ; extra == 'test'
47
+ Requires-Dist: astropy; extra == "test"
48
+ Requires-Dist: gwcs; extra == "test"
49
+ Requires-Dist: pytest; extra == "test"
50
+ Requires-Dist: pytest-cov; extra == "test"
51
+ Requires-Dist: pytest-doctestplus; extra == "test"
52
+ Provides-Extra: docs
53
+ Requires-Dist: tomli; python_version < "3.11" and extra == "docs"
54
+ Requires-Dist: sphinx; extra == "docs"
55
+ Requires-Dist: sphinx-automodapi; extra == "docs"
56
+ Requires-Dist: sphinx-rtd-theme; extra == "docs"
57
+ Requires-Dist: matplotlib; extra == "docs"
58
+ Requires-Dist: pytest-doctestplus; extra == "docs"
58
59
 
59
60
  drizzle Documentation
60
61
  =====================
@@ -0,0 +1,16 @@
1
+ drizzle/__init__.py,sha256=hMpqmjPhrUWTRU0eXNOcrpiqQFGp4lf9opY8FXqLLEQ,325
2
+ drizzle/cdrizzle.cp310-win_amd64.pyd,sha256=C6SBGdZEGo_rlic5QZaQzcOxg9y5jV1HVIYfhh-ndfg,100864
3
+ drizzle/resample.py,sha256=LXc3TxaXvOd05zrszMa94JZbMSu7T3kDn4zoL3N7yeI,28982
4
+ drizzle/util.py,sha256=os9wHm1JkKiG5jtnNCZAXG3vnnXxLHBpi8OTWsiPI7k,845
5
+ drizzle/utils.py,sha256=hz6TVSb5dWIVw3P28EeeSc6PjVJNy4JAG5tB1v1yIrE,10846
6
+ drizzle/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ drizzle/tests/helpers.py,sha256=BF_IbAwBZFgrTglw33Mgw56xfKYqNJXVTtjCwUB_U98,5887
8
+ drizzle/tests/test_cdrizzle.py,sha256=utepqMiY8xtgQ8gBRBHwnlMhbBB1pq1xE4spf-wO7Kw,726
9
+ drizzle/tests/test_overlap_calc.py,sha256=ucwDL9fd8NVAxTdz-sWum_uobhm-TGkCr2yl69BKiC4,7062
10
+ drizzle/tests/test_resample.py,sha256=13UfYaGtTT2utQfF7j_8pQXzC51RFZ8EpRLFYSdz1MM,31600
11
+ drizzle/tests/test_utils.py,sha256=s4-z4ZMTcoIUyxHW0pMRpQB2GiA1lbfuNLQzkOgflp8,7691
12
+ drizzle-2.0.1.dist-info/LICENSE.rst,sha256=sUXj5W73D9TcOw5ZXaDdcthYdY2b2dTJPsxBuZTOYWQ,1505
13
+ drizzle-2.0.1.dist-info/METADATA,sha256=2G_rWumBwJpBy9MC7qc_c7CHA3qj_4RLxIHehazIIdM,10894
14
+ drizzle-2.0.1.dist-info/WHEEL,sha256=rzGfZgUcGeKSgIHGYMuqg4xE4VPHxnaldXH6BG0zjVk,101
15
+ drizzle-2.0.1.dist-info/top_level.txt,sha256=MA5uqwTj1sJBi-hCeQj9v3-sZ9nVUTe6bd_zGWTKy5A,8
16
+ drizzle-2.0.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp310-cp310-win_amd64
5
5
 
@@ -1,15 +0,0 @@
1
- drizzle/__init__.py,sha256=hMpqmjPhrUWTRU0eXNOcrpiqQFGp4lf9opY8FXqLLEQ,325
2
- drizzle/cdrizzle.cp310-win_amd64.pyd,sha256=TKAFcz4qTyNoaF7uL_c_Kwp7akC_-xYB0Rmq1Iwugic,100864
3
- drizzle/resample.py,sha256=t6HCYNWwnz4-mKYtzIWDFIEkHOi84ZI5GD4x3L6Wp0k,28982
4
- drizzle/util.py,sha256=os9wHm1JkKiG5jtnNCZAXG3vnnXxLHBpi8OTWsiPI7k,845
5
- drizzle/utils.py,sha256=Mze8pASdCiSXEsIJNIGkTcLbqszpJrrE5U576AtkzeI,8776
6
- drizzle/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- drizzle/tests/test_cdrizzle.py,sha256=utepqMiY8xtgQ8gBRBHwnlMhbBB1pq1xE4spf-wO7Kw,726
8
- drizzle/tests/test_overlap_calc.py,sha256=ucwDL9fd8NVAxTdz-sWum_uobhm-TGkCr2yl69BKiC4,7062
9
- drizzle/tests/test_resample.py,sha256=Xtov5vpVOEWOscKngGl8GkDyWSj_GpRNlceGIJ_Jdfg,41014
10
- drizzle/tests/test_utils.py,sha256=rlRvd7JKo7YeVPIhYAYg4WgXLN7yge39Zkngv8jq4ds,5889
11
- drizzle-2.0.0.dist-info/LICENSE.rst,sha256=sUXj5W73D9TcOw5ZXaDdcthYdY2b2dTJPsxBuZTOYWQ,1505
12
- drizzle-2.0.0.dist-info/METADATA,sha256=dv6lr7uK6t4T5IzDF4UYvS5vYXBFhd0ZWQdTPdFMJ0Y,10850
13
- drizzle-2.0.0.dist-info/WHEEL,sha256=IqiWNwTSPPvorR7mTezuRY2eqj__44JKKkjOiewDX64,101
14
- drizzle-2.0.0.dist-info/top_level.txt,sha256=MA5uqwTj1sJBi-hCeQj9v3-sZ9nVUTe6bd_zGWTKy5A,8
15
- drizzle-2.0.0.dist-info/RECORD,,