diff --git a/imsim/lsst_image.py b/imsim/lsst_image.py index 8b6a4329..302ec1bf 100644 --- a/imsim/lsst_image.py +++ b/imsim/lsst_image.py @@ -38,7 +38,14 @@ def setup(self, config, base, image_num, obj_num, ignore, logger): image_num,image_num,obj_num) self.nobjects = self.getNObj(config, base, image_num, logger=logger) - logger.debug('image %d: nobj = %d',image_num,self.nobjects) + if 'nobjects' in config: + # User specified nobjects. + # Make sure it's not more than what any input catalog can + # handle (we don't want repeated objects). + input_nobj = galsim.config.ProcessInputNObjects(base) + if input_nobj is not None: + self.nobjects = min(self.nobjects, input_nobj) + logger.info('image %d: nobj = %d', image_num, self.nobjects) # These are allowed for LSST_Image, but we don't use them here. extra_ignore = [ 'image_pos', 'world_pos', 'stamp_size', 'stamp_xsize', 'stamp_ysize', diff --git a/tests/test_lsst_image.py b/tests/test_lsst_image.py new file mode 100644 index 00000000..6eb566a9 --- /dev/null +++ b/tests/test_lsst_image.py @@ -0,0 +1,71 @@ +import os +import shutil +import sys +import logging +from pathlib import Path +import numpy as np +import galsim + + +def test_image_nobjects(): + """ + Test that the minimum of the optional config setting of + image.nobjects and the number of objects available is used to + avoid repeated object renderings. + """ + imsim_dir = os.path.dirname(os.path.abspath(str(Path(__file__).parent))) + os.environ['SIMS_SED_LIBRARY_DIR'] \ + = os.path.join(imsim_dir, 'tests', 'data', 'test_sed_library') + template = os.path.join(imsim_dir, 'config', 'imsim-config-instcat.yaml') + instcat_file = os.path.join(imsim_dir, 'tests', 'data', + 'test_multiproc_instcat.txt') + + logger = logging.getLogger('test_lsst_image') + if len(logger.handlers) == 0: + logger.addHandler(logging.StreamHandler(sys.stdout)) + logger.setLevel(logging.CRITICAL) # silence the log messages + + camera = "LsstCam" + output_dir = f"fits_{camera}" + + # Loop over values of image.nobjects that bracket the expected number + # from the instance catalog to test the number of objects actually + # rendered. + for nobjects, nexpected in zip((1, 5, ""), (1, 3, 3)): + config = {'modules': ['imsim'], + 'template': template, + 'input.instance_catalog.file_name': instcat_file, + 'input.opsim_data.file_name': instcat_file, + 'input.tree_rings': '', + 'input.atm_psf': '', + 'input.checkpoint': '', + 'image.sky_level': 0, + 'image.random_seed': 42, + 'image.sensor': '', + 'image.nobjects': nobjects, + 'stamp.fft_sb_thresh': '1e5', + 'stamp.size': 48, + 'psf.items': '', + 'psf.type': 'Gaussian', + 'psf.fwhm': 0.7, + 'output.camera': camera, + 'output.cosmic_ray_rate': 0, + 'output.det_num.first': 94, + 'output.nfiles': 1, + 'output.readout': '', + 'output.dir': output_dir, + 'output.truth.dir': output_dir, + 'output.truth.file_name.format': 'centroid_%08d-%1d-%s-%s-det%03d.txt', + } + + galsim.config.Process(config, logger=logger) + data = np.genfromtxt(f"{output_dir}/centroid_00161899-0-r-R22_S11-det094.txt", + names=True) + assert nexpected == data.size + + shutil.rmtree(output_dir) + +if __name__ == '__main__': + testfns = [v for k, v in vars().items() if k[:5] == 'test_' and callable(v)] + for testfn in testfns: + testfn()