286 self.
rng = np.random.RandomState(self.config.rngSeed)
290 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
291 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
292 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
293 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
294 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
295 [1e-2, 0.0, 0.0, 2.2e-2, 0.0, 0.0, 0.0, 0.0],
296 [1e-2, 5e-3, 5e-4, 3e-3, 4e-2, 5e-3, 5e-3, 0.0]])
297 if getDebugFrame(self.
_display,
"mockCrosstalkCoeffs"):
298 self.
crosstalkCoeffs = np.array([[0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
299 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
300 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
301 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
302 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
303 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
304 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
305 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
308 [4., 16., 26., 16., 4.],
309 [7., 26., 41., 26., 7.],
310 [4., 16., 26., 16., 4.],
311 [1., 4., 7., 4., 1.]]) / 273.0
432 """Generate a simulated ISR image.
436 exposure : `lsst.afw.image.Exposure` or `dict`
437 Simulated ISR image data.
441 This method currently constructs a "raw" data image by:
443 * Generating a simulated sky with noise
444 * Adding a single Gaussian "star"
445 * Adding the fringe signal
446 * Multiplying the frame by the simulated flat
447 * Adding dark current (and noise)
448 * Adding a bias offset (and noise)
449 * Adding an overscan gradient parallel to the pixel y-axis
450 * Simulating crosstalk by adding a scaled version of each
451 amplifier to each other amplifier.
453 The exposure with image data constructed this way is in one of
456 * A single image, with overscan and prescan regions retained
457 * A single image, with overscan and prescan regions trimmed
458 * A `dict`, containing the amplifer data indexed by the
461 The nonlinearity, CTE, and brighter fatter are currently not
464 Note that this method generates an image in the reverse
465 direction as the ISR processing, as the output image here has
466 had a series of instrument effects added to an idealized
471 for idx, amp
in enumerate(exposure.getDetector()):
473 if self.config.isTrimmed
is True:
476 bbox = amp.getRawDataBBox()
478 ampData = exposure.image[bbox]
480 if self.config.doAddSky
is True:
481 self.
amplifierAddNoise(ampData, self.config.skyLevel, np.sqrt(self.config.skyLevel))
483 if self.config.doAddSource
is True:
484 for sourceAmp, sourceFlux, sourceX, sourceY
in zip(self.config.sourceAmp,
485 self.config.sourceFlux,
487 self.config.sourceY):
491 if self.config.doAddFringe
is True:
493 x0=np.array(self.config.fringeX0),
494 y0=np.array(self.config.fringeY0))
496 if self.config.doAddFlat
is True:
497 if ampData.getArray().sum() == 0.0:
499 u0 = exposure.getDimensions().getX()
500 v0 = exposure.getDimensions().getY()
503 if self.config.doAddDark
is True:
505 self.config.darkRate * self.config.darkTime / self.config.gain,
506 np.sqrt(self.config.darkRate
507 * self.config.darkTime / self.config.gain))
509 if self.config.doAddCrosstalk
is True:
516 ctCalib.subtractCrosstalk(
519 doSubtrahendMasking=
True,
520 minPixelToMask=np.inf,
525 for amp
in exposure.getDetector():
527 if self.config.isTrimmed
is True:
530 bbox = amp.getRawDataBBox()
532 ampData = exposure.image[bbox]
534 if self.config.doAddBias
is True:
536 self.config.readNoise / self.config.gain)
538 if self.config.doAddOverscan
is True:
539 oscanBBox = amp.getRawHorizontalOverscanBBox()
540 oscanData = exposure.image[oscanBBox]
542 self.config.readNoise / self.config.gain)
545 1.0 * self.config.overscanScale)
547 1.0 * self.config.overscanScale)
549 if self.config.doGenerateAmpDict
is True:
551 for amp
in exposure.getDetector():
552 expDict[amp.getName()] = exposure
586 """Construct a test exposure.
588 The test exposure has a simple WCS set, as well as a list of
589 unlikely header keywords that can be removed during ISR
590 processing to exercise that code.
594 isTrimmed : `bool` or `None`, optional
595 Override the configuration isTrimmed?
599 exposure : `lsst.afw.exposure.Exposure`
600 Construct exposure containing masked image of the
603 if isTrimmed
is None:
604 _isTrimmed = self.config.isTrimmed
606 _isTrimmed = isTrimmed
608 camera = self.
getCamera(isForAssembly=self.config.isLsstLike)
609 detector = camera[self.config.detectorIndex]
610 image = afwUtils.makeImageFromCcd(
612 isTrimmed=_isTrimmed,
616 imageFactory=afwImage.ImageF,
619 var = afwImage.ImageF(image.getDimensions())
625 exposure.setDetector(detector)
626 exposure.setWcs(self.
getWcs())
628 visitInfo =
afwImage.VisitInfo(exposureTime=self.config.expTime, darkTime=self.config.darkTime)
629 exposure.getInfo().setVisitInfo(visitInfo)
631 exposure.getInfo().setId(12345)
633 metadata = exposure.getMetadata()
634 metadata.add(
"SHEEP", 7.3,
"number of sheep on farm")
635 metadata.add(
"MONKEYS", 155,
"monkeys per tree")
636 metadata.add(
"VAMPIRES", 4,
"How scary are vampires.")
639 now = datetime.now(timezone.utc)
640 currentMjd = astropy.time.Time(now, format=
'datetime', scale=
'utc').mjd
641 metadata.add(
"MJD", currentMjd,
"Modified Julian Date that the file was written")
643 ccd = exposure.getDetector()
644 newCcd = ccd.rebuild()
647 'LL': ReadoutCorner.LL,
648 'LR': ReadoutCorner.LR,
649 'UR': ReadoutCorner.UR,
650 'UL': ReadoutCorner.UL,
653 newAmp = amp.rebuild()
654 newAmp.setLinearityCoeffs((0., 1., 0., 0.))
655 newAmp.setLinearityType(
"Polynomial")
656 newAmp.setGain(self.config.gain)
657 newAmp.setSuspectLevel(25000.0)
658 newAmp.setSaturation(32000.0)
659 readoutCorner = amp.getReadoutCorner().name
662 imageBBox = amp.getRawDataBBox()
663 rawBbox = amp.getRawBBox()
664 parallelOscanBBox = amp.getRawParallelOverscanBBox()
665 serialOscanBBox = amp.getRawSerialOverscanBBox()
666 prescanBBox = amp.getRawPrescanBBox()
668 if self.config.isLsstLike:
670 xoffset, yoffset = amp.getRawXYOffset()
672 flipx = bool(amp.getRawFlipX())
673 flipy = bool(amp.getRawFlipY())
675 xExt = rawBbox.getDimensions().getX()
677 imageBBox.flipLR(xExt)
678 parallelOscanBBox.flipLR(xExt)
679 serialOscanBBox.flipLR(xExt)
680 prescanBBox.flipLR(xExt)
682 yExt = rawBbox.getDimensions().getY()
684 imageBBox.flipTB(yExt)
685 parallelOscanBBox.flipTB(yExt)
686 serialOscanBBox.flipTB(yExt)
687 prescanBBox.flipTB(yExt)
688 if not flipx
and not flipy:
690 elif flipx
and not flipy:
692 elif flipx
and flipy:
694 elif not flipx
and flipy:
696 rawBbox.shift(offext)
697 imageBBox.shift(offext)
698 parallelOscanBBox.shift(offext)
699 serialOscanBBox.shift(offext)
700 prescanBBox.shift(offext)
701 newAmp.setReadoutCorner(readoutMap[readoutCorner])
702 newAmp.setRawBBox(rawBbox)
703 newAmp.setRawDataBBox(imageBBox)
704 newAmp.setRawParallelOverscanBBox(parallelOscanBBox)
705 newAmp.setRawSerialOverscanBBox(serialOscanBBox)
706 newAmp.setRawPrescanBBox(prescanBBox)
707 newAmp.setRawFlipX(
False)
708 newAmp.setRawFlipY(
False)
710 newAmp.setRawXYOffset(no_offset)
712 newCcd.append(newAmp)
714 exposure.setDetector(newCcd.finish())
716 exposure.image.array[:] = np.zeros(exposure.getImage().getDimensions()).transpose()
717 exposure.mask.array[:] = np.zeros(exposure.getMask().getDimensions()).transpose()
718 exposure.variance.array[:] = np.zeros(exposure.getVariance().getDimensions()).transpose()