question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incorrect behavior in vectorized `wcs.world_to_pixel()` with TPV

See original GitHub issue

Description

The wcs.world_to_pixel() function can give incorrect results when run in vectorized mode with TPV.

Expected behavior

Results from vectorized mode are the same as in scalar mode.

Actual behavior

In my vectorized test case, outputs are mostly bogus.

Steps to Reproduce

Here is a reproduction case — apologies for the length:

from astropy.coordinates import SkyCoord
from astropy import units as u
from astropy.wcs import WCS
import numpy as np

# Create a WCS with a base TAN projection
hdr = {
    "WCSAXES": 2,
    "CRPIX1": 9019.3448,
    "CRPIX2": 9822.9018,
    "PC1_1": -0.00116096,
    "PC1_2": 0.000330426,
    "PC2_1": 0.000330397,
    "PC2_2": 0.00116203,
    "CDELT1": 1.0,
    "CDELT2": 1.0,
    "CUNIT1": "deg",
    "CUNIT2": "deg",
    "CTYPE1": "RA---TAN",
    "CTYPE2": "DEC--TAN",
    "CRVAL1": 337.103834,
    "CRVAL2": 90.0,
    "EQUINOX": 2000.0,
}
wcs_tan = WCS(hdr)

# Create a WCS with TPV distortion terms
hdr.update(
    **{
        "CTYPE1": "RA---TPV",
        "CTYPE2": "DEC--TPV",
        "PV1_0": -0.004862344579,
        "PV1_1": 0.9988506351,
        "PV1_2": 0.0003631415552,
        "PV1_4": -0.000151807543,
        "PV1_5": 0.0003264940806,
        "PV1_6": 1.054162749e-05,
        "PV1_7": 3.71399551e-05,
        "PV1_8": -4.673290603e-06,
        "PV1_9": -8.221049725e-06,
        "PV1_10": -2.048430933e-05,
        "PV1_12": 3.850243018e-06,
        "PV1_13": -3.850788487e-06,
        "PV1_14": -4.402412681e-07,
        "PV1_15": -1.261618912e-06,
        "PV1_16": -3.483007815e-07,
        "PV1_17": -2.971533523e-07,
        "PV1_18": 1.807889219e-07,
        "PV1_19": -2.141983906e-07,
        "PV1_20": 1.168331168e-07,
        "PV1_21": 1.762917378e-07,
        "PV1_22": 1.134792701e-07,
        "PV2_0": -0.005101922485,
        "PV2_1": 1.000314578,
        "PV2_2": 0.0009117987251,
        "PV2_4": 5.178903105e-05,
        "PV2_5": -0.0001677371386,
        "PV2_6": 0.0003132549032,
        "PV2_7": -1.196471938e-05,
        "PV2_8": -2.031118482e-05,
        "PV2_9": 1.334272569e-05,
        "PV2_10": -1.92055231e-05,
        "PV2_12": -3.595935319e-07,
        "PV2_13": 1.634133749e-07,
        "PV2_14": -1.36746203e-06,
        "PV2_15": 1.684772597e-06,
        "PV2_16": -3.050997407e-06,
        "PV2_17": 8.867628883e-08,
        "PV2_18": 1.641951829e-07,
        "PV2_19": -6.17124982e-08,
        "PV2_20": -2.511534806e-08,
        "PV2_21": -5.634176609e-08,
        "PV2_22": 1.882567755e-07,
    }
)
wcs_tpv = WCS(hdr)

# Vector of lats and lons that demonstrate the problem
lats = np.linspace(1.0453819570955787, 1.2938789521827248, 256)
lons = np.linspace(3.7637488459848645, 4.709526042452718, 256)
INDEX = 230

def do_scalar(wcs):
    "Calculate the pixel coordinate of a particular position with scalar evaluation"
    c = SkyCoord(lons[INDEX] * u.rad, lats[INDEX] * u.rad, frame="icrs")
    idx = wcs.world_to_pixel(c)
    return (idx[0].item(), idx[1].item())

def do_vector(wcs):
    "Calculate the pixel coordinate of a particular pixel with vector evaluation"
    c = SkyCoord(lons * u.rad, lats * u.rad, frame="icrs")
    idx = wcs.world_to_pixel(c)
    return (idx[0][INDEX], idx[1][INDEX])

# Without distortions, results are consistent as you would hope:
print("TAN scalar:", do_scalar(wcs_tan))
print("TAN vector:", do_vector(wcs_tan))

# With distortions, results are not consistent:
print("TPV scalar:", do_scalar(wcs_tpv))
print("TPV vector:", do_vector(wcs_tpv))

Comparing the result of wcs.world_to_pixel() for the scalar versus vector inputs here, it looks like the 0’th element of the array is correct, but the rest are garbage. So, perhaps something is trying to vectorize but not actually initializing anything past the 0’th element?

Update: If I run the test repeatedly, the results from the vector-TPV case vary, although they are always around -1. So there is probably some uninitialized memory being read here.

System Details

Linux-5.18.13-200.fc36.x86_64-x86_64-with-glibc2.35
Python 3.9.13 | packaged by conda-forge | (main, May 27 2022, 16:56:21) 
[GCC 10.3.0]
Numpy 1.23.1
pyerfa 2.0.0.1
astropy 5.1
Scipy 1.8.1
Matplotlib 3.5.2

CC @imbasimba

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:11 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
pkgwcommented, Sep 1, 2022

Thanks for digging into this! I’ll see if I can create a pure-WCSLIB reproduction case and report it to Mark if so. In the meantime I’d advocate for keeping this issue open until we retire that last 0.01% of uncertainty about where the bug lies. I’ll post follow-up comments as I dig in.

0reactions
pkgwcommented, Sep 7, 2022

Noting for posterity: I sent Mark an email about this, CC’ing @mcara. I think that I’ve identified an issue in how WCSLIB handles errors in the situation created by this test case.

Read more comments on GitHub >

github_iconTop Results From Across the Web

World Coordinate System (astropy.wcs)
astropy.wcs contains utilities for managing World Coordinate System (WCS) ... Perform just the core WCS transformation from world to pixel coordinates.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found