Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precision issues near poles for large values of nside #34

Open
astrofrog opened this issue Sep 25, 2017 · 10 comments
Open

Precision issues near poles for large values of nside #34

astrofrog opened this issue Sep 25, 2017 · 10 comments

Comments

@astrofrog
Copy link
Member

astrofrog commented Sep 25, 2017

At the moment, our longitude/latitude to pixel conversion has a lower precision than that of the official HEALPix library close to the poles. This is visible when making a map of pixel values for 2**28 for the following range of coordinates:

lat_min = 89.999996
lat_max = 89.999997
lon_min = -5
lon_max = +5

Original HEALPix library (via healpy)

healpy_true

This package

healpy_false

I think I've tracked down the issue to the xyztohp function, and I think the issue could be with these lines:

        // solve eqn 20: k = Ns - xx (in the northern hemi)
		root = (1.0 - vz*zfactor) * 3.0 * mysquare(Nside * (2.0 * phi_t - pi) / pi);
		kx = (root <= 0.0) ? 0.0 : sqrt(root);

        // solve eqn 19 for k = Ns - yy
		root = (1.0 - vz*zfactor) * 3.0 * mysquare(Nside * 2.0 * phi_t / pi);
		ky = (root <= 0.0) ? 0.0 : sqrt(root);

		if (north) {
			xx = Nside - kx;
			yy = Nside - ky;
		} else {
			xx = ky;
			yy = kx;
		}

The issue is that doubles actually have less precision information than int64 (only 52 bits are allocated to significant precision), so by going through double and doing operations such as sqrt etc which further degrade precision, I think we are losing precision there. So this may not be a 32-bit vs 64-bit int issue but rather an issue with floating point precision. We should investigate whether we can improve the precision here, for example by using long double or finding other ways to avoid precision loss. For now, I will update the documentation to mention the resolution to which the results can be trusted.

@dstndstn - if you have any ideas on improving precision here, please feel free to comment!

@astrofrog astrofrog changed the title Precision issues for large values of nside Precision issues near poles for large values of nside Sep 25, 2017
@astrofrog astrofrog added this to the Future milestone Sep 25, 2017
@dstndstn
Copy link
Collaborator

dstndstn commented Sep 25, 2017 via email

@dstndstn
Copy link
Collaborator

I had a further look at this, and indeed the precision loss is in converting to unit-sphere coordinates. In order to fix this, I think one would have to pass Dec, in addition to z, into xyztohp -- or maybe pass in (1-z) and z -- or event sqrt(1-z) and z if you want to get really fancy -- and then use trig identities.

@dstndstn
Copy link
Collaborator

PS, it's things like this that make me hate the healpix paper.

@dstndstn
Copy link
Collaborator

In e1df57b I used "long double" trig functions and the result seems to fix this resolution problem.

polar

I only did that for the one function used by the library, but presumably we could use this approach more widely. I assume there is some computational cost for using the long double trig functions, so I don't know whether to use this everywhere or not.

@cdeil
Copy link
Member

cdeil commented Jun 26, 2018

@dstndstn - Do you understand this? Is "double" 64 bit and "long double" more? Or are both 64 bit and just the C functions called are higher precision somehow?

Maybe open a PR with the commit you have, and wait for @astrofrog to comment whether to merge as-is or apply more widely?

@dstndstn
Copy link
Collaborator

"long double" is longer than 64 bits. How long depends on implementation;
https://en.wikipedia.org/wiki/Long_double

@dstndstn
Copy link
Collaborator

PR #93

@dstndstn
Copy link
Collaborator

PR #94 instead?

@fxpineau
Copy link

fxpineau commented Jul 2, 2018

I don't know if it helps but in the case of the CDS Java HEALPix lib I developed, I replaced \sqrt{3(1-\sin\delta)} by the equivalent \sqrt{6}\cos(\delta/2 + \pi/4) for the Collignon projection (=> we also save a sqrt computation, which is a slow operation).
Basically, the costly operations are: a sine for the Cylindrical projection, a cosine for the Collignon projection.

@fxpineau
Copy link

fxpineau commented Jul 2, 2018

(In your lib, see more efficient algo to compute the Morton code for not small orders here: https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableLookup)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants