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

Fix floating point issues #194

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion romanisim/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,19 @@ def simulate_counts_generic(image, exptime, objlist=None, psf=None,
image.quantize()
rng_numpy_seed = rng.raw()
rng_numpy = np.random.default_rng(rng_numpy_seed)

# NOTE: Here, we convert the array of float32 values to int32 (i4), so
# we need to "clip" them to be in the valid range first. However, just
# clipping with the maximum int32 value (2^31 - 1) isn't sufficient.
# This is because `np.float32(2**31 - 1)` is the same value as
# `np.float32(2**31)` due to floating point imprecision, and on some
# architectures, converting that value to int32 rolls over to a negative
# number. To resolve, we use `np.nextafter` to get the previous floating
# point number, which is roughly 2^31 - 128.
MAX_SAFE_VALUE = np.nextafter(np.float32(2**31 - 1), 0)
image.array[:, :] = rng_numpy.binomial(
np.clip(image.array, 0, 2**31 - 1).astype('i4'), flat / maxflat)
np.clip(image.array, 0, MAX_SAFE_VALUE).astype("i4"), flat / maxflat
)

if dark is not None:
workim = image * 0
Expand Down
13 changes: 13 additions & 0 deletions romanisim/tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,19 @@ def test_simulate_counts_generic():
assert np.sum(objinfo['counts'] > 0) == 0
# these sources should be out of bounds

### Assert that out-of-range values do not cause integer overflow:
try:
# Have numpy raise on warnings:
np.seterr(all='raise')
# Test simulating with a value that is out of range for an int32
im9 = im.copy()
im9.array[0][0] = np.float32(2**40)
image.simulate_counts_generic(im9, exptime, sky=sky, flat=0.5, zpflux=zpflux)
finally:
# revert numpy warning settings to default
np.seterr(all='print')



def test_simulate_counts():
imdict = set_up_image_rendering_things()
Expand Down
Loading