Repository navigation
Rubin deep coadd simulation code #521
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
Merged
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
d61885b
Add interface to deep_coadds and cell-based coadd PSFs
jchiang87 c4cb7ab
rename coadd_psf.py -> deep_coadd.py
jchiang87 489317e
provide info on deep_coadds more generally
jchiang87 e160fd2
initial implementation of coadd image builder
jchiang87 fffa020
initial implementation of coadd wcs builder
jchiang87 ef0fae0
add RubinDeepCoaddOutput type; adjust various configs
jchiang87 ac0a3da
add deep-coadd template yaml
jchiang87 fc753cf
initial stamp and noise code
jchiang87 8d15b6c
add RubinDeepCoaddBandpass
jchiang87 d95c817
implement .draw method for RubinDeepCoaddStampBuilder
jchiang87 bcd33c2
use LSST_SiliconBuilder as base class; enable fft rendering
jchiang87 bedafcc
enable iterating over coadds
jchiang87 5917ee6
revert inadvertant changes
jchiang87 909073b
revert inadvertant whitespace change
jchiang87 27fc58f
move psf builder to a separate file; try to use consistent naming thr…
jchiang87 a991c70
switch to using lsst.images version of deep_coadd throughout; also co…
jchiang87 cc1e198
add access to number of visits per cell; refactor caching
jchiang87 86c42e3
use photon ops weighting to scale object fluxes so that output units …
jchiang87 523ccbe
add default input.deep_coadds config
jchiang87 5fddd54
set maximum number of simulated photons to avoid excess memory usage
jchiang87 3beeafa
use the noise realization to estimate the noise variance for stamp si…
jchiang87 2edcc27
use maxN in drawImage to limit the memory usage for bright objects
jchiang87 29b5643
add class docstring and some comments
jchiang87 729d09a
disable fft option for deep_coadd sims
jchiang87 02eda92
set noise_var to avoid apparent stamp edges; add output.truth section…
jchiang87 58610d5
update DeepCoadds.getPSF and .getNumVisits interfaces to pass the coo…
jchiang87 dd3fb79
add RubinDeepCoaddGaussianNoise type and require user to provide a no…
jchiang87 729e56a
divide noise_var value passed to get_stamp_size by 3 to suppress appa…
jchiang87 31daf28
let GalSim handle the psfs instead of extracting them and adding them…
jchiang87 3fa99a1
tweak class docstring
jchiang87 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| modules: | ||
| - imsim | ||
|
|
||
| eval_variables: | ||
| itract: { type: DeepCoaddData, field: tract } | ||
| ipatch: { type: DeepCoaddData, field: patch } | ||
| sband: { type: DeepCoaddData, field: band } | ||
| incoadds: { type: DeepCoaddData, field: ncoadds } | ||
| fpupil_R_outer: 4.18 | ||
| fpupil_R_inner: 2.55 # M1 inner diameter is 2.558, but we need a bit of slack for off-axis rays | ||
| fpupil_area: | ||
| type: Eval | ||
| str: "np.pi * (pupil_R_outer**2 - pupil_R_inner**2) * 100**2" | ||
|
|
||
| input: | ||
| sky_catalog: | ||
| file_name: default_sky_cat.yaml | ||
| band: $band | ||
|
|
||
| deep_coadds: | ||
| repo: dp2 | ||
| collection: dp2 | ||
| skymap_name: lsst_cells_v2 | ||
|
|
||
| checkpoint: | ||
| dir: checkpoint | ||
| file_name: | ||
| type: FormattedStr | ||
| format : checkpoint_%s-%d-%d.hdf | ||
| items: | ||
| - $band | ||
| - $tract | ||
| - $patch | ||
|
|
||
| gal: | ||
| type: SkyCatObj | ||
|
|
||
| stamp: | ||
| type: RubinDeepCoaddStamp | ||
| max_flux_simple: 100 # When to switch to simple SED. | ||
| world_pos: | ||
| type: SkyCatWorldPos | ||
| band: $band | ||
| pupil_area: $pupil_area | ||
| exptime: 30.0 # Exposure time per visit | ||
|
|
||
| image: | ||
| type: RubinDeepCoaddImage | ||
| random_seed: 42 | ||
| nproc: 1 | ||
| nbatch: 100 | ||
| nsubbatch: 50 | ||
| nbatch_per_checkpoint: 1 | ||
| band: $band | ||
| tract: $tract | ||
| patch: $patch | ||
|
|
||
| wcs: | ||
| type: RubinDeepCoaddWcs | ||
| band: $band | ||
| tract: $tract | ||
| patch: $patch | ||
|
|
||
| bandpass: | ||
| type: RubinDeepCoaddBandpass | ||
| band: $band | ||
|
|
||
| noise: | ||
| type: RubinDeepCoaddGaussianNoise | ||
| band: $band | ||
| tract: $tract | ||
| patch: $patch | ||
|
|
||
| psf: | ||
| type: RubinDeepCoaddPSF | ||
|
|
||
| output: | ||
| type: RubinDeepCoaddOutput | ||
| coadd_num: | ||
| type: Sequence | ||
| nitems: $ncoadds | ||
| first: 0 | ||
| nproc: 1 | ||
| nfiles: 1 | ||
| dir: fits | ||
| file_name: | ||
| type: FormattedStr | ||
| format: deep_coadd_%s-%d-%d.fits | ||
| items: | ||
| - $band | ||
| - $tract | ||
| - $patch | ||
|
|
||
| truth: | ||
| dir: '@output.dir' | ||
| file_name: | ||
| type: FormattedStr | ||
| format: centroid_%s-%d-%d.txt.gz | ||
| items: | ||
| - $band | ||
| - $tract | ||
| - $patch | ||
| columns: | ||
| object_id: "@object_id" | ||
| ra: $sky_pos.ra.deg | ||
| dec: $sky_pos.dec.deg | ||
| x: $image_pos.x | ||
| y: $image_pos.y | ||
| nominal_flux: "@simulated_flux" | ||
| phot_flux: "@phot_flux" | ||
| realized_flux: "@realized_flux" | ||
| stamp_size: "@stamp_size" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import galsim | ||
| from galsim.config import BandpassBuilder, RegisterBandpassType | ||
|
|
||
|
|
||
| __all__ = ['RubinDeepCoaddBandpassBuilder'] | ||
|
|
||
|
|
||
| class RubinDeepCoaddBandpassBuilder(BandpassBuilder): | ||
| """Build the Rubin bandpass to be used with deep coadd sims | ||
| from standard passbands.""" | ||
| def buildBandpass(self, config, base, logger): | ||
| """ | ||
| Parameters: | ||
| config: The configuration dict for the bandpass type. | ||
| base: The base configuration dict. | ||
| logger: If provided, a logger for logging debug statements. | ||
| Returns: | ||
| the constructed Bandpass object. | ||
| """ | ||
| req = { 'band': str } | ||
| params, safe = galsim.config.GetAllParams(config, base, req=req) | ||
| deep_coadds = galsim.config.GetInputObj('deep_coadds', config, base, | ||
| 'RubinDeepCoaddBandpass') | ||
| return deep_coadds.getBandpass(params['band']), safe | ||
|
|
||
|
|
||
| RegisterBandpassType('RubinDeepCoaddBandpass', RubinDeepCoaddBandpassBuilder()) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| from itertools import pairwise | ||
| import numpy as np | ||
| import galsim | ||
| from galsim.config import (GetAllParams, AddNoise, RegisterImageType, | ||
| RegisterNoiseType, GetInputObj, GaussianNoiseBuilder) | ||
| from .lsst_image import LSST_ImageBuilderBase | ||
|
|
||
|
|
||
| __all__ = ['RubinDeepCoaddImageBuilder'] | ||
|
|
||
|
|
||
| class RubinDeepCoaddImageBuilder(LSST_ImageBuilderBase): # noqa: N801 | ||
| def setup(self, config, base, image_num, obj_num, ignore, logger): | ||
| """ | ||
| Do the initialization and setup for a Rubin/LSST deep coadd image. | ||
|
|
||
| Parameters: | ||
| config: The configuration dict for the image field. | ||
| base: The base configuration dict. | ||
| image_num: The current image number. | ||
| obj_num: The first object number in the image. | ||
| ignore: A list of parameters that are allowed to be in config | ||
| that we can ignore here. | ||
| logger: A logger object to log progress. | ||
|
|
||
| Returns: | ||
| xsize, ysize | ||
| """ | ||
| if 'noise' not in base['image']: | ||
| raise RuntimeError( | ||
| "A noise type needs to be specified for rendering the image. " | ||
| "The ``RubinDeepCoaddGaussianNoise`` type models the noise " | ||
| "level in the original coadd image and could be used here." | ||
| ) | ||
|
|
||
| self.nobjects = self.getNObj(config, base, image_num, logger=logger) | ||
| 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) | ||
|
|
||
| req = { 'tract': int, 'patch': int, 'band': str } | ||
| opt = { 'nbatch': int, 'nsubbatch': int, 'nbatch_per_checkpoint': int } | ||
| extra_ignore = ['image_pos', 'world_pos', 'stamp_size', | ||
| 'stamp_xsize', 'stamp_ysize', 'nobjects' ] | ||
| params = GetAllParams(config, base, req=req, opt=opt, | ||
| ignore=ignore+extra_ignore)[0] | ||
|
|
||
| self.tract = params['tract'] | ||
| self.patch = params['patch'] | ||
| self.band = params['band'] | ||
|
|
||
| self.nbatch = params.get('nbatch', 10) | ||
| self.nbatch_per_checkpoint = params.get('nbatch_per_checkpoint', 1) | ||
| self.nsubbatch = params.get('nsubbatch', 50) | ||
| try: | ||
| self.checkpoint = GetInputObj( | ||
| 'checkpoint', config, base, 'RubinCoaddImageBuilder') | ||
| except galsim.config.GalSimConfigError: | ||
| self.checkpoint = None | ||
|
|
||
| deep_coadds = GetInputObj( | ||
| 'deep_coadds', config, base, 'LSSTC_CoaddImageBuilder') | ||
| bbox = deep_coadds.skymap[self.tract][self.patch].getOuterBBox() | ||
| xsize, ysize = bbox.width, bbox.height | ||
|
|
||
| data_id = {'band': self.band, | ||
| 'tract': self.tract, | ||
| 'patch': self.patch} | ||
| self.noise_level = np.std( | ||
| deep_coadds.get(data_id=data_id).noise_realizations[0].array) | ||
|
|
||
| return xsize, ysize | ||
|
|
||
| def addNoise(self, image, config, base, image_num, obj_num, current_var, | ||
| logger): | ||
| """Add image noise | ||
|
|
||
| Parameters: | ||
| image: The image onto which to add the noise. | ||
| config: The configuration dict for the image field. | ||
| base: The base configuration dict. | ||
| image_num: The current image number. | ||
| obj_num: The first object number in the image. | ||
| current_var: The current noise variance in each postage stamps. | ||
| logger: A logger object to log progress. | ||
| """ | ||
| AddNoise(base, image, current_var, logger) | ||
|
|
||
| def buildImage(self, config, base, image_num, obj_num, logger): | ||
|
|
||
| all_stamps = [] | ||
| all_vars = [] | ||
| full_image = self._create_full_image(config, base) | ||
| min_batch_size = 10 | ||
| if self.nobjects//self.nbatch < min_batch_size: | ||
| num_batches = 1 | ||
| else: | ||
| num_batches = self.nbatch | ||
| bounds = np.linspace(0, self.nobjects, num_batches + 1, dtype=int) | ||
| for batch, (start_obj_num, end_obj_num) in enumerate(pairwise(bounds)): | ||
| nobj_batch = end_obj_num - start_obj_num | ||
| stamps, current_vars = galsim.config.BuildStamps( | ||
| nobj_batch, base, logger=logger, obj_num=start_obj_num, | ||
| do_noise=False) | ||
| base['index_key'] = 'image_num' | ||
|
|
||
| for k in range(nobj_batch): | ||
| if stamps[k] is None: | ||
| continue | ||
| bounds = stamps[k].bounds & full_image.bounds | ||
| if not bounds.isDefined(): | ||
| continue | ||
| full_image[bounds] += stamps[k][bounds] | ||
|
|
||
| nz_var = np.nonzero(current_vars)[0] | ||
| all_stamps.extend([stamps[k] for k in nz_var]) | ||
| all_vars.extend([current_vars[k] for k in nz_var]) | ||
|
|
||
| current_var = galsim.config.FlattenNoiseVariance( | ||
| base, full_image, all_stamps, all_vars, logger) | ||
| return full_image, current_var | ||
|
|
||
|
|
||
| class RubinDeepCoaddGaussianNoiseBuilder(GaussianNoiseBuilder): | ||
| """ | ||
| Treat the variance of the coadd noise realization plane | ||
| as Gaussian noise for a specified deep_coadd image. | ||
| """ | ||
|
|
||
| def getNoiseVariance(self, config, base, full=False): | ||
| req = { 'tract': int, 'patch': int, 'band': str } | ||
| params = GetAllParams(config, base, req=req)[0] | ||
| deep_coadds = galsim.config.GetInputObj('deep_coadds', config, base, | ||
| 'RubinDeepCoaddGaussianNoiseBuilder') | ||
| return deep_coadds.getNoiseVar(params['tract'], params['patch'], | ||
| params['band']) | ||
|
|
||
|
|
||
| RegisterImageType('RubinDeepCoaddImage', RubinDeepCoaddImageBuilder()) | ||
| RegisterNoiseType('RubinDeepCoaddGaussianNoise', | ||
| RubinDeepCoaddGaussianNoiseBuilder()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import galsim | ||
| from galsim.config import (OutputBuilder, RegisterOutputType, ParseValue, | ||
| GetAllParams, GetInputObj, BuildImage, | ||
| eval_base_variables) | ||
|
|
||
|
|
||
| __all__ = ['RubinDeepCoaddOutputBuilder'] | ||
|
|
||
|
|
||
| class RubinDeepCoaddOutputBuilder(OutputBuilder): | ||
|
|
||
| _added_eval_base_variables = False | ||
|
|
||
| def setup(self, config, base, file_num, logger): | ||
| coadd_num = ParseValue(config, 'coadd_num', base, int)[0] | ||
| if not self._added_eval_base_variables: | ||
| eval_base_variables.append('coadd_num') | ||
| self._added_eval_base_variables = True | ||
| base['coadd_num'] = coadd_num | ||
| deep_coadds = GetInputObj('deep_coadds', config, base, | ||
| 'RubinDeepCoaddOutputBuilder') | ||
| data_id = deep_coadds.data_ids[coadd_num] | ||
| patch = deep_coadds.skymap[data_id['tract']][data_id['patch']] | ||
| bbox = patch.getOuterBBox() | ||
| base['det_xsize'] = bbox.width | ||
| base['det_ysize'] = bbox.height | ||
|
|
||
| def getNFiles(self, config, base, logger=None): | ||
| if 'nfiles' in config: | ||
| return ParseValue(config, 'nfiles', base, int)[0] | ||
| else: | ||
| deep_coadds = GetInputObj('deep_coadds', config, base, | ||
| 'RubinDeepCoaddOutputBuilder') | ||
| return len(deep_coadds.data_ids) | ||
|
|
||
| def buildImages(self, config, base, file_num, image_num, obj_num, | ||
| ignore, logger): | ||
| ignore += [ 'file_name', 'dir', 'nfiles', 'coadd_num' ] | ||
| params, _ = GetAllParams(config, base, ignore=ignore) | ||
|
|
||
| image = BuildImage(base, image_num, obj_num, logger=logger) | ||
| image.header = galsim.FitsHeader() | ||
| image.wcs.header = {} | ||
| return [ image ] | ||
|
|
||
|
|
||
| RegisterOutputType('RubinDeepCoaddOutput', RubinDeepCoaddOutputBuilder()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import galsim | ||
| from galsim.config import GetInputObj, RegisterObjectType | ||
|
|
||
|
|
||
| __all__ = ["BuildRubinDeepCoaddPSF"] | ||
|
|
||
|
|
||
| def BuildRubinDeepCoaddPSF(config, base, ignore, gsparams, logger): | ||
| """ | ||
| Build PSFs from Rubin deep_coadds. The deep_coadd image will be | ||
| retrieved from the data repository using the butler for the | ||
| tract-patch combination corresponding to the object's sky position. | ||
|
|
||
| Assuming the input.deep_coadd object is defined, to use this | ||
| PSF, add the following to the config yaml: | ||
|
|
||
| input.atm_psf: "" # disable the atmospheric PSF | ||
| psf: | ||
| type: RubinDeepCoaddPSF | ||
| """ | ||
| deep_coadds = GetInputObj('deep_coadds', config, base, 'RubinDeepCoaddPSF') | ||
| coadd_num = base['coadd_num'] | ||
| assert (coadd_num >= 0 and coadd_num < len(deep_coadds.data_ids)) | ||
| data_id = deep_coadds.data_ids[coadd_num] | ||
| image_pos = base['image_pos'] | ||
| celestial_coord = base['wcs'].toWorld(image_pos) | ||
| band = data_id['band'] | ||
| safe = False | ||
| return deep_coadds.getPSF(celestial_coord, band), safe | ||
|
|
||
|
|
||
| RegisterObjectType('RubinDeepCoaddPSF', BuildRubinDeepCoaddPSF, | ||
| input_type='deep_coadds') |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a special deep_coadds version? This looks like it's just the normal LSST bandpass we normally use. Am I missing something here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This retrieves the "standard passband" from the butler, which is a calibration product. See the butler code here. This was mentioned in a slack thread. The one we've been using for the visit level sims can also have per-detector throughputs included, which we wouldn't use for the coadds.