296 self.
rng = np.random.RandomState(self.config.rngSeed)
300 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
301 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
302 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
303 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
304 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
305 [1e-2, 0.0, 0.0, 2.2e-2, 0.0, 0.0, 0.0, 0.0],
306 [1e-2, 5e-3, 5e-4, 3e-3, 4e-2, 5e-3, 5e-3, 0.0]])
307 if getDebugFrame(self.
_display,
"mockCrosstalkCoeffs"):
308 self.
crosstalkCoeffs = np.array([[0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
309 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
310 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
311 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
312 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
313 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
314 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
315 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
318 [4., 16., 26., 16., 4.],
319 [7., 26., 41., 26., 7.],
320 [4., 16., 26., 16., 4.],
321 [1., 4., 7., 4., 1.]]) / 273.0
323 self.
aN = np.array([[1., 0.5, 0.0125, 0., 0.],
324 [0.5, 0.010, 0., 0., 0.],
325 [0.0125, 0., 0., 0., 0.],
326 [0, 0., 0., 0., 0.]]) * -1e-7
327 self.
aE = np.array([[1., 0.5, 0.0125, 0., 0.],
328 [0.5, 0.010, 0., 0., 0.],
329 [0.0125, 0., 0., 0., 0.],
330 [0, 0., 0., 0., 0.]]) * -1e-7
470 """Generate a simulated ISR image.
474 exposure : `lsst.afw.image.Exposure` or `dict`
475 Simulated ISR image data.
479 This method currently constructs a "raw" data image by:
481 * Generating a simulated sky with noise
482 * Adding a single Gaussian "star"
483 * Adding the fringe signal
484 * Multiplying the frame by the simulated flat
485 * Adding dark current (and noise)
486 * Adding a bias offset (and noise)
487 * Adding an overscan gradient parallel to the pixel y-axis
488 * Simulating crosstalk by adding a scaled version of each
489 amplifier to each other amplifier.
491 The exposure with image data constructed this way is in one of
494 * A single image, with overscan and prescan regions retained
495 * A single image, with overscan and prescan regions trimmed
496 * A `dict`, containing the amplifer data indexed by the
499 The nonlinearity, CTE, and brighter fatter are currently not
502 Note that this method generates an image in the reverse
503 direction as the ISR processing, as the output image here has
504 had a series of instrument effects added to an idealized
509 for idx, amp
in enumerate(exposure.getDetector()):
511 if self.config.isTrimmed
is True:
514 bbox = amp.getRawDataBBox()
516 ampData = exposure.image[bbox]
518 if self.config.doAddSky
is True:
519 self.
amplifierAddNoise(ampData, self.config.skyLevel, np.sqrt(self.config.skyLevel))
521 if self.config.doAddSource
is True:
522 for sourceAmp, sourceFlux, sourceX, sourceY
in zip(self.config.sourceAmp,
523 self.config.sourceFlux,
525 self.config.sourceY):
529 if self.config.doAddFringe
is True:
531 x0=np.array(self.config.fringeX0),
532 y0=np.array(self.config.fringeY0))
534 if self.config.doAddFlat
is True:
535 if ampData.getArray().sum() == 0.0:
537 u0 = exposure.getDimensions().getX()
538 v0 = exposure.getDimensions().getY()
541 if self.config.doAddDark
is True:
543 self.config.darkRate * self.config.darkTime / self.config.gain,
544 np.sqrt(self.config.darkRate
545 * self.config.darkTime / self.config.gain))
547 if self.config.doAddCrosstalk
is True:
554 ctCalib.subtractCrosstalk(
557 doSubtrahendMasking=
True,
558 minPixelToMask=np.inf,
563 for amp
in exposure.getDetector():
565 if self.config.isTrimmed
is True:
568 bbox = amp.getRawDataBBox()
570 ampData = exposure.image[bbox]
572 if self.config.doAddBias
is True:
574 self.config.readNoise / self.config.gain)
576 if self.config.doAddOverscan
is True:
577 oscanBBox = amp.getRawHorizontalOverscanBBox()
578 oscanData = exposure.image[oscanBBox]
580 self.config.readNoise / self.config.gain)
583 1.0 * self.config.overscanScale)
585 1.0 * self.config.overscanScale)
587 if self.config.doGenerateAmpDict
is True:
589 for amp
in exposure.getDetector():
590 expDict[amp.getName()] = exposure
624 """Construct a test exposure.
626 The test exposure has a simple WCS set, as well as a list of
627 unlikely header keywords that can be removed during ISR
628 processing to exercise that code.
632 isTrimmed : `bool` or `None`, optional
633 Override the configuration isTrimmed?
637 exposure : `lsst.afw.exposure.Exposure`
638 Construct exposure containing masked image of the
641 if isTrimmed
is None:
642 _isTrimmed = self.config.isTrimmed
644 _isTrimmed = isTrimmed
646 camera = self.
getCamera(isForAssembly=self.config.isLsstLike)
647 detector = camera[self.config.detectorIndex]
648 image = afwUtils.makeImageFromCcd(
650 isTrimmed=_isTrimmed,
654 imageFactory=afwImage.ImageF,
657 var = afwImage.ImageF(image.getDimensions())
658 mask = afwImage.Mask(image.getDimensions())
661 maskedImage = afwImage.makeMaskedImage(image, mask, var)
662 exposure = afwImage.makeExposure(maskedImage)
663 exposure.setDetector(detector)
664 exposure.setWcs(self.
getWcs())
666 visitInfo = afwImage.VisitInfo(exposureTime=self.config.expTime, darkTime=self.config.darkTime)
667 exposure.getInfo().setVisitInfo(visitInfo)
669 exposure.getInfo().setId(12345)
671 metadata = exposure.getMetadata()
672 metadata.add(
"SHEEP", 7.3,
"number of sheep on farm")
673 metadata.add(
"MONKEYS", 155,
"monkeys per tree")
674 metadata.add(
"VAMPIRES", 4,
"How scary are vampires.")
675 metadata.add(
"FILTER",
"r_57",
"My favorite color.")
678 now = datetime.now(timezone.utc)
679 currentMjd = astropy.time.Time(now, format=
'datetime', scale=
'utc').mjd
680 metadata.add(
"MJD", currentMjd,
"Modified Julian Date that the file was written")
682 ccd = exposure.getDetector()
683 newCcd = ccd.rebuild()
686 'LL': ReadoutCorner.LL,
687 'LR': ReadoutCorner.LR,
688 'UR': ReadoutCorner.UR,
689 'UL': ReadoutCorner.UL,
692 newAmp = amp.rebuild()
693 newAmp.setLinearityCoeffs((0., 1., 0., 0.))
694 newAmp.setLinearityType(
"Polynomial")
695 newAmp.setGain(self.config.gain)
696 newAmp.setSuspectLevel(25000.0)
697 newAmp.setSaturation(32000.0)
698 readoutCorner = amp.getReadoutCorner().name
701 imageBBox = amp.getRawDataBBox()
702 rawBbox = amp.getRawBBox()
703 parallelOscanBBox = amp.getRawParallelOverscanBBox()
704 serialOscanBBox = amp.getRawSerialOverscanBBox()
705 prescanBBox = amp.getRawPrescanBBox()
707 if self.config.isLsstLike:
709 xoffset, yoffset = amp.getRawXYOffset()
711 flipx = bool(amp.getRawFlipX())
712 flipy = bool(amp.getRawFlipY())
714 xExt = rawBbox.getDimensions().getX()
716 imageBBox.flipLR(xExt)
717 parallelOscanBBox.flipLR(xExt)
718 serialOscanBBox.flipLR(xExt)
719 prescanBBox.flipLR(xExt)
721 yExt = rawBbox.getDimensions().getY()
723 imageBBox.flipTB(yExt)
724 parallelOscanBBox.flipTB(yExt)
725 serialOscanBBox.flipTB(yExt)
726 prescanBBox.flipTB(yExt)
727 if not flipx
and not flipy:
729 elif flipx
and not flipy:
731 elif flipx
and flipy:
733 elif not flipx
and flipy:
735 rawBbox.shift(offext)
736 imageBBox.shift(offext)
737 parallelOscanBBox.shift(offext)
738 serialOscanBBox.shift(offext)
739 prescanBBox.shift(offext)
740 newAmp.setReadoutCorner(readoutMap[readoutCorner])
741 newAmp.setRawBBox(rawBbox)
742 newAmp.setRawDataBBox(imageBBox)
743 newAmp.setRawParallelOverscanBBox(parallelOscanBBox)
744 newAmp.setRawSerialOverscanBBox(serialOscanBBox)
745 newAmp.setRawPrescanBBox(prescanBBox)
746 newAmp.setRawFlipX(
False)
747 newAmp.setRawFlipY(
False)
749 newAmp.setRawXYOffset(no_offset)
751 newCcd.append(newAmp)
753 exposure.setDetector(newCcd.finish())
755 exposure.image.array[:] = np.zeros(exposure.getImage().getDimensions()).transpose()
756 exposure.mask.array[:] = np.zeros(exposure.getMask().getDimensions()).transpose()
757 exposure.variance.array[:] = np.zeros(exposure.getVariance().getDimensions()).transpose()