Skip to content

Commit 6c526d4

Browse files
committed
fix: raise errors for celestial coords
1 parent f1498e2 commit 6c526d4

6 files changed

Lines changed: 88 additions & 22 deletions

File tree

jax_galsim/angle.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,30 @@
2121
# SOFTWARE.
2222
import galsim as _galsim
2323
import jax.numpy as jnp
24+
import numpy as np
2425
from jax.tree_util import register_pytree_node_class
2526

26-
from jax_galsim.core.utils import cast_to_float, ensure_hashable, implements
27+
from jax_galsim.core.utils import (
28+
cast_to_float,
29+
ensure_hashable,
30+
has_tracers,
31+
implements,
32+
)
33+
34+
NON_COMPLEX_TYPES = (
35+
float,
36+
int,
37+
np.int16,
38+
np.int32,
39+
np.int64,
40+
np.float32,
41+
np.float64,
42+
jnp.int16,
43+
jnp.int32,
44+
jnp.int64,
45+
jnp.float32,
46+
jnp.float64,
47+
)
2748

2849

2950
@implements(_galsim.AngleUnit)
@@ -178,15 +199,23 @@ def __sub__(self, other):
178199
return _Angle(self._rad - other._rad)
179200

180201
def __mul__(self, other):
202+
if not (has_tracers(other) or isinstance(other, NON_COMPLEX_TYPES)):
203+
raise TypeError(
204+
"Cannot multiply Angle by %s of type %s" % (other, type(other))
205+
)
181206
return _Angle(self._rad * other)
182207

183208
__rmul__ = __mul__
184209

185210
def __div__(self, other):
186211
if isinstance(other, AngleUnit):
187212
return self._rad / other.value
188-
else:
213+
elif has_tracers(other) or isinstance(other, NON_COMPLEX_TYPES):
189214
return _Angle(self._rad / other)
215+
else:
216+
raise TypeError(
217+
"Cannot divide Angle by %s of type %s" % (other, type(other))
218+
)
190219

191220
__truediv__ = __div__
192221

jax_galsim/celestial.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
from functools import partial
2424

2525
import coord as _coord
26+
import equinox
2627
import galsim as _galsim
2728
import jax
2829
import jax.numpy as jnp
30+
import numpy as np
2931
from jax.tree_util import register_pytree_node_class
3032

3133
from jax_galsim.angle import Angle, _Angle, arcsec, degrees, radians
@@ -74,6 +76,16 @@ def __init__(self, ra, dec=None):
7476
elif not isinstance(dec, Angle):
7577
raise TypeError("dec must be a galsim.Angle")
7678
else:
79+
if isinstance(dec._rad, (float, int)):
80+
if dec._rad < -np.pi / 2 or dec._rad > np.pi / 2:
81+
raise ValueError("dec must be between -90 deg and +90 deg.")
82+
else:
83+
dec._rad = equinox.error_if(
84+
jnp.array(dec._rad),
85+
jnp.any((dec._rad < -jnp.pi / 2) | (dec._rad > jnp.pi / 2)),
86+
"dec must be between -90 deg and +90 deg.",
87+
)
88+
7789
# Normal case
7890
self._ra = ra
7991
self._dec = dec
@@ -121,15 +133,14 @@ def get_xyz(self):
121133

122134
@staticmethod
123135
@jax.jit
124-
@implements(
125-
_galsim.celestial.CelestialCoord.from_xyz,
126-
lax_description=(
127-
"The JAX version of this static method does not check that the norm of the input "
128-
"vector is non-zero."
129-
),
130-
)
136+
@implements(_galsim.celestial.CelestialCoord.from_xyz)
131137
def from_xyz(x, y, z):
132138
norm = jnp.sqrt(x * x + y * y + z * z)
139+
norm = equinox.error_if(
140+
norm,
141+
jnp.any(norm == 0),
142+
"CelestialCoord for position (0,0,0) is undefined.",
143+
)
133144
ret = CelestialCoord.__new__(CelestialCoord)
134145
ret._x = x / norm
135146
ret._y = y / norm
@@ -236,13 +247,7 @@ def distanceTo(self, coord2):
236247

237248
return _Angle(theta)
238249

239-
@implements(
240-
_galsim.celestial.CelestialCoord.greatCirclePoint,
241-
lax_description=(
242-
"The JAX version of this method does not check that coord2 defines a unique great "
243-
"circle with the current coord at angle theta."
244-
),
245-
)
250+
@implements(_galsim.celestial.CelestialCoord.greatCirclePoint)
246251
@jax.jit
247252
def greatCirclePoint(self, coord2, theta):
248253
aux = self._get_aux()
@@ -280,8 +285,11 @@ def greatCirclePoint(self, coord2, theta):
280285

281286
# Normalize
282287
wr = (wx**2 + wy**2 + wz**2) ** 0.5
283-
# if wr == 0.:
284-
# raise ValueError("coord2 does not define a unique great circle with self.")
288+
wr = equinox.error_if(
289+
wr,
290+
jnp.any(wr == 0),
291+
"coord2 does not define a unique great circle with self.",
292+
)
285293
wx /= wr
286294
wy /= wr
287295
wz /= wr

tests/GalSim

tests/conftest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ def pytest_collection_modifyitems(config, items):
9898
):
9999
item.add_marker(skip)
100100

101+
if any([t in item.nodeid for t in test_config["skipped_tests"]["coord"]]):
102+
item.add_marker(skip)
103+
101104

102105
@lru_cache(maxsize=128)
103106
def _infile(val, fname):

tests/galsim_tests_config.yaml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ enabled_tests:
2828
- test_astropy.py
2929
- test_celestial.py
3030

31+
# tests to explicitly skip
32+
# applied on top of the enabled set above
33+
skipped_tests:
34+
coord:
35+
- "tests/Coord/tests/test_celestial.py::test_xyz_raises"
36+
- "tests/Coord/tests/test_celestial.py::test_greatcircle_raises"
37+
3138
# This documents which error messages will be allowed
3239
# without being reported as an error. These typically
3340
# correspond to features that are not implemented yet
@@ -88,9 +95,8 @@ allowed_failures:
8895
- "module 'jax_galsim' has no attribute 'CorrelatedNoise'"
8996
- "CelestialCoord.precess is too slow" # cannot get jax to warmup but once it does it passes
9097
- "ValueError not raised by from_xyz"
91-
- "ValueError not raised by greatCirclePoint"
92-
- "TypeError not raised by __mul__"
93-
- "ValueError not raised by CelestialCoord"
98+
# - "ValueError not raised by greatCirclePoint"
99+
# - "ValueError not raised by CelestialCoord"
94100
- "module 'jax_galsim' has no attribute 'BaseCorrelatedNoise'"
95101
- "module 'jax_galsim' has no attribute 'fft'"
96102
- "Transform does not support callable arguments."

tests/jax/test_celestial_jax.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import galsim as _galsim
2+
import jax.numpy as jnp
23
import numpy as np
34
import pytest
45

@@ -118,3 +119,22 @@ def test_celestial_jax_ecliptic_obliquity():
118119
ecliptic_obliquity(epoch).rad,
119120
_ecliptic_obliquity(epoch).rad,
120121
)
122+
123+
124+
def test_celestial_jax_xyz_raises():
125+
np.testing.assert_raises(
126+
Exception, jax_galsim.CelestialCoord.from_xyz, 0.0, 0.0, 0.0
127+
)
128+
129+
130+
def test_celestial_jax_greatcircle_raises():
131+
theta = 50 * jax_galsim.radians
132+
eq1 = jax_galsim.CelestialCoord(
133+
0 * jax_galsim.radians, 0 * jax_galsim.radians
134+
) # point on the equator
135+
eq2 = jax_galsim.CelestialCoord(
136+
jnp.array(1) * jax_galsim.radians, 0 * jax_galsim.radians
137+
) # 1 radian along equator
138+
139+
np.testing.assert_raises(Exception, eq1.greatCirclePoint, eq1, theta)
140+
np.testing.assert_raises(Exception, eq2.greatCirclePoint, eq2, theta)

0 commit comments

Comments
 (0)