33 import lsst.pex.config
as pexConfig
35 from .crosstalk
import X_FLIP, Y_FLIP
37 __all__ = [
"IsrMockConfig",
"IsrMock",
"RawMock",
"TrimmedRawMock",
"RawDictMock",
38 "CalibratedRawMock",
"MasterMock",
39 "BiasMock",
"DarkMock",
"FlatMock",
"FringeMock",
"UntrimmedFringeMock",
40 "BfKernelMock",
"DefectMock",
"CrosstalkCoeffMock",
"TransmissionMock",
45 """Configuration parameters for isrMock.
47 These parameters produce generic fixed position signals from
48 various sources, and combine them in a way that matches how those
49 signals are combined to create real data. The camera used is the
50 test camera defined by the afwUtils code.
53 isLsstLike = pexConfig.Field(
56 doc=
"If True, products have one raw image per amplifier, otherwise, one raw image per detector.",
58 plateScale = pexConfig.Field(
61 doc=
"Plate scale used in constructing mock camera.",
63 radialDistortion = pexConfig.Field(
66 doc=
"Radial distortion term used in constructing mock camera.",
68 isTrimmed = pexConfig.Field(
71 doc=
"If True, amplifiers have been trimmed and mosaicked to remove regions outside the data BBox.",
73 detectorIndex = pexConfig.Field(
76 doc=
"Index for the detector to use. The default value uses a standard 2x4 array of amps.",
78 rngSeed = pexConfig.Field(
81 doc=
"Seed for random number generator used to add noise.",
84 gain = pexConfig.Field(
87 doc=
"Gain for simulated data in e^-/DN.",
89 readNoise = pexConfig.Field(
92 doc=
"Read noise of the detector in e-.",
94 expTime = pexConfig.Field(
97 doc=
"Exposure time for simulated data.",
101 skyLevel = pexConfig.Field(
104 doc=
"Background contribution to be generated from 'the sky' in DN.",
106 sourceFlux = pexConfig.ListField(
109 doc=
"Peak flux level (in DN) of simulated 'astronomical sources'.",
111 sourceAmp = pexConfig.ListField(
114 doc=
"Amplifier to place simulated 'astronomical sources'.",
116 sourceX = pexConfig.ListField(
119 doc=
"Peak position (in amplifier coordinates) of simulated 'astronomical sources'.",
121 sourceY = pexConfig.ListField(
124 doc=
"Peak position (in amplifier coordinates) of simulated 'astronomical sources'.",
126 overscanScale = pexConfig.Field(
129 doc=
"Amplitude (in DN) of the ramp function to add to overscan data.",
131 biasLevel = pexConfig.Field(
134 doc=
"Background contribution to be generated from the bias offset in DN.",
136 darkRate = pexConfig.Field(
139 doc=
"Background level contribution (in e-/s) to be generated from dark current.",
141 darkTime = pexConfig.Field(
144 doc=
"Exposure time for the dark current contribution.",
146 flatDrop = pexConfig.Field(
149 doc=
"Fractional flux drop due to flat from center to edge of detector along x-axis.",
151 fringeScale = pexConfig.ListField(
154 doc=
"Peak fluxes for the components of the fringe ripple in DN.",
156 fringeX0 = pexConfig.ListField(
159 doc=
"Center position for the fringe ripples.",
161 fringeY0 = pexConfig.ListField(
164 doc=
"Center position for the fringe ripples.",
168 doAddSky = pexConfig.Field(
171 doc=
"Apply 'sky' signal to output image.",
173 doAddSource = pexConfig.Field(
176 doc=
"Add simulated source to output image.",
178 doAddCrosstalk = pexConfig.Field(
181 doc=
"Apply simulated crosstalk to output image. This cannot be corrected by ISR, "
182 "as detector.hasCrosstalk()==False.",
184 doAddOverscan = pexConfig.Field(
187 doc=
"If untrimmed, add overscan ramp to overscan and data regions.",
189 doAddBias = pexConfig.Field(
192 doc=
"Add bias signal to data.",
194 doAddDark = pexConfig.Field(
197 doc=
"Add dark signal to data.",
199 doAddFlat = pexConfig.Field(
202 doc=
"Add flat signal to data.",
204 doAddFringe = pexConfig.Field(
207 doc=
"Add fringe signal to data.",
211 doTransmissionCurve = pexConfig.Field(
214 doc=
"Return a simulated transmission curve.",
216 doDefects = pexConfig.Field(
219 doc=
"Return a simulated defect list.",
221 doBrighterFatter = pexConfig.Field(
224 doc=
"Return a simulated brighter-fatter kernel.",
226 doCrosstalkCoeffs = pexConfig.Field(
229 doc=
"Return the matrix of crosstalk coefficients.",
231 doDataRef = pexConfig.Field(
234 doc=
"Return a simulated gen2 butler dataRef.",
236 doGenerateImage = pexConfig.Field(
239 doc=
"Return the generated output image if True.",
241 doGenerateData = pexConfig.Field(
244 doc=
"Return a non-image data structure if True.",
246 doGenerateAmpDict = pexConfig.Field(
249 doc=
"Return a dict of exposure amplifiers instead of an afwImage.Exposure.",
254 """Class to generate consistent mock images for ISR testing.
256 ISR testing currently relies on one-off fake images that do not
257 accurately mimic the full set of detector effects. This class
258 uses the test camera/detector/amplifier structure defined in
259 `lsst.afw.cameraGeom.testUtils` to avoid making the test data
260 dependent on any of the actual obs package formats.
262 ConfigClass = IsrMockConfig
263 _DefaultName =
"isrMock"
267 self.
rng = np.random.RandomState(self.config.rngSeed)
269 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
270 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
271 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
272 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
273 [1e-2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
274 [1e-2, 0.0, 0.0, 2.2e-2, 0.0, 0.0, 0.0, 0.0],
275 [1e-2, 5e-3, 5e-4, 3e-3, 4e-2, 5e-3, 5e-3, 0.0]])
278 [4., 16., 26., 16., 4.],
279 [7., 26., 41., 26., 7.],
280 [4., 16., 26., 16., 4.],
281 [1., 4., 7., 4., 1.]]) / 273.0
284 """Generate a mock ISR product, and return it.
288 image : `lsst.afw.image.Exposure`
289 Simulated ISR image with signals added.
291 Simulated ISR data products.
293 Returned if no valid configuration was found.
298 Raised if both doGenerateImage and doGenerateData are specified.
300 if self.config.doGenerateImage
and self.config.doGenerateData:
301 raise RuntimeError(
"Only one of doGenerateImage and doGenerateData may be specified.")
302 elif self.config.doGenerateImage:
304 elif self.config.doGenerateData:
310 """Generate simulated ISR data.
312 Currently, only the class defined crosstalk coefficient
313 matrix, brighter-fatter kernel, a constant unity transmission
314 curve, or a simple single-entry defect list can be generated.
319 Simulated ISR data product.
321 if sum(map(bool, [self.config.doBrighterFatter,
322 self.config.doDefects,
323 self.config.doTransmissionCurve,
324 self.config.doCrosstalkCoeffs])) != 1:
325 raise RuntimeError(
"Only one data product can be generated at a time.")
326 elif self.config.doBrighterFatter
is True:
328 elif self.config.doDefects
is True:
330 elif self.config.doTransmissionCurve
is True:
332 elif self.config.doCrosstalkCoeffs
is True:
338 """Generate a simple Gaussian brighter-fatter kernel.
342 kernel : `numpy.ndarray`
343 Simulated brighter-fatter kernel.
348 """Generate a simple single-entry defect list.
352 defectList : `lsst.meas.algorithms.Defects`
353 Simulated defect list
359 """Generate the simulated crosstalk coefficients.
363 coeffs : `numpy.ndarray`
364 Simulated crosstalk coefficients.
370 """Generate a simulated flat transmission curve.
374 transmission : `lsst.afw.image.TransmissionCurve`
375 Simulated transmission curve.
378 return afwImage.TransmissionCurve.makeIdentity()
381 """Generate a simulated ISR image.
385 exposure : `lsst.afw.image.Exposure` or `dict`
386 Simulated ISR image data.
390 This method currently constructs a "raw" data image by:
391 * Generating a simulated sky with noise
392 * Adding a single Gaussian "star"
393 * Adding the fringe signal
394 * Multiplying the frame by the simulated flat
395 * Adding dark current (and noise)
396 * Adding a bias offset (and noise)
397 * Adding an overscan gradient parallel to the pixel y-axis
398 * Simulating crosstalk by adding a scaled version of each
399 amplifier to each other amplifier.
401 The exposure with image data constructed this way is in one of
403 * A single image, with overscan and prescan regions retained
404 * A single image, with overscan and prescan regions trimmed
405 * A `dict`, containing the amplifer data indexed by the
408 The nonlinearity, CTE, and brighter fatter are currently not
411 Note that this method generates an image in the reverse
412 direction as the ISR processing, as the output image here has
413 had a series of instrument effects added to an idealized
418 for idx, amp
in enumerate(exposure.getDetector()):
420 if self.config.isTrimmed
is True:
423 bbox = amp.getRawDataBBox()
425 ampData = exposure.image[bbox]
427 if self.config.doAddSky
is True:
428 self.
amplifierAddNoise(ampData, self.config.skyLevel, np.sqrt(self.config.skyLevel))
430 if self.config.doAddSource
is True:
431 for sourceAmp, sourceFlux, sourceX, sourceY
in zip(self.config.sourceAmp,
432 self.config.sourceFlux,
434 self.config.sourceY):
438 if self.config.doAddFringe
is True:
440 x0=np.array(self.config.fringeX0),
441 y0=np.array(self.config.fringeY0))
443 if self.config.doAddFlat
is True:
444 if ampData.getArray().sum() == 0.0:
446 u0 = exposure.getDimensions().getX()
447 v0 = exposure.getDimensions().getY()
450 if self.config.doAddDark
is True:
452 self.config.darkRate * self.config.darkTime / self.config.gain,
453 np.sqrt(self.config.darkRate *
454 self.config.darkTime / self.config.gain))
456 if self.config.doAddCrosstalk
is True:
458 for idxS, ampS
in enumerate(exposure.getDetector()):
459 for idxT, ampT
in enumerate(exposure.getDetector()):
460 ampDataS = exposure.image[ampS.getBBox()
if self.config.isTrimmed
461 else ampS.getRawDataBBox()]
462 ampDataT = exposure.image[ampT.getBBox()
if self.config.isTrimmed
463 else ampT.getRawDataBBox()]
465 (X_FLIP[ampS.getReadoutCorner()] ^
466 X_FLIP[ampT.getReadoutCorner()]),
467 (Y_FLIP[ampS.getReadoutCorner()] ^
468 Y_FLIP[ampT.getReadoutCorner()]))
471 for amp
in exposure.getDetector():
473 if self.config.isTrimmed
is True:
476 bbox = amp.getRawDataBBox()
478 ampData = exposure.image[bbox]
480 if self.config.doAddBias
is True:
482 self.config.readNoise / self.config.gain)
484 if self.config.doAddOverscan
is True:
485 oscanBBox = amp.getRawHorizontalOverscanBBox()
486 oscanData = exposure.image[oscanBBox]
488 self.config.readNoise / self.config.gain)
491 1.0 * self.config.overscanScale)
493 1.0 * self.config.overscanScale)
495 if self.config.doGenerateAmpDict
is True:
497 for amp
in exposure.getDetector():
498 expDict[amp.getName()] = exposure
505 """Construct a test camera object.
509 camera : `lsst.afw.cameraGeom.camera`
512 cameraWrapper = afwTestUtils.CameraWrapper(
513 plateScale=self.config.plateScale,
514 radialDistortion=self.config.radialDistortion,
515 isLsstLike=self.config.isLsstLike,
517 camera = cameraWrapper.camera
521 """Construct a test exposure.
523 The test exposure has a simple WCS set, as well as a list of
524 unlikely header keywords that can be removed during ISR
525 processing to exercise that code.
529 exposure : `lsst.afw.exposure.Exposure`
530 Construct exposure containing masked image of the
534 detector = camera[self.config.detectorIndex]
535 image = afwUtils.makeImageFromCcd(detector,
536 isTrimmed=self.config.isTrimmed,
540 imageFactory=afwImage.ImageF)
542 var = afwImage.ImageF(image.getDimensions())
548 exposure.setDetector(detector)
549 exposure.setWcs(self.
getWcs())
551 visitInfo =
afwImage.VisitInfo(exposureTime=self.config.expTime, darkTime=self.config.darkTime)
552 exposure.getInfo().setVisitInfo(visitInfo)
554 metadata = exposure.getMetadata()
555 metadata.add(
"SHEEP", 7.3,
"number of sheep on farm")
556 metadata.add(
"MONKEYS", 155,
"monkeys per tree")
557 metadata.add(
"VAMPIRES", 4,
"How scary are vampires.")
559 ccd = exposure.getDetector()
560 newCcd = ccd.rebuild()
563 newAmp = amp.rebuild()
564 newAmp.setLinearityCoeffs((0., 1., 0., 0.))
565 newAmp.setLinearityType(
"Polynomial")
566 newAmp.setGain(self.config.gain)
567 newAmp.setSuspectLevel(25000.0)
568 newAmp.setSaturation(32000.0)
569 newCcd.append(newAmp)
570 exposure.setDetector(newCcd.finish())
572 exposure.image.array[:] = np.zeros(exposure.getImage().getDimensions()).transpose()
573 exposure.mask.array[:] = np.zeros(exposure.getMask().getDimensions()).transpose()
574 exposure.variance.array[:] = np.zeros(exposure.getVariance().getDimensions()).transpose()
579 """Construct a dummy WCS object.
581 Taken from the deprecated ip_isr/examples/exampleUtils.py.
583 This is not guaranteed, given the distortion and pixel scale
584 listed in the afwTestUtils camera definition.
588 wcs : `lsst.afw.geom.SkyWcs`
596 """Convert between a local amplifier coordinate and the full
601 ampData : `lsst.afw.image.ImageF`
602 Amplifier image to use for conversions.
604 X-coordinate of the point to transform.
606 Y-coordinate of the point to transform.
611 Transformed x-coordinate.
613 Transformed y-coordinate.
617 The output is transposed intentionally here, to match the
618 internal transpose between numpy and afw.image coordinates.
620 u = x + ampData.getBBox().getBeginX()
621 v = y + ampData.getBBox().getBeginY()
627 """Add Gaussian noise to an amplifier's image data.
629 This method operates in the amplifier coordinate frame.
633 ampData : `lsst.afw.image.ImageF`
634 Amplifier image to operate on.
636 Mean value of the Gaussian noise.
638 Sigma of the Gaussian noise.
640 ampArr = ampData.array
641 ampArr[:] = ampArr[:] + self.
rng.normal(mean, sigma,
642 size=ampData.getDimensions()).transpose()
645 """Add a y-axis linear gradient to an amplifier's image data.
647 This method operates in the amplifier coordinate frame.
651 ampData : `lsst.afw.image.ImageF`
652 Amplifier image to operate on.
654 Start value of the gradient (at y=0).
656 End value of the gradient (at y=ymax).
658 nPixY = ampData.getDimensions().getY()
659 ampArr = ampData.array
660 ampArr[:] = ampArr[:] + (np.interp(range(nPixY), (0, nPixY - 1), (start, end)).reshape(nPixY, 1) +
661 np.zeros(ampData.getDimensions()).transpose())
664 """Add a single Gaussian source to an amplifier.
666 This method operates in the amplifier coordinate frame.
670 ampData : `lsst.afw.image.ImageF`
671 Amplifier image to operate on.
673 Peak flux of the source to add.
675 X-coordinate of the source peak.
677 Y-coordinate of the source peak.
679 for x
in range(0, ampData.getDimensions().getX()):
680 for y
in range(0, ampData.getDimensions().getY()):
681 ampData.array[y][x] = (ampData.array[y][x] +
682 scale * np.exp(-0.5 * ((x - x0)**2 + (y - y0)**2) / 3.0**2))
685 """Add a scaled copy of an amplifier to another, simulating crosstalk.
687 This method operates in the amplifier coordinate frame.
691 ampDataSource : `lsst.afw.image.ImageF`
692 Amplifier image to add scaled copy from.
693 ampDataTarget : `lsst.afw.image.ImageF`
694 Amplifier image to add scaled copy to.
696 Flux scale of the copy to add to the target.
700 This simulates simple crosstalk between amplifiers.
702 ampDataTarget.array[:] = (ampDataTarget.array[:] +
703 scale * ampDataSource.array[:])
707 """Add a fringe-like ripple pattern to an amplifier's image data.
711 amp : `~lsst.afw.ampInfo.AmpInfoRecord`
712 Amplifier to operate on. Needed for amp<->exp coordinate transforms.
713 ampData : `lsst.afw.image.ImageF`
714 Amplifier image to operate on.
715 scale : `numpy.array` or `float`
716 Peak intensity scaling for the ripple.
717 x0 : `numpy.array` or `float`, optional
719 y0 : `numpy.array` or `float`, optional
724 This uses an offset sinc function to generate a ripple
725 pattern. True fringes have much finer structure, but this
726 pattern should be visually identifiable. The (x, y)
727 coordinates are in the frame of the amplifier, and (u, v) in
728 the frame of the full trimmed image.
730 for x
in range(0, ampData.getDimensions().getX()):
731 for y
in range(0, ampData.getDimensions().getY()):
733 ampData.getArray()[y][x] = np.sum((ampData.getArray()[y][x] +
735 np.sinc(((u - x0) / 50)**2 +
736 ((v - y0) / 50)**2)))
739 """Multiply an amplifier's image data by a flat-like pattern.
743 amp : `lsst.afw.ampInfo.AmpInfoRecord`
744 Amplifier to operate on. Needed for amp<->exp coordinate transforms.
745 ampData : `lsst.afw.image.ImageF`
746 Amplifier image to operate on.
748 Fractional drop from center to edge of detector along x-axis.
750 Peak location in detector coordinates.
752 Peak location in detector coordinates.
756 This uses a 2-d Gaussian to simulate an illumination pattern
757 that falls off towards the edge of the detector. The (x, y)
758 coordinates are in the frame of the amplifier, and (u, v) in
759 the frame of the full trimmed image.
762 raise RuntimeError(
"Flat fractional drop cannot be greater than 1.0")
764 sigma = u0 / np.sqrt(-2.0 * np.log(fracDrop))
766 for x
in range(0, ampData.getDimensions().getX()):
767 for y
in range(0, ampData.getDimensions().getY()):
769 f = np.exp(-0.5 * ((u - u0)**2 + (v - v0)**2) / sigma**2)
770 ampData.array[y][x] = (ampData.array[y][x] * f)
774 """Generate a raw exposure suitable for ISR.
778 self.config.isTrimmed =
False
779 self.config.doGenerateImage =
True
780 self.config.doGenerateAmpDict =
False
781 self.config.doAddOverscan =
True
782 self.config.doAddSky =
True
783 self.config.doAddSource =
True
784 self.config.doAddCrosstalk =
False
785 self.config.doAddBias =
True
786 self.config.doAddDark =
True
790 """Generate a trimmed raw exposure.
794 self.config.isTrimmed =
True
795 self.config.doAddOverscan =
False
799 """Generate a trimmed raw exposure.
803 self.config.isTrimmed =
True
804 self.config.doGenerateImage =
True
805 self.config.doAddOverscan =
False
806 self.config.doAddSky =
True
807 self.config.doAddSource =
True
808 self.config.doAddCrosstalk =
False
810 self.config.doAddBias =
False
811 self.config.doAddDark =
False
812 self.config.doAddFlat =
False
813 self.config.doAddFringe =
True
815 self.config.biasLevel = 0.0
816 self.config.readNoise = 10.0
820 """Generate a raw exposure dict suitable for ISR.
824 self.config.doGenerateAmpDict =
True
828 """Parent class for those that make master calibrations.
832 self.config.isTrimmed =
True
833 self.config.doGenerateImage =
True
834 self.config.doAddOverscan =
False
835 self.config.doAddSky =
False
836 self.config.doAddSource =
False
837 self.config.doAddCrosstalk =
False
839 self.config.doAddBias =
False
840 self.config.doAddDark =
False
841 self.config.doAddFlat =
False
842 self.config.doAddFringe =
False
846 """Simulated master bias calibration.
850 self.config.doAddBias =
True
851 self.config.readNoise = 10.0
855 """Simulated master dark calibration.
859 self.config.doAddDark =
True
860 self.config.darkTime = 1.0
864 """Simulated master flat calibration.
868 self.config.doAddFlat =
True
872 """Simulated master fringe calibration.
876 self.config.doAddFringe =
True
880 """Simulated untrimmed master fringe calibration.
884 self.config.isTrimmed =
False
888 """Simulated brighter-fatter kernel.
892 self.config.doGenerateImage =
False
893 self.config.doGenerateData =
True
894 self.config.doBrighterFatter =
True
895 self.config.doDefects =
False
896 self.config.doCrosstalkCoeffs =
False
897 self.config.doTransmissionCurve =
False
901 """Simulated defect list.
905 self.config.doGenerateImage =
False
906 self.config.doGenerateData =
True
907 self.config.doBrighterFatter =
False
908 self.config.doDefects =
True
909 self.config.doCrosstalkCoeffs =
False
910 self.config.doTransmissionCurve =
False
914 """Simulated crosstalk coefficient matrix.
918 self.config.doGenerateImage =
False
919 self.config.doGenerateData =
True
920 self.config.doBrighterFatter =
False
921 self.config.doDefects =
False
922 self.config.doCrosstalkCoeffs =
True
923 self.config.doTransmissionCurve =
False
927 """Simulated transmission curve.
931 self.config.doGenerateImage =
False
932 self.config.doGenerateData =
True
933 self.config.doBrighterFatter =
False
934 self.config.doDefects =
False
935 self.config.doCrosstalkCoeffs =
False
936 self.config.doTransmissionCurve =
True
940 """Simulated gen2 butler data ref.
942 Currently only supports get and put operations, which are most
943 likely to be called for data in ISR processing.
946 dataId =
"isrMock Fake Data"
954 if 'config' in kwargs.keys():
962 self.
config.doGenerateImage =
True
963 self.
config.doGenerateData =
False
968 self.
config.doGenerateImage =
False
969 self.
config.doGenerateData =
True
971 def get(self, dataType, **kwargs):
972 """Return an appropriate data product.
977 Type of data product to return.
981 mock : IsrMock.run() result
984 if "_filename" in dataType:
986 return tempfile.mktemp(),
"mock"
987 elif 'transmission_' in dataType:
990 elif dataType ==
'ccdExposureId':
993 elif dataType ==
'camera':
996 elif dataType ==
'raw':
999 elif dataType ==
'bias':
1002 elif dataType ==
'dark':
1005 elif dataType ==
'flat':
1008 elif dataType ==
'fringe':
1011 elif dataType ==
'defects':
1014 elif dataType ==
'bfKernel':
1017 elif dataType ==
'linearizer':
1019 elif dataType ==
'crosstalkSources':
1022 raise RuntimeError(
"ISR DataRefMock cannot return %s.", dataType)
1024 def put(self, exposure, filename):
1025 """Write an exposure to a FITS file.
1029 exposure : `lsst.afw.image.Exposure`
1030 Image data to write out.
1032 Base name of the output file.
1034 exposure.writeFits(filename+
".fits")
1038 """Simulated gen2 butler data ref.
1040 Currently only supports get and put operations, which are most
1041 likely to be called for data in ISR processing.
1044 dataId =
"isrMock Fake Data"
1052 if 'config' in kwargs.keys():
1056 self.
config.isTrimmed =
True
1057 self.
config.doAddFringe =
True
1058 self.
config.readNoise = 10.0
1060 def get(self, dataType, **kwargs):
1061 """Return an appropriate data product.
1066 Type of data product to return.
1070 mock : IsrMock.run() result
1073 if "_filename" in dataType:
1074 return tempfile.mktemp(),
"mock"
1075 elif 'transmission_' in dataType:
1077 elif dataType ==
'ccdExposureId':
1079 elif dataType ==
'camera':
1081 elif dataType ==
'raw':
1083 elif dataType ==
'bias':
1085 elif dataType ==
'dark':
1087 elif dataType ==
'flat':
1089 elif dataType ==
'fringe':
1091 configCopy = copy.deepcopy(self.
config)
1092 for scale, x, y
in zip(self.
config.fringeScale, self.
config.fringeX0, self.
config.fringeY0):
1093 configCopy.fringeScale = [1.0]
1094 configCopy.fringeX0 = [x]
1095 configCopy.fringeY0 = [y]
1098 elif dataType ==
'defects':
1100 elif dataType ==
'bfKernel':
1102 elif dataType ==
'linearizer':
1104 elif dataType ==
'crosstalkSources':
1109 def put(self, exposure, filename):
1110 """Write an exposure to a FITS file.
1114 exposure : `lsst.afw.image.Exposure`
1115 Image data to write out.
1117 Base name of the output file.
1119 exposure.writeFits(filename+
".fits")