From a7458f7693d93b3d7a9e4a916b2ea2a3ccaa9eda Mon Sep 17 00:00:00 2001 From: OfficialAbhinavSingh Date: Mon, 6 Jul 2026 22:21:31 +0530 Subject: [PATCH] Add output validation and fix missing noise in simple_sim_2 DeepLens.simple_sim_2 computed Poisson noise but never added it to the returned image (self.image_real = self.image_model + self.image_model, doubling the noiseless model instead of using self.poisson). This silently produced noiseless training/validation images for every Model_II/III/IV run using the Euclid/HST-resolution pipeline. Also add deeplense/validation.py to catch NaN/Inf/empty/constant images from failed lens configurations, wired into both simple_sim and simple_sim_2 (replacing a NaN check that had been written and then commented out). Wrap the Model_I-III batch simulation loops so a single failed draw is logged and skipped instead of crashing the entire (multi-thousand-iteration) SLURM job. --- Model_I/sim_axion.py | 22 +++++++++++++++------- Model_I/sim_cdm.py | 22 +++++++++++++++------- Model_I/sim_no_sub.py | 22 +++++++++++++++------- Model_II/sim_axion.py | 24 ++++++++++++++++-------- Model_II/sim_cdm.py | 24 ++++++++++++++++-------- Model_II/sim_no_sub.py | 24 ++++++++++++++++-------- Model_III/sim_axion.py | 24 ++++++++++++++++-------- Model_III/sim_cdm.py | 24 ++++++++++++++++-------- Model_III/sim_no_sub.py | 24 ++++++++++++++++-------- deeplense/lens.py | 8 ++++++-- deeplense/validation.py | 34 ++++++++++++++++++++++++++++++++++ 11 files changed, 181 insertions(+), 71 deletions(-) create mode 100644 deeplense/validation.py diff --git a/Model_I/sim_axion.py b/Model_I/sim_axion.py index e778412..87f5b06 100644 --- a/Model_I/sim_axion.py +++ b/Model_I/sim_axion.py @@ -11,14 +11,22 @@ axion_masses = 10**np.random.uniform(-24,-22,num_sim) +failures = 0 for i in range(num_sim): - lens = DeepLens(axion_mass=axion_masses[i]) - lens.make_single_halo(1e12) - lens.make_vortex(3e10) - lens.make_source_light() - lens.simple_sim() - File = np.array([lens.image_real,axion_masses[i]]) - np.save('/users/mtoomey/scratch/deeplense/Model_I_test/axion/axion_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens(axion_mass=axion_masses[i]) + lens.make_single_halo(1e12) + lens.make_vortex(3e10) + lens.make_source_light() + lens.simple_sim() + File = np.array([lens.image_real,axion_masses[i]]) + np.save('/users/mtoomey/scratch/deeplense/Model_I_test/axion/axion_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_axion: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_axion: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_I/sim_cdm.py b/Model_I/sim_cdm.py index 2811275..d9e0b49 100644 --- a/Model_I/sim_cdm.py +++ b/Model_I/sim_cdm.py @@ -8,14 +8,22 @@ # Number of sims num_sim = int(5e3) +failures = 0 for i in range(num_sim): - lens = DeepLens() - lens.make_single_halo(1e12) - lens.make_old_cdm() - lens.make_source_light() - lens.simple_sim() - File = lens.image_real - np.save('/users/mtoomey/scratch/deeplense/Model_I_test/cdm/cdm_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens() + lens.make_single_halo(1e12) + lens.make_old_cdm() + lens.make_source_light() + lens.simple_sim() + File = lens.image_real + np.save('/users/mtoomey/scratch/deeplense/Model_I_test/cdm/cdm_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_cdm: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_cdm: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_I/sim_no_sub.py b/Model_I/sim_no_sub.py index 9d45151..2058afc 100644 --- a/Model_I/sim_no_sub.py +++ b/Model_I/sim_no_sub.py @@ -8,14 +8,22 @@ # Number of sims num_sim = int(5e3) +failures = 0 for i in range(num_sim): - lens = DeepLens() - lens.make_single_halo(1e12) - lens.make_no_sub() - lens.make_source_light() - lens.simple_sim() - File = lens.image_real - np.save('/users/mtoomey/scratch/deeplense/Model_I_test/no_sub/no_sub_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens() + lens.make_single_halo(1e12) + lens.make_no_sub() + lens.make_source_light() + lens.simple_sim() + File = lens.image_real + np.save('/users/mtoomey/scratch/deeplense/Model_I_test/no_sub/no_sub_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_no_sub: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_no_sub: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_II/sim_axion.py b/Model_II/sim_axion.py index a3e5e28..09fef60 100644 --- a/Model_II/sim_axion.py +++ b/Model_II/sim_axion.py @@ -11,15 +11,23 @@ axion_masses = 10**np.random.uniform(-24,-22,num_sim) +failures = 0 for i in range(num_sim): - lens = DeepLens(axion_mass=axion_masses[i]) - lens.make_single_halo(1e12) - lens.make_vortex(3e10) - lens.set_instrument('Euclid') - lens.make_source_light_mag() - lens.simple_sim_2() - File = np.array([lens.image_real,axion_masses[i]]) - np.save('/users/mtoomey/scratch/deeplense/Model_II_test/axion/axion_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens(axion_mass=axion_masses[i]) + lens.make_single_halo(1e12) + lens.make_vortex(3e10) + lens.set_instrument('Euclid') + lens.make_source_light_mag() + lens.simple_sim_2() + File = np.array([lens.image_real,axion_masses[i]]) + np.save('/users/mtoomey/scratch/deeplense/Model_II_test/axion/axion_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_axion: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_axion: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_II/sim_cdm.py b/Model_II/sim_cdm.py index ca9e4f3..3163310 100644 --- a/Model_II/sim_cdm.py +++ b/Model_II/sim_cdm.py @@ -8,15 +8,23 @@ # Number of sims num_sim = int(5e3) +failures = 0 for i in range(num_sim): - lens = DeepLens() - lens.make_single_halo(1e12) - lens.make_old_cdm() - lens.set_instrument('Euclid') - lens.make_source_light_mag() - lens.simple_sim_2() - File = lens.image_real - np.save('/users/mtoomey/scratch/deeplense/Model_II_test/cdm/cdm_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens() + lens.make_single_halo(1e12) + lens.make_old_cdm() + lens.set_instrument('Euclid') + lens.make_source_light_mag() + lens.simple_sim_2() + File = lens.image_real + np.save('/users/mtoomey/scratch/deeplense/Model_II_test/cdm/cdm_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_cdm: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_cdm: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_II/sim_no_sub.py b/Model_II/sim_no_sub.py index 8c1cade..8025285 100644 --- a/Model_II/sim_no_sub.py +++ b/Model_II/sim_no_sub.py @@ -8,15 +8,23 @@ # Number of sims num_sim = int(5e3) +failures = 0 for i in range(num_sim): - lens = DeepLens() - lens.make_single_halo(1e12) - lens.make_no_sub() - lens.set_instrument('Euclid') - lens.make_source_light_mag() - lens.simple_sim_2() - File = lens.image_real - np.save('/users/mtoomey/scratch/deeplense/Model_II_test/no_sub/no_sub_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens() + lens.make_single_halo(1e12) + lens.make_no_sub() + lens.set_instrument('Euclid') + lens.make_source_light_mag() + lens.simple_sim_2() + File = lens.image_real + np.save('/users/mtoomey/scratch/deeplense/Model_II_test/no_sub/no_sub_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_no_sub: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_no_sub: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_III/sim_axion.py b/Model_III/sim_axion.py index 8c976a1..a35a4e5 100644 --- a/Model_III/sim_axion.py +++ b/Model_III/sim_axion.py @@ -11,15 +11,23 @@ axion_masses = 10**np.random.uniform(-24,-22,num_sim) +failures = 0 for i in range(num_sim): - lens = DeepLens(axion_mass=axion_masses[i]) - lens.make_single_halo(1e12) - lens.make_vortex(3e10) - lens.set_instrument('hst') - lens.make_source_light_mag() - lens.simple_sim_2() - File = np.array([lens.image_real,axion_masses[i]]) - np.save('/users/mtoomey/scratch/deeplense/Model_III_test/axion/axion_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens(axion_mass=axion_masses[i]) + lens.make_single_halo(1e12) + lens.make_vortex(3e10) + lens.set_instrument('hst') + lens.make_source_light_mag() + lens.simple_sim_2() + File = np.array([lens.image_real,axion_masses[i]]) + np.save('/users/mtoomey/scratch/deeplense/Model_III_test/axion/axion_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_axion: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_axion: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_III/sim_cdm.py b/Model_III/sim_cdm.py index edce33d..6259f36 100644 --- a/Model_III/sim_cdm.py +++ b/Model_III/sim_cdm.py @@ -8,15 +8,23 @@ # Number of sims num_sim = int(3e5) +failures = 0 for i in range(num_sim): - lens = DeepLens() - lens.make_single_halo(1e12) - lens.make_old_cdm() - lens.set_instrument('hst') - lens.make_source_light_mag() - lens.simple_sim_2() - File = lens.image_real - np.save('/users/mtoomey/scratch/deeplense/Model_III_test/cdm/cdm_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens() + lens.make_single_halo(1e12) + lens.make_old_cdm() + lens.set_instrument('hst') + lens.make_source_light_mag() + lens.simple_sim_2() + File = lens.image_real + np.save('/users/mtoomey/scratch/deeplense/Model_III_test/cdm/cdm_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_cdm: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_cdm: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/Model_III/sim_no_sub.py b/Model_III/sim_no_sub.py index 94dec4c..e0ae0b5 100644 --- a/Model_III/sim_no_sub.py +++ b/Model_III/sim_no_sub.py @@ -8,15 +8,23 @@ # Number of sims num_sim = int(3e5) +failures = 0 for i in range(num_sim): - lens = DeepLens() - lens.make_single_halo(1e12) - lens.make_no_sub() - lens.set_instrument('hst') - lens.make_source_light_mag() - lens.simple_sim_2() - File = lens.image_real - np.save('/users/mtoomey/scratch/deeplense/Model_III_test/no_sub/no_sub_sim_' + str(random.getrandbits(128)),File) + try: + lens = DeepLens() + lens.make_single_halo(1e12) + lens.make_no_sub() + lens.set_instrument('hst') + lens.make_source_light_mag() + lens.simple_sim_2() + File = lens.image_real + np.save('/users/mtoomey/scratch/deeplense/Model_III_test/no_sub/no_sub_sim_' + str(random.getrandbits(128)),File) + except Exception as exc: + failures += 1 + print(f"sim_no_sub: skipping sim {i} after failure: {exc}") + continue + +print(f"sim_no_sub: completed with {failures} failed sim(s) out of {num_sim}") diff --git a/deeplense/lens.py b/deeplense/lens.py index 9ea428b..cb550db 100644 --- a/deeplense/lens.py +++ b/deeplense/lens.py @@ -11,6 +11,8 @@ from lenstronomy.LensModel.lens_model import LensModel from lenstronomy.SimulationAPI.sim_api import SimAPI +from deeplense.validation import validate_image + #TODO this is only valid for halo z=0.5 @@ -267,7 +269,8 @@ def simple_sim(self): bkg = image_util.add_background(image_model, sigma_bkd=background_rms) image_real = exp_time * (image_model + poisson + bkg) - self.image_real = np.random.poisson(image_real.clip(min=0))#print(np.isnan(image_real).any()) + self.image_real = np.random.poisson(image_real.clip(min=0)) + validate_image(self.image_real) self.image_model = image_model self.poisson = poisson self.bkg = bkg @@ -310,7 +313,8 @@ def simple_sim_2(self): self.image_model = image self.poisson = sim.noise_for_model(model=image) - self.image_real = self.image_model + self.image_model + self.image_real = self.image_model + self.poisson + validate_image(self.image_real) def set_instrument(self,inst_name): """ diff --git a/deeplense/validation.py b/deeplense/validation.py new file mode 100644 index 0000000..9f16969 --- /dev/null +++ b/deeplense/validation.py @@ -0,0 +1,34 @@ +import numpy as np + + +class SimulationValidationError(ValueError): + """Raised when a simulated image fails a numerical/physical sanity check.""" + + +def validate_image(image): + """ + Sanity-check a simulated lensing image before it is saved to disk. + + Catches the failure modes that otherwise silently corrupt a batch run: + NaN/Inf pixels (unstable lens configuration), empty arrays, and + constant/zero-variance images (a degenerate sim that produced no + signal). Returns the image unchanged so it can be used inline. + """ + image = np.asarray(image) + + if image.size == 0: + raise SimulationValidationError("simulated image is empty") + + if np.isnan(image).any(): + raise SimulationValidationError("simulated image contains NaN values") + + if np.isinf(image).any(): + raise SimulationValidationError("simulated image contains Inf values") + + if np.all(image == image.flat[0]): + raise SimulationValidationError( + "simulated image has zero variance (constant image, likely a " + "failed lens/source configuration)" + ) + + return image