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())
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.")
677 now = datetime.now(timezone.utc)
678 currentMjd = astropy.time.Time(now, format=
'datetime', scale=
'utc').mjd
679 metadata.add(
"MJD", currentMjd,
"Modified Julian Date that the file was written")
681 ccd = exposure.getDetector()
682 newCcd = ccd.rebuild()
685 'LL': ReadoutCorner.LL,
686 'LR': ReadoutCorner.LR,
687 'UR': ReadoutCorner.UR,
688 'UL': ReadoutCorner.UL,
691 newAmp = amp.rebuild()
692 newAmp.setLinearityCoeffs((0., 1., 0., 0.))
693 newAmp.setLinearityType(
"Polynomial")
694 newAmp.setGain(self.config.gain)
695 newAmp.setSuspectLevel(25000.0)
696 newAmp.setSaturation(32000.0)
697 readoutCorner = amp.getReadoutCorner().name
700 imageBBox = amp.getRawDataBBox()
701 rawBbox = amp.getRawBBox()
702 parallelOscanBBox = amp.getRawParallelOverscanBBox()
703 serialOscanBBox = amp.getRawSerialOverscanBBox()
704 prescanBBox = amp.getRawPrescanBBox()
706 if self.config.isLsstLike:
708 xoffset, yoffset = amp.getRawXYOffset()
710 flipx = bool(amp.getRawFlipX())
711 flipy = bool(amp.getRawFlipY())
713 xExt = rawBbox.getDimensions().getX()
715 imageBBox.flipLR(xExt)
716 parallelOscanBBox.flipLR(xExt)
717 serialOscanBBox.flipLR(xExt)
718 prescanBBox.flipLR(xExt)
720 yExt = rawBbox.getDimensions().getY()
722 imageBBox.flipTB(yExt)
723 parallelOscanBBox.flipTB(yExt)
724 serialOscanBBox.flipTB(yExt)
725 prescanBBox.flipTB(yExt)
726 if not flipx
and not flipy:
728 elif flipx
and not flipy:
730 elif flipx
and flipy:
732 elif not flipx
and flipy:
734 rawBbox.shift(offext)
735 imageBBox.shift(offext)
736 parallelOscanBBox.shift(offext)
737 serialOscanBBox.shift(offext)
738 prescanBBox.shift(offext)
739 newAmp.setReadoutCorner(readoutMap[readoutCorner])
740 newAmp.setRawBBox(rawBbox)
741 newAmp.setRawDataBBox(imageBBox)
742 newAmp.setRawParallelOverscanBBox(parallelOscanBBox)
743 newAmp.setRawSerialOverscanBBox(serialOscanBBox)
744 newAmp.setRawPrescanBBox(prescanBBox)
745 newAmp.setRawFlipX(
False)
746 newAmp.setRawFlipY(
False)
748 newAmp.setRawXYOffset(no_offset)
750 newCcd.append(newAmp)
752 exposure.setDetector(newCcd.finish())
754 exposure.image.array[:] = np.zeros(exposure.getImage().getDimensions()).transpose()
755 exposure.mask.array[:] = np.zeros(exposure.getMask().getDimensions()).transpose()
756 exposure.variance.array[:] = np.zeros(exposure.getVariance().getDimensions()).transpose()