MockObject.py 18.9 KB
Newer Older
Fang Yuedong's avatar
Fang Yuedong committed
1
2
3
import galsim
import numpy as np
import astropy.constants as cons
Fang Yuedong's avatar
Fang Yuedong committed
4
from astropy import wcs
Fang Yuedong's avatar
Fang Yuedong committed
5
from astropy.table import Table
6

7
from ObservationSim.MockObject._util import magToFlux, VC_A, convolveGaussXorders
8
9
from ObservationSim.MockObject._util import integrate_sed_bandpass, getNormFactorForSpecWithABMAG, getObservedSED, \
    getABMAG
10
from ObservationSim.MockObject.SpecDisperser import SpecDisperser
Fang Yuedong's avatar
Fang Yuedong committed
11

12

Fang Yuedong's avatar
Fang Yuedong committed
13
class MockObject(object):
14
    def __init__(self, param, logger=None):
Fang Yuedong's avatar
Fang Yuedong committed
15
        self.param = param
Fang Yuedong's avatar
Fang Yuedong committed
16
17
18
19
        
        for key in self.param:
            setattr(self, key, self.param[key])
        
Fang Yuedong's avatar
Fang Yuedong committed
20
21
22
23
24
25
        if self.param["star"] == 0:
            self.type = "galaxy"
        elif self.param["star"] == 1:
            self.type = "star"
        elif self.param["star"] == 2:
            self.type = "quasar"
26

Fang Yuedong's avatar
Fang Yuedong committed
27
28
29
30
31
32
33
34
35
        # self.id = self.param["id"]
        # self.ra = self.param["ra"]
        # self.dec = self.param["dec"]
        # self.ra_orig = self.param["ra_orig"]
        # self.dec_orig = self.param["dec_orig"]
        # self.z = self.param["z"]
        # self.sed_type = self.param["sed_type"]
        # self.model_tag = self.param["model_tag"]
        # self.mag_use_normal = self.param["mag_use_normal"]
36
        self.sed = None
Fang Yuedong's avatar
Fang Yuedong committed
37

38
        # Place holder for outputs
Fang Yuedong's avatar
Fang Yuedong committed
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        # self.av = self.param["av"]
        # self.redden = self.param["redden"]
        # self.pmra = self.param["pmra"]
        # self.pmdec = self.param["pmdec"]
        # self.rv = self.param["rv"]
        # self.parallax = self.param["parallax"]
        # self.g1 = self.param["g1"]
        # self.g2 = self.param["g2"]
        # self.thetaR = self.param["theta"]
        # self.bfrac = self.param["bfrac"]
        # self.hlr_disk = self.param["hlr_disk"]
        # self.hlr_bulge = self.param["hlr_bulge"]
        # self.e1_disk, self.e2_disk = 0., 0.
        # self.e1_bulge, self.e2_bulge = 0., 0.
53
        self.additional_output_str = ""
54

55
56
        self.logger = logger

Fang Yuedong's avatar
Fang Yuedong committed
57
58
59
    def getMagFilter(self, filt):
        if filt.filter_type in ["GI", "GV", "GU"]:
            return self.param["mag_use_normal"]
60
        return self.param["mag_%s" % filt.filter_type]
Fang Yuedong's avatar
Fang Yuedong committed
61
62
        # (TEST) stamp size
        # return 13.0
63

64
    def getFluxFilter(self, filt):
65
        return self.param["flux_%s" % filt.filter_type]
Fang Yuedong's avatar
Fang Yuedong committed
66
67

    def getNumPhotons(self, flux, tel, exptime=150.):
68
        pupil_area = tel.pupil_area * (100.) ** 2  # m^2 to cm^2
Fang Yuedong's avatar
Fang Yuedong committed
69
70
71
        return flux * pupil_area * exptime

    def getElectronFluxFilt(self, filt, tel, exptime=150.):
72
73
74
75
76
77
        # photonEnergy = filt.getPhotonE()
        # flux = magToFlux(self.getMagFilter(filt))
        # factor = 1.0e4 * flux/photonEnergy * VC_A * (1.0/filt.blue_limit - 1.0/filt.red_limit)
        # return factor * filt.efficiency * tel.pupil_area * exptime
        flux = self.getFluxFilter(filt)
        return flux * tel.pupil_area * exptime
Fang Yuedong's avatar
Fang Yuedong committed
78
79
80
81

    def getPosWorld(self):
        ra = self.param["ra"]
        dec = self.param["dec"]
82
        return galsim.CelestialCoord(ra=ra * galsim.degrees, dec=dec * galsim.degrees)
Fang Yuedong's avatar
Fang Yuedong committed
83

xin's avatar
xin committed
84
    def getPosImg_Offset_WCS(self, img, fdmodel=None, chip=None, verbose=True, img_header=None):
Fang Yuedong's avatar
Fang Yuedong committed
85
86
87
88
89
90
        self.posImg = img.wcs.toImage(self.getPosWorld())
        self.localWCS = img.wcs.local(self.posImg)
        if (fdmodel is not None) and (chip is not None):
            if verbose:
                print("\n")
                print("Before field distortion:\n")
91
                print("x = %.2f, y = %.2f\n" % (self.posImg.x, self.posImg.y), flush=True)
Fang Yuedong's avatar
Fang Yuedong committed
92
93
94
            self.posImg = fdmodel.get_Distorted(chip=chip, pos_img=self.posImg)
            if verbose:
                print("After field distortion:\n")
95
                print("x = %.2f, y = %.2f\n" % (self.posImg.x, self.posImg.y), flush=True)
Fang Yuedong's avatar
Fang Yuedong committed
96
97
98
99
100
101
        x, y = self.posImg.x + 0.5, self.posImg.y + 0.5
        self.x_nominal = int(np.floor(x + 0.5))
        self.y_nominal = int(np.floor(y + 0.5))
        dx = x - self.x_nominal
        dy = y - self.y_nominal
        self.offset = galsim.PositionD(dx, dy)
xin's avatar
xin committed
102
103
104
105
106
107
108
109

        if img_header is not None:
            self.real_wcs = galsim.FitsWCS(header=img_header)
        else:
            self.real_wcs = None

        return self.posImg, self.offset, self.localWCS, self.real_wcs

110
    def getRealPos(self, img, global_x=0., global_y=0., img_real_wcs=None):
xin's avatar
xin committed
111
112
113
114
115
116
        img_global_pos = galsim.PositionD(global_x, global_y)
        cel_pos = img.wcs.toWorld(img_global_pos)
        realPos = img_real_wcs.toImage(cel_pos)

        return realPos

Fang Yuedong's avatar
Fang Yuedong committed
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    def drawObject(self, img, final, flux=None, filt=None, tel=None, exptime=150.):
        """ Draw (point like) object on img.
        Should be overided for extended source, e.g. galaxy...
        Paramter:
            img: the "canvas"
            final: final (after shear, PSF etc.) GSObject
        Return:
            img: the image with the GSObject added (or discarded)
            isUpdated: is the "canvas" been updated? (a flag for updating statistcs)
        """
        isUpdated = True

        # Draw with FFT
        # stamp = final.drawImage(wcs=self.localWCS, offset=self.offset)

        # Draw with Photon Shoot
        stamp = final.drawImage(wcs=self.localWCS, method='phot', offset=self.offset)
134

Fang Yuedong's avatar
Fang Yuedong committed
135
136
137
138
139
140
141
142
143
144
        stamp.setCenter(self.x_nominal, self.y_nominal)
        if np.sum(np.isnan(stamp.array)) >= 1:
            stamp.setZero()
        bounds = stamp.bounds & img.bounds
        if bounds.area() == 0:
            isUpdated = False
        else:
            img[bounds] += stamp[bounds]
        return img, stamp, isUpdated

145
146
    def drawObj_multiband(self, tel, pos_img, psf_model, bandpass_list, filt, chip, nphotons_tot=None, g1=0, g2=0,
                          exptime=150.):
Fang Yuedong's avatar
Fang Yuedong committed
147
148
149
150
151
152
153
154
        if nphotons_tot == None:
            nphotons_tot = self.getElectronFluxFilt(filt, tel, exptime)
        # print("nphotons_tot = ", nphotons_tot)

        try:
            full = integrate_sed_bandpass(sed=self.sed, bandpass=filt.bandpass_full)
        except Exception as e:
            print(e)
155
            self.logger.error(e)
Fang Yuedong's avatar
Fang Yuedong committed
156
157
158
159
160
161
162
163
164
165
166
167
168
            return False

        nphotons_sum = 0
        photons_list = []
        xmax, ymax = 0, 0

        # (TEST) Galsim Parameters
        if self.getMagFilter(filt) <= 15:
            folding_threshold = 5.e-4
        else:
            folding_threshold = 5.e-3
        gsp = galsim.GSParams(folding_threshold=folding_threshold)

169
170
        self.real_pos = self.getRealPos(chip.img, global_x=self.posImg.x, global_y=self.posImg.y,
                                        img_real_wcs=self.real_wcs)
xin's avatar
xin committed
171

xin's avatar
xin committed
172
        x, y = self.real_pos.x + 0.5, self.real_pos.y + 0.5
xin's avatar
xin committed
173
174
175
176
177
178
        x_nominal = int(np.floor(x + 0.5))
        y_nominal = int(np.floor(y + 0.5))
        dx = x - x_nominal
        dy = y - y_nominal
        offset = galsim.PositionD(dx, dy)

xin's avatar
xin committed
179
        real_wcs_local = self.real_wcs.local(self.real_pos)
xin's avatar
xin committed
180

Fang Yuedong's avatar
Fang Yuedong committed
181
182
183
184
185
186
        for i in range(len(bandpass_list)):
            bandpass = bandpass_list[i]
            try:
                sub = integrate_sed_bandpass(sed=self.sed, bandpass=bandpass)
            except Exception as e:
                print(e)
187
                self.logger.error(e)
Fang Yuedong's avatar
Fang Yuedong committed
188
189
                # return False
                continue
190
191

            ratio = sub / full
Fang Yuedong's avatar
Fang Yuedong committed
192
193
194
195
196
197
198
199

            if not (ratio == -1 or (ratio != ratio)):
                nphotons = ratio * nphotons_tot
            else:
                # return False
                continue
            nphotons_sum += nphotons
            # print("nphotons_sub-band_%d = %.2f"%(i, nphotons))
200
201
            psf, pos_shear = psf_model.get_PSF(chip=chip, pos_img=pos_img, bandpass=bandpass,
                                               folding_threshold=folding_threshold)
Fang Yuedong's avatar
Fang Yuedong committed
202
203
204
205
            star = galsim.DeltaFunction(gsparams=gsp)
            star = star.withFlux(nphotons)
            star = galsim.Convolve(psf, star)

xin's avatar
xin committed
206
207
208
209
210
211
212
213
214
            # stamp = star.drawImage(wcs=self.localWCS, method='phot', offset=self.offset, save_photons=True)
            # xmax = max(xmax, stamp.xmax)
            # ymax = max(ymax, stamp.ymax)
            # photons = stamp.photons
            # photons.x += self.x_nominal
            # photons.y += self.y_nominal
            # photons_list.append(photons)

            stamp = star.drawImage(wcs=real_wcs_local, method='phot', offset=offset, save_photons=True)
Fang Yuedong's avatar
Fang Yuedong committed
215
216
217
            xmax = max(xmax, stamp.xmax)
            ymax = max(ymax, stamp.ymax)
            photons = stamp.photons
xin's avatar
xin committed
218
219
            photons.x += x_nominal
            photons.y += y_nominal
Fang Yuedong's avatar
Fang Yuedong committed
220
221
            photons_list.append(photons)

xin's avatar
xin committed
222
223
224
        stamp = galsim.ImageF(int(xmax * 1.1), int(ymax * 1.1))
        stamp.wcs = real_wcs_local
        stamp.setCenter(x_nominal, y_nominal)
225
        bounds = stamp.bounds & galsim.BoundsI(0, chip.npix_x - 1, 0, chip.npix_y - 1)
Fang Yuedong's avatar
Fang Yuedong committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
        
        # # (DEBUG)
        # print("stamp bounds: ", stamp.bounds)
        # print(bounds)
        if bounds.area() > 0:
            chip.img.setOrigin(0, 0)
            stamp[bounds] = chip.img[bounds]
            for i in range(len(photons_list)):
                if i == 0:
                    chip.sensor.accumulate(photons_list[i], stamp)
                else:
                    chip.sensor.accumulate(photons_list[i], stamp, resume=True)

            chip.img[bounds] = stamp[bounds]

            chip.img.setOrigin(chip.bound.xmin, chip.bound.ymin)
xin's avatar
xin committed
242
243
        # Test stamp size
        # print(xmax, ymax)
xin's avatar
xin committed
244

xin's avatar
xin committed
245
246
247
248
        # stamp = galsim.ImageF(int(xmax*1.1), int(ymax*1.1))
        # stamp.wcs = self.localWCS
        # stamp.setCenter(self.x_nominal, self.y_nominal)
        # bounds = stamp.bounds & chip.img.bounds
xin's avatar
xin committed
249
250
251
252
253
254
255
256
        # stamp[bounds] = chip.img[bounds]
        # for i in range(len(photons_list)):
        #     if i == 0:
        #         chip.sensor.accumulate(photons_list[i], stamp)
        #     else:
        #         chip.sensor.accumulate(photons_list[i], stamp, resume=True)
        #
        # chip.img[bounds] = stamp[bounds]
Fang Yuedong's avatar
Fang Yuedong committed
257
258
259
260
261
262
        # print(chip.img.array.sum())
        # print("nphotons_sum = ", nphotons_sum)
        del photons_list
        del stamp
        return True, pos_shear

263
    def addSLStoChipImage(self, sdp=None, chip=None, xOrderSigPlus=None, local_wcs=None):
Xin Zhang's avatar
Xin Zhang committed
264
265
266
        spec_orders = sdp.compute_spec_orders()
        for k, v in spec_orders.items():
            img_s = v[0]
Fang Yuedong's avatar
Fang Yuedong committed
267
268
269
270
271
272
273
274
275
            #########################################################
            # DEBUG
            #########################################################
            # print("before convolveGaussXorders, img_s:", img_s)
            nan_ids = np.isnan(img_s)
            if img_s[nan_ids].shape[0] > 0:
                # img_s[nan_ids] = 0
                print("DEBUG: before convolveGaussXorders specImg nan num is", img_s[nan_ids].shape[0])
            #########################################################
Xin Zhang's avatar
Xin Zhang committed
276
277
278
            img_s, orig_off = convolveGaussXorders(img_s, xOrderSigPlus[k])
            origin_order_x = v[1] - orig_off
            origin_order_y = v[2] - orig_off
Fang Yuedong's avatar
Fang Yuedong committed
279
280
281
282
283
284
285
286
287
288

            #########################################################
            # DEBUG
            #########################################################
            # print("DEBUG: orig_off is", orig_off)
            nan_ids = np.isnan(img_s)
            if img_s[nan_ids].shape[0] > 0:
                img_s[nan_ids] = 0
                print("DEBUG: specImg nan num is", img_s[nan_ids].shape[0])
            #########################################################
Xin Zhang's avatar
Xin Zhang committed
289
290
291
292
293
294
295
296
            specImg = galsim.ImageF(img_s)
            photons = galsim.PhotonArray.makeFromImage(specImg)
            photons.x += origin_order_x
            photons.y += origin_order_y

            xlen_imf = int(specImg.xmax - specImg.xmin + 1)
            ylen_imf = int(specImg.ymax - specImg.ymin + 1)
            stamp = galsim.ImageF(xlen_imf, ylen_imf)
xin's avatar
xin committed
297
            stamp.wcs = local_wcs
Xin Zhang's avatar
Xin Zhang committed
298
299
            stamp.setOrigin(origin_order_x, origin_order_y)

300
            bounds = stamp.bounds & galsim.BoundsI(0, chip.npix_x - 1, 0, chip.npix_y - 1)
Xin Zhang's avatar
Xin Zhang committed
301
302
            if bounds.area() == 0:
                continue
xin's avatar
xin committed
303
            chip.img.setOrigin(0, 0)
Xin Zhang's avatar
Xin Zhang committed
304
305
306
            stamp[bounds] = chip.img[bounds]
            chip.sensor.accumulate(photons, stamp)
            chip.img[bounds] = stamp[bounds]
xin's avatar
xin committed
307
            chip.img.setOrigin(chip.bound.xmin, chip.bound.ymin)
Xin Zhang's avatar
Xin Zhang committed
308
309
310
            del stamp
        del spec_orders

Fang Yuedong's avatar
Fang Yuedong committed
311
    def drawObj_slitless(self, tel, pos_img, psf_model, bandpass_list, filt, chip, nphotons_tot=None, g1=0, g2=0,
Xin Zhang's avatar
Xin Zhang committed
312
                         exptime=150., normFilter=None, grating_split_pos=3685):
313

Fang Yuedong's avatar
Fang Yuedong committed
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
        norm_thr_rang_ids = normFilter['SENSITIVITY'] > 0.001
        sedNormFactor = getNormFactorForSpecWithABMAG(ABMag=self.param['mag_use_normal'], spectrum=self.sed,
                                                      norm_thr=normFilter,
                                                      sWave=np.floor(normFilter[norm_thr_rang_ids][0][0]),
                                                      eWave=np.ceil(normFilter[norm_thr_rang_ids][-1][0]))
        # print(self.x_nominal, self.y_nominal, chip.bound)

        if sedNormFactor == 0:
            return False

        if self.getMagFilter(filt) <= 15:
            folding_threshold = 5.e-4
        else:
            folding_threshold = 5.e-3
        gsp = galsim.GSParams(folding_threshold=folding_threshold)

        normalSED = Table(np.array([self.sed['WAVELENGTH'], self.sed['FLUX'] * sedNormFactor]).T,
                          names=('WAVELENGTH', 'FLUX'))

333
334
        self.real_pos = self.getRealPos(chip.img, global_x=self.posImg.x, global_y=self.posImg.y,
                                        img_real_wcs=self.real_wcs)
xin's avatar
xin committed
335
336
337
338
339
340
341
342
343
344

        x, y = self.real_pos.x + 0.5, self.real_pos.y + 0.5
        x_nominal = int(np.floor(x + 0.5))
        y_nominal = int(np.floor(y + 0.5))
        dx = x - x_nominal
        dy = y - y_nominal
        offset = galsim.PositionD(dx, dy)

        real_wcs_local = self.real_wcs.local(self.real_pos)

345
        flat_cube = chip.flat_cube
Zhang Xin's avatar
Zhang Xin committed
346

347
348
        xOrderSigPlus = {'A': 1.3909419820029296, 'B': 1.4760376591236062, 'C': 4.035447379743442,
                         'D': 5.5684364343742825, 'E': 16.260021029735388}
xin's avatar
xin committed
349
        grating_split_pos_chip = 0 + grating_split_pos
Fang Yuedong's avatar
Fang Yuedong committed
350
351
        for i in range(len(bandpass_list)):
            bandpass = bandpass_list[i]
352
353
            psf, pos_shear = psf_model.get_PSF(chip=chip, pos_img=pos_img, bandpass=bandpass,
                                               folding_threshold=folding_threshold)
Fang Yuedong's avatar
Fang Yuedong committed
354
355
356
            star = galsim.DeltaFunction(gsparams=gsp)
            star = star.withFlux(tel.pupil_area * exptime)
            star = galsim.Convolve(psf, star)
xin's avatar
xin committed
357
            starImg = star.drawImage(nx=100, ny=100, wcs=real_wcs_local)
Fang Yuedong's avatar
Fang Yuedong committed
358

xin's avatar
xin committed
359
360
            origin_star = [y_nominal - (starImg.center.y - starImg.ymin),
                           x_nominal - (starImg.center.x - starImg.xmin)]
Fang Yuedong's avatar
Fang Yuedong committed
361

Xin Zhang's avatar
Xin Zhang committed
362
363
364
365
366
367
368
369
370
371
            gal_origin = [origin_star[0], origin_star[1]]
            gal_end = [origin_star[0] + starImg.array.shape[0] - 1, origin_star[1] + starImg.array.shape[1] - 1]

            if gal_origin[1] < grating_split_pos_chip < gal_end[1]:
                subSlitPos = int(grating_split_pos_chip - gal_origin[1] + 1)
                ## part img disperse

                subImg_p1 = starImg.array[:, 0:subSlitPos]
                star_p1 = galsim.Image(subImg_p1)
                origin_p1 = origin_star
372
373
                xcenter_p1 = min(x_nominal, grating_split_pos_chip - 1) - 0
                ycenter_p1 = y_nominal - 0
Xin Zhang's avatar
Xin Zhang committed
374
375

                sdp_p1 = SpecDisperser(orig_img=star_p1, xcenter=xcenter_p1,
376
377
378
379
380
381
                                       ycenter=ycenter_p1, origin=origin_p1,
                                       tar_spec=normalSED,
                                       band_start=bandpass.blue_limit * 10, band_end=bandpass.red_limit * 10,
                                       conf=chip.sls_conf[0],
                                       isAlongY=0,
                                       flat_cube=flat_cube)
Xin Zhang's avatar
Xin Zhang committed
382

383
                self.addSLStoChipImage(sdp=sdp_p1, chip=chip, xOrderSigPlus=xOrderSigPlus, local_wcs=real_wcs_local)
Xin Zhang's avatar
Xin Zhang committed
384

385
                subImg_p2 = starImg.array[:, subSlitPos + 1:starImg.array.shape[1]]
Xin Zhang's avatar
Xin Zhang committed
386
387
                star_p2 = galsim.Image(subImg_p2)
                origin_p2 = [origin_star[0], grating_split_pos_chip]
xin's avatar
xin committed
388
389
                xcenter_p2 = max(x_nominal, grating_split_pos_chip - 1) - 0
                ycenter_p2 = y_nominal - 0
Xin Zhang's avatar
Xin Zhang committed
390
391
392
393
394
395

                sdp_p2 = SpecDisperser(orig_img=star_p2, xcenter=xcenter_p2,
                                       ycenter=ycenter_p2, origin=origin_p2,
                                       tar_spec=normalSED,
                                       band_start=bandpass.blue_limit * 10, band_end=bandpass.red_limit * 10,
                                       conf=chip.sls_conf[1],
396
397
                                       isAlongY=0,
                                       flat_cube=flat_cube)
Xin Zhang's avatar
Xin Zhang committed
398

399
                self.addSLStoChipImage(sdp=sdp_p2, chip=chip, xOrderSigPlus=xOrderSigPlus, local_wcs=real_wcs_local)
Xin Zhang's avatar
Xin Zhang committed
400
401
402

                del sdp_p1
                del sdp_p2
403
            elif grating_split_pos_chip <= gal_origin[1]:
xin's avatar
xin committed
404
405
                sdp = SpecDisperser(orig_img=starImg, xcenter=x_nominal - 0,
                                    ycenter=y_nominal - 0, origin=origin_star,
Xin Zhang's avatar
Xin Zhang committed
406
407
408
                                    tar_spec=normalSED,
                                    band_start=bandpass.blue_limit * 10, band_end=bandpass.red_limit * 10,
                                    conf=chip.sls_conf[1],
409
410
411
                                    isAlongY=0,
                                    flat_cube=flat_cube)
                self.addSLStoChipImage(sdp=sdp, chip=chip, xOrderSigPlus=xOrderSigPlus, local_wcs=real_wcs_local)
Xin Zhang's avatar
Xin Zhang committed
412
                del sdp
413
            elif grating_split_pos_chip >= gal_end[1]:
xin's avatar
xin committed
414
415
                sdp = SpecDisperser(orig_img=starImg, xcenter=x_nominal - 0,
                                    ycenter=y_nominal - 0, origin=origin_star,
Xin Zhang's avatar
Xin Zhang committed
416
417
418
                                    tar_spec=normalSED,
                                    band_start=bandpass.blue_limit * 10, band_end=bandpass.red_limit * 10,
                                    conf=chip.sls_conf[0],
419
420
421
                                    isAlongY=0,
                                    flat_cube=flat_cube)
                self.addSLStoChipImage(sdp=sdp, chip=chip, xOrderSigPlus=xOrderSigPlus, local_wcs=real_wcs_local)
Xin Zhang's avatar
Xin Zhang committed
422
                del sdp
Fang Yuedong's avatar
Fang Yuedong committed
423
424
425
426
427
428
429
430
431
432
433
434
435
            del psf
        return True, pos_shear

    def SNRestimate(self, img_obj, flux, noise_level=0.0, seed=31415):
        img_flux = img_obj.added_flux
        stamp = img_obj.copy() * 0.0
        rng = galsim.BaseDeviate(seed)
        gaussianNoise = galsim.GaussianNoise(rng, sigma=noise_level)
        stamp.addNoise(gaussianNoise)
        sig_obj = np.std(stamp.array)
        snr_obj = img_flux / sig_obj
        return snr_obj

436
437
    # def getObservedEll(self, g1=0, g2=0):
    #     return 0.0, 0.0, 0.0, 0.0, 0.0, 0.0