def get_flux_and_err(imagedat, psfmodel, xy, ntestpositions=100, psfradpix=3, apradpix=3, skyannpix=None, skyalgorithm='sigmaclipping', setskyval=None, recenter_target=True, recenter_fakes=True, exptime=1, exact=True, ronoise=1, phpadu=1, verbose=False, debug=False): """ Measure the flux and flux uncertainty for a source at the given x,y position using both aperture and psf-fitting photometry. Flux errors are measured by planting fake psfs or empty apertures into the sky annulus and recovering a distribution of fluxes with forced photometry. :param imagedat: target image numpy data array (with the star still there) :param psfmodel: psf model fits file or a 4-tuple with [gaussparam,lookuptable,psfmag,psfzpt] :param xy: x,y position of the center of the fake planting field :param ntestpositions: number of test positions for empty apertures and/or fake stars to use for determining the flux error empirically. :param psfradpix: radius to use for psf fitting, in pixels :param apradpix: radius of photometry aperture, in pixels :param skyannpix: inner and outer radius of sky annulus, in pixels :param skyalgorithm: algorithm to use for determining the sky value from the pixels within the sky annulus: 'sigmaclipping' or 'mmm' :param setskyval: if not None, use this value for the sky, ignoring the skyannulus :param recenter_target: use cntrd to locate the target center near the given xy position. :param recenter_fakes: recenter on each planted fake when recovering it :param exptime: exposure time of the image, for determining poisson noise :param ronoise: read-out noise, for determining aperture flux error analytically :param phpadu: photons-per-ADU, for determining aper flux err analytically :param verbose: turn verbosity on :param debug: enter pdb debugging mode :return: apflux, apfluxerr, psfflux, psffluxerr The flux measured through the given aperture and through psf fitting, along with associated errors. """ if not np.any(skyannpix): skyannpix = [8, 15] # locate the target star center position x, y = xy if recenter_target: x, y = cntrd(imagedat, x, y, psfradpix) if x < 0 or y < 0: print("WARNING [photfunctions.py] : recentering failed") import pdb pdb.set_trace() # do aperture photometry directly on the source # (Note : using an arbitrary zeropoint of 25 here) aperout = aper(imagedat, x, y, phpadu=phpadu, apr=apradpix, skyrad=skyannpix, setskyval=setskyval, zeropoint=25, exact=exact, verbose=verbose, skyalgorithm=skyalgorithm, debug=debug) apmag, apmagerr, apflux, apfluxerr, sky, skyerr, apbadflag, apoutstr = \ aperout # define a set of test position points that uniformly samples the sky # annulus region, for planting empty apertures and/or fake stars rmin = float(skyannpix[0]) rmax = float(skyannpix[1]) u = np.random.uniform(rmin, rmax, ntestpositions) v = np.random.uniform(0, rmin + rmax, ntestpositions) r = np.where(v < u, u, rmax + rmin - u) theta = np.random.uniform(0, 2 * np.pi, ntestpositions) xtestpositions = r * np.cos(theta) + x ytestpositions = r * np.sin(theta) + y psfflux = psffluxerr = np.nan if psfmodel is not None: # set up the psf model realization gaussparam, lookuptable, psfmag, psfzpt = rdpsfmodel(psfmodel) psfmodel = [gaussparam, lookuptable, psfmag, psfzpt] pk = pkfit_class(imagedat, gaussparam, lookuptable, ronoise, phpadu) # do the psf fitting try: scale = pk.pkfit_fast_norecenter(1, x, y, sky, psfradpix) psfflux = scale * 10 ** (0.4 * (25. - psfmag)) except RuntimeWarning: print("PythonPhot.pkfit_norecenter failed.") psfflux = np.nan if np.isfinite(psfflux): # remove the target star from the image imagedat = addtoimarray(imagedat, psfmodel, [x, y], fluxscale=-psfflux) # plant fakes and recover their fluxes with psf fitting # imdatsubarray = imagedat[y-rmax-2*psfradpix:y+rmax+2*psfradpix, # x-rmax-2*psfradpix:x+rmax+2*psfradpix] fakecoordlist, fakefluxlist = [], [] for xt, yt in zip(xtestpositions, ytestpositions): # To ensure appropriate sampling of sub-pixel positions, # we assign random sub-pixel offsets to each position. xt = int(xt) + np.random.random() yt = int(yt) + np.random.random() fakefluxaper, fakefluxpsf, fakecoord = add_and_recover( imagedat, psfmodel, [xt, yt], fluxscale=psfflux, cleanup=True, psfradius=psfradpix, recenter=recenter_fakes) if np.isfinite(fakefluxpsf): fakecoordlist.append(fakecoord) fakefluxlist.append(fakefluxpsf) fakefluxlist = np.array(fakefluxlist) fakefluxmean, fakefluxsigma = gaussian_fit_to_histogram(fakefluxlist) if abs(fakefluxmean - psfflux) > fakefluxsigma and verbose: print("WARNING: psf flux may be biased. Fake psf flux tests " "found a significantly non-zero sky value not accounted for " "in measurement of the target flux: \\" "Mean psf flux offset in sky annulus = %.3e\\" % (fakefluxmean - psfflux) + "sigma of fake flux distribution = %.3e" % fakefluxsigma + "NOTE: this is included as a systematic error, added in " "quadrature to the psf flux err derived from fake psf " "recovery.") psfflux_poissonerr = (poissonErr(psfflux * exptime, confidence=1) / exptime) # Total flux error is the quadratic sum of the poisson noise with # the systematic (shift) and statistical (dispersion) errors # inferred from fake psf planting and recovery psffluxerr = np.sqrt(psfflux_poissonerr**2 + (fakefluxmean - psfflux)**2 + fakefluxsigma**2) # drop down empty apertures and recover their fluxes with aperture phot # NOTE : if the star was removed for psf fitting, then we take advantage # of that to get aperture flux errors with the star gone. emptyaperout = aper(imagedat, np.array(xtestpositions), np.array(ytestpositions), phpadu=phpadu, apr=apradpix, setskyval=sky, zeropoint=25, exact=False, verbose=verbose, skyalgorithm=skyalgorithm, debug=debug) emptyapflux = emptyaperout[2] if np.any(np.isfinite(emptyapflux)): emptyapmeanflux, emptyapsigma = gaussian_fit_to_histogram(emptyapflux) emptyapbias = abs(emptyapmeanflux) - emptyapsigma if np.any(emptyapbias > 0) and verbose: print("WARNING: aperture flux may be biased. Empty aperture flux tests" " found a significantly non-zero sky value not accounted for in " "measurement of the target flux: \\" "Mean empty aperture flux in sky annulus = %s\\" % emptyapmeanflux + "sigma of empty aperture flux distribution = %s" % emptyapsigma) if np.iterable(apflux): apflux_poissonerr = np.array( [poissonErr(fap * exptime, confidence=1) / exptime for fap in apflux]) else: apflux_poissonerr = (poissonErr(apflux * exptime, confidence=1) / exptime) apfluxerr = np.sqrt(apflux_poissonerr**2 + emptyapbias**2 + emptyapsigma**2) else: if np.iterable(apradpix): apfluxerr = [np.nan for aprad in apradpix] else: apfluxerr = np.nan if psfmodel is not None and np.isfinite(psfflux): # return the target star back into the image imagedat = addtoimarray(imagedat, psfmodel, [x, y], fluxscale=psfflux) if debug > 1: import pdb pdb.set_trace() return apflux, apfluxerr, psfflux, psffluxerr, sky, skyerr
indices_y = np.where(d_y > 0)[0] width_x = len(indices_x) width_y = len(indices_y) fwhm = (width_x + width_y) / 2 rms = (np.std(image - image.mean(axis=0))) x, y, flux, sharp, round = find(image, fwhm=fwhm, hmin=rms * 3, verbose=False) xpos, ypos = x, y # run aper to get mags and sky values for specified coords mag, magerr, flux, fluxerr, sky, skyerr, badflag, outstr = \ aper.aper(image, xpos, ypos, phpadu=1, apr=5, zeropoint=25, skyrad=[40, 50], badpix=[0, 10000000000], exact=True, verbose=False) # use the stars at those coords to generate a PSF model gauss, psf, psfmag = \ getpsf.getpsf(image, xpos, ypos, mag, sky, 1, 1, np.arange(len(xpos)), fitrad=window/2, psfname='output_psf.fits', psfrad=int(window+20)/2, verbose=False) print("Amplitude of Gauss Function : " + str(gauss[0])) print("X-Axis Best Fit Offset : " + str(gauss[1])) print("Y-Axis Best Fit Offset : " + str(gauss[2])) print("Standard deviation of the gauss function on the X-axis : " + str(gauss[3])) print("Standard deviation of the gauss function on the Y-axis : " + str(gauss[4])) # plt.plot(gauss)
def add_and_recover(imagedat, psfmodel, xy, fluxscale=1, psfradius=5, skyannpix=None, skyalgorithm='sigmaclipping', setskyval=None, recenter=False, ronoise=1, phpadu=1, cleanup=True, verbose=False, debug=False): """ Add a single fake star psf model to the image at the given position and flux scaling, re-measure the flux at that position and report it, Also deletes the planted psf from the imagedat array so that we don't pollute that image array. :param imagedat: target image numpy data array :param psfmodel: psf model fits file or tuple with [gaussparam,lookuptable] :param xy: x,y position for fake psf, using the IDL/python convention where [0,0] is the lower left corner. :param fluxscale: flux scaling to apply to the planted psf :param recenter: use cntrd to locate the center of the added psf, instead of relying on the input x,y position to define the psf fitting :param cleanup: remove the planted psf from the input imagedat array. :return: """ if not skyannpix: skyannpix = [8, 15] # add the psf to the image data array imdatwithpsf = addtoimarray(imagedat, psfmodel, xy, fluxscale=fluxscale) # TODO: allow for uncertainty in the x,y positions gaussparam, lookuptable, psfmag, psfzpt = rdpsfmodel(psfmodel) # generate an instance of the pkfit class for this psf model # and target image pk = pkfit_class(imdatwithpsf, gaussparam, lookuptable, ronoise, phpadu) x, y = xy if debug: from .photfunctions import showpkfit from matplotlib import pyplot as pl, cm fig = pl.figure(3) showpkfit(imdatwithpsf, psfmodel, xy, 11, fluxscale, verbose=True) fig = pl.figure(1) pl.imshow(imdatwithpsf[y - 20:y + 20, x - 20:x + 20], cmap=cm.Greys, interpolation='nearest') pl.colorbar() import pdb pdb.set_trace() if recenter: xc, yc = cntrd(imdatwithpsf, x, y, psfradius, verbose=verbose) if xc > 0 and yc > 0 and abs(xc - xy[0]) < 5 and abs(yc - xy[1]) < 5: x, y = xc, yc # do aperture photometry to get the sky aperout = aper(imdatwithpsf, x, y, phpadu=phpadu, apr=psfradius * 3, skyrad=skyannpix, setskyval=(setskyval is not None and setskyval), zeropoint=psfzpt, exact=False, verbose=verbose, skyalgorithm=skyalgorithm, debug=debug) apmag, apmagerr, apflux, apfluxerr, sky, skyerr, apbadflag, apoutstr\ = aperout # do the psf fitting try: scale = pk.pkfit_fast_norecenter(1, x, y, sky, psfradius) fluxpsf = scale * 10 ** (-0.4 * (psfmag - psfzpt)) except RuntimeWarning: print("photfunctions.add_and_recover failed on RuntimeWarning") fluxpsf = -99 if cleanup: # remove the fake psf from the image imagedat = addtoimarray(imdatwithpsf, psfmodel, xy, fluxscale=-fluxscale) return apflux[0], fluxpsf, [x, y]
def simulate_image(psffits=None, theofits=None, obsfits=None, distance=None, extfits=None, wlen=None, pfov=None, filt=None, psfext=0, obsext=0, bgstd=0, bgmed=0, silent=False, posang=0, foi_as=4, outname=None, manscale=None, fnucdiam_as=0.45, suffix=None, fitsize=None, outfolder='.', writesimfits=False, writetheofits=False, writeallfits=False, writefitplot=False, debug=False, returncmod=True, fitpsf=False, saveplot=False, meastime=False): """ Simulate a (VISIR) imaging observaion given a real image, a PSF reference image and a model image for a provided object distance and position angle Current constraints: - The routine assumes that the images are squares (x = y) """ if meastime: tstart = time.time() psfim = fits.getdata(psffits, ext=psfext) psfhead = fits.getheader(psffits) # print(obsfits, obsext) # ==== 1. Load Observational and PSF data ==== if obsfits is not None: obsim = fits.getdata(obsfits, ext=obsext) obshead = fits.getheader(obsfits) if wlen is None: wlen = float(obshead['WAVELEN']) if pfov is None: pfov = obshead['PFOV'] if filt is None: filt = obshead['Filter'] else: if wlen is None: wlen = float(psfhead['WAVELEN']) if pfov is None: pfov = psfhead['PFOV'] if filt is None: filt = psfhead['Filter'] wlenstr = "{:.1f}".format(wlen) diststr = "{:.1f}".format(distance) pastr = "{:.0f}".format(posang) # --- optinal cropping of the PSF image if fitsize is not None: psfim = _crop_image(psfim, box=fitsize, cenpos=_get_pointsource(psfim)[0][2:4]) psfsize = np.array(np.shape(psfim)) psfsize_as = psfsize[0] * pfov if not silent: print("Obs. wavelength [um]: " + wlenstr) # ==== 2. Prepare theoretical image for convolution ==== theohdu = fits.open(theofits) theohead = theohdu[0].header # --- check if provided file is the full cube if 'NAXIS3' in theohead: # find the right frame to be extracted mind, mwlen = find_wlen_match(theofits, wlen) theoim = theohdu[0].data[mind] if not silent: print(" - Model wavelength [um] | frame no: " + str(mwlen) + " | " + str(mind)) else: theoim = theohdu[0].data theohdu.close() if meastime: print(" - All files read. Elapsed time: ", time.time() - tstart) if debug is True: print("THEOIM: ") plt.imshow(theoim, origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # --- if a manual scaling (fudge) factor was provided, apply to the model if manscale: theoim = theoim * manscale # --- rotate the model image (this changes its extent and thus has to be # done first) # unrot = np.copy(theoim) if np.abs(posang - 0) > 0.01: theoim = ndimage.interpolation.rotate(theoim, 180 - posang, order=0) if meastime: print(" - Model rotated. Elapsed time: ", time.time() - tstart) if debug is True: print("THEOIM_ROT: ") plt.imshow(theoim, origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # --- size units of the theoretical image theopixsize_pc = theohead['CDELT1'] theosize = np.array(np.shape(theoim)) theosize_pc = theopixsize_pc * theosize[0] # pc theosize_as = 2 * np.arctan( theosize_pc / distance / 2.0e6) * 180 / np.pi * 3600 theopixsize_as = (2 * np.arctan(theopixsize_pc / distance / 2.e6) * 180 / np.pi * 3600) # plt.imshow(unrot, origin='bottom', norm=LogNorm()) # plt.imshow(theoim, origin='bottom', norm=LogNorm()) # plt.imshow(theoim, origin='bottom') # theopfov = angsize/theosize[0] # normalize image to flux = 1 # theoim = theoim/np.sum(theoim) # theoim = theoim/np.max(theoim) # --- convert to the right flux units # surface brightness unit in cube is W/m^2/arcsec2 # -> convert to flux density in mJy # print(np.sum(theoim)) freq = 2.99793e8 / (1e-6 * wlen) # print(freq) theoim = theoim * 1.0e29 / freq * theopixsize_as**2 theototflux = np.sum(theoim) # --- resample to the same pixel size as the observation # print( "- Resampling the model image to instrument pixel size...") # --- the ndimage.zoom sometimes creates weird artifacts and thus might not # be a good choice. Instead, use the self-made routine # theoim_resres = ndimage.zoom(theoim_res, theopixsize_as/pfov, order=0) # --- do the rasmpling before scaling it to the size of the observation to # save computing time theoim_res, sizerat = _increase_pixelsize(theoim, oldpfov=theopixsize_as, newpfov=pfov, meastime=False) if meastime: print(" - Pixelsize increased. Elapsed time: ", time.time() - tstart) if debug is True: print("sizerat: ", sizerat) print("THEOIM_RESRES: ") plt.imshow(theoim_res, origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # --- if the PSF frame size is larger than the model extend the model frame framerat = psfsize_as / theosize_as if debug is True: print("psfsize_as: ", psfsize_as) print("theosize_as: ", theosize_as) print("theopixsize_as: ", theopixsize_as) print("theosize_pc: ", theosize_pc) print("theosize: ", theosize) print("framerat: ", framerat) #print("newsize: ", newsize) if framerat > 1.0: theoim_resres = _extend_image(theoim_res, fac=framerat) if meastime: print(" - Frame extended. Elapsed time: ", time.time() - tstart) if debug is True: print("thesize_ext: ", np.shape(theoim_resres)) print("THEOIM_RESRES: ") plt.imshow(theoim_resres, origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # plt.imshow(theoim_res, origin='bottom') else: theoim_resres = np.copy(theoim_res) theosize_new = np.array(np.shape(theoim_resres)) if debug is True: print("theosize_new: ", theosize_new) print("new theosize_as: ", theosize_new * pfov) # print(np.sum(theoim_resres)) # --- after resampling we need to re-establish the right flux levels theoim_resres = theoim_resres / np.sum(theoim_resres) * theototflux # plt.imshow(theoim_resres, origin='bottom', norm=LogNorm()) # plt.imshow(theoim_resres, origin='bottom') # ==== 4. Optionally, apply a foreground extinction map if provided ==== if extfits: exthdu = fits.open(extfits) exthead = exthdu[0].header extpfov = exthead["PFOV"] # check if provided file is the full cube if 'NAXIS3' in exthead: # find the right frame to be extracted if not mind: mind, mwlen = find_wlen_match(theofits, wlen) extim = exthdu[0].data[mind] else: extim = exthdu[0].data # plt.imshow(extim,origin='bottom') # plt.show() exthdu.close() # --- Do we have to resample the extinction map if np.abs(extpfov - pfov) > 0.001: # print("Resampling extinction map... ") extim = ndimage.zoom(extim, 1.0 * pfov / extpfov, order=0) # --- match the size of the extinction map to the one of the model # image extsize = np.array(np.shape(extim)) if theosize_new[0] > extsize[0]: print(" - ERROR: provided extinction map is too small to cover \ the imaged region. Abort...") return () if extsize[0] > theosize_new[0]: # print("Cuttting exctinction map...") extim = _crop_image(extim, box=theosize_new) # --- finally apply the extinction map theoim_resres = theoim_resres * extim # print('Maximum extinction: ',np.min(extim)) # ==== 5. Obtain the Airy function from the calibrator ==== if debug is True: print("PSF_IM: ") plt.imshow(psfim, origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # --- set up the fitting of the STD star image # --- assume that the maximum of the (cropped) image is the STD star if fitpsf is True: psfmax = np.max(psfim) psfmaxpos = np.unravel_index(np.argmax(psfim), psfsize) # print(im_bg, im_max, im_size, im_maxpos) # --- Use an Airy plus a Moffat + constant as PSF model c_init = models.Const2D(amplitude=np.median(psfim)) oa_init = obsc_AiryDisk2D(amplitude=psfmax, x_0=psfmaxpos[1], y_0=psfmaxpos[0], radius=5, obsrat=0.15) m_init = models.Moffat2D(amplitude=psfmax, x_0=psfmaxpos[1], y_0=psfmaxpos[0], gamma=5, alpha=1) a_plus_m = oa_init + m_init + c_init # print(psfmax, psfmaxpos) # --- Selection of fitting method fit_meth = fitting.LevMarLSQFitter() # --- Do the Fitting: y, x = np.mgrid[:psfsize[0], :psfsize[1]] am_fit = fit_meth(a_plus_m, x, y, psfim) # print(am_fit.radius_0.value, am_fit.obsrat_0.value) # then refine the fit by subtracting another Moffat # a_plus_m_minus_m = am_fit - m_init # amm_fit = fit_meth(a_plus_m_minus_m, x, y, psfim) # z_amm = amm_fit(x, y) # res = psfim - z_amm #print(amm_fit.radius_0.value, amm_fit.obsrat_0.value) if meastime: print(" - PSf fit. Elapsed time: ", time.time() - tstart) if debug is True: print("PSF_FIT: ") plt.imshow(am_fit(x, y), origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # --- Genarate the PSF image with the fitted model # --- check whether the model image is on sky larger than the PSF image # and if this is the case increase the grid and adjust the positions # of the fits size_diff = theosize_new[0] - psfsize[0] if size_diff > 0: y, x = np.mgrid[:theosize_new[0], :theosize_new[1]] am_fit.x_0_0 = am_fit.x_0_0 + 0.5 * size_diff am_fit.y_0_0 = am_fit.y_0_0 + 0.5 * size_diff am_fit.x_0_1 = am_fit.x_0_1 + 0.5 * size_diff am_fit.y_0_1 = am_fit.y_0_1 + 0.5 * size_diff # --- create the final PSF image by subtracting the constant terms # and normalise by its area psf = am_fit(x, y) - am_fit.amplitude_2.value psf = psf / np.sum(psf) if debug is True: print("PSF_FINAL: ") plt.imshow(psf, origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # plt.imshow(psf, origin='bottom', norm=LogNorm()) # plt.show() if writeallfits is True: fout = psffits.replace('.fits', '_fit.fits') if 'OBS NAME' in psfhead: psfhead.remove('OBS NAME') fits.writeto(fout, psf, psfhead, overwrite=True) # --- optinally, write the a plot documenting the quality of the PSF fit if writefitplot: fitplotfname = psffits.split('/')[-1] fitplotfname = fitplotfname.replace('.fits', '_fitplot.pdf') fitplotfname = outfolder + '/' + fitplotfname maxrad = int(0.5 * np.sqrt(0.5) * np.min(psfsize)) _make_fit_plots(psfim, am_fit(x, y), fitplotfname, am_fit.x_0_0, am_fit.y_0_0, maxrad, inv=True, cmap='gist_heat', labelcolor='black') # --- alternatively the PSF can also be direclty provided so that no fit is # necessary else: # normalise the provided psf psf = psfim - np.nanmin(psfim) psf = psf / np.nansum(psf) psf[np.argwhere(np.isnan(psf))] = 0 # ==== 6. Convolution of the model image with the PSF ==== simim = scipy.signal.convolve2d(theoim_resres, psf, mode='same') # print(np.sum(simim)) if meastime: print(" - Model convolved. Elapsed time: ", time.time() - tstart) if debug is True: print("SIMIM:") plt.imshow(simim, origin='bottom', norm=LogNorm(), interpolation='nearest') plt.show() # ==== 7. Flux measurements and application of noise ==== # --- Flux measurement on the model image before applying noise ftotmod = int(np.nansum(simim)) apos = 0.5 * np.array(theosize_new) nucrad_px = 0.5 * fnucdiam_as / pfov from aper import aper (mag, magerr, flux, fluxerr, sky, skyerr, badflag, outstr) = aper(simim, apos[1], apos[0], apr=nucrad_px, exact=True, setskyval=0) fnucmod = int(flux) if not silent: print(' - Model total | nuclear flux [mJy]: ' + str(ftotmod) + ' | ' + str(fnucmod)) plotsize_px = int(1.0 * foi_as / pfov) # --- Measure the background noise from the real observation if obsfits is not None: bg = np.copy(obsim) # bgsize = np.shape(bg) params, _, _ = _get_pointsource(obsim) xpos = params[2] ypos = params[3] bg[int(ypos - 0.5 * plotsize_px):int(ypos + 0.5 * plotsize_px), int(xpos - 0.5 * plotsize_px):int(xpos + 0.5 * plotsize_px)] = 0 if bgstd == 0: bgstd = np.std(bg[bg != 0]) if bgmed == 0: bgmed = np.median(bg[bg != 0]) # plt.imshow(bg, origin='bottom', norm=LogNorm(), cmap='gist_heat') # --- crop the observational image to the requested plot size cim = _crop_image(obsim, box=plotsize_px, cenpos=_get_pointsource(obsim)[0][2:4]) newsize = np.shape(cim) # --- make flux measurements on the nucleus and total ftotobs = int(np.sum(cim - bgmed)) apos = 0.5 * np.array(newsize) (mag, magerr, flux, fluxerr, sky, skyerr, badflag, outstr) = aper(cim, apos[1], apos[0], apr=nucrad_px, exact=True, setskyval=0) fnucobs = int(flux) if not silent: print(' - Observed total | nuclear flux [mJy]: ' + str(ftotobs) + ' | ' + str(fnucobs)) else: cim = None if meastime: print(" - Fluxes measured. Elapsed time: ", time.time() - tstart) # pdb.set_trace() # --- crop the simulated image to the requested plot size params, _, _ = _get_pointsource(simim) csimim = _crop_image(simim, box=plotsize_px, cenpos=_get_pointsource(simim)[0][2:4]) if debug is True: plt.imshow(simim, origin='bottom', cmap='gist_heat', norm=LogNorm()) plt.title('simim') plt.show() print(plotsize_px, np.shape(csimim)) plt.imshow(csimim, origin='bottom', cmap='gist_heat', norm=LogNorm()) plt.title('csimim') plt.show() if meastime: print(" - Obs cropped. Elapsed time: ", time.time() - tstart) # --- generate an artifical noise frame with same properties as in real # image if bgstd > 0: artbg = np.random.normal(scale=bgstd, size=(plotsize_px, plotsize_px)) + bgmed # artbg = 0 # --- apply the artificial background # csimim = csimim/np.max(csimim)*(np.max(cim)-bgmed)+bgmed+artbg csimim = csimim + artbg # --- crop the PSF image to the requested plot size cpsf = _crop_image(psf, box=plotsize_px, cenpos=_get_pointsource(psf)[0][2:4]) # print(bgmed, bgstd, np.std(artbg), np.median(cim), np.median(csimim), # np.std(cim), np.std(csimim), np.max(cim), np.min(cim), np.max(csimim), # np.min(csimim)) if meastime: print(" - PSF cropped. Elapsed time: ", time.time() - tstart) theopfov = theopixsize_as theobox = int(np.round(plotsize_px * pfov / theopfov)) if returncmod: # --- crop the model imae to the requested plot size if framerat > 1.0: theoim_res_0 = _extend_image(theoim, fac=framerat) else: theoim_res_0 = theoim cmod = _crop_image(theoim_res_0, box=theobox, exact=False) # plt.imshow(cmod, origin='bottom', norm=LogNorm(), cmap='gist_heat') if meastime: print(" - Theo cropped. Elapsed time: ", time.time() - tstart) else: cmod = None # --- write out the simulated image as a fits file if not outname: theofitsfile = theofits.split("/")[-1] out_str = theofitsfile.replace("_total.fits", "") out_str = (out_str + "_pa" + pastr + "_dist" + diststr + "_wlen" + wlenstr) if suffix: out_str = out_str + "_" + suffix else: out_str = outname out_str = outfolder + '/' + out_str if writeallfits or writetheofits: fout = out_str + '_mod.fits' theohead["Filter"] = filt theohead["WAVELEN"] = wlen theohead["PFOV"] = theopixsize_as fits.writeto(fout, cmod, theohead, overwrite=True) if saveplot: _simple_image_plot(cmod, fout.replace(".fits", ".png"), log=True) if writeallfits or writesimfits: fout = out_str + '_sim.fits' theohead["PFOV"] = pfov theohead["BUNIT"] = 'mJy' ts = np.shape(simim) theohead["CRPIX1"] = 0.5 * ts[1] theohead["CDELT1"] = pfov theohead["CTYPE1"] = 'arcsec' theohead["CRPIX2"] = 0.5 * ts[0] theohead["CDELT2"] = pfov theohead["CTYPE2"] = 'arcsec' fits.writeto(fout, csimim, theohead, overwrite=True) if saveplot: _simple_image_plot(csimim, fout.replace(".fits", ".png"), log=True) if meastime: print(" - All finished: ", time.time() - tstart) return (cpsf, cmod, cim, csimim, wlen, pfov, theopfov)