def parse_aperture(aperture_name): ''' Return [image mask, pupil mask, fov_pixels, trim_fov_pixels, pixelscale] ''' aperture_keys = ['mask210r','mask335r','mask430r','masklwb','maskswb', 'fqpm1065','fqpm1140','fqpm1550','lyot2300'] assert aperture_name in aperture_keys, \ 'Aperture {} not recognized! Must be one of {}'.format(aperture_name, aperture_keys) nc = webbpsf.NIRCam() miri = webbpsf.MIRI() aperture_dict = { 'mask210r' : ['MASK210R','CIRCLYOT', 101, None, nc._pixelscale_short], 'mask335r' : ['MASK335R','CIRCLYOT', 101, None, nc._pixelscale_long], 'mask430r' : ['MASK430R','CIRCLYOT', 101, None, nc._pixelscale_long], 'masklwb' : ['MASKLWB','WEDGELYOT', 351, 101, nc._pixelscale_long], 'maskswb' : ['MASKSWB','WEDGELYOT', 351, 101, nc._pixelscale_short], 'fqpm1065' : ['FQPM1065','MASKFQPM', 81, None, miri.pixelscale], 'fqpm1140' : ['FQPM1140','MASKFQPM', 81, None, miri.pixelscale], 'fqpm1550' : ['FQPM1550','MASKFQPM', 81, None, miri.pixelscale], 'lyot2300' : ['LYOT2300','MASKLYOT', 81, None, miri.pixelscale] } return aperture_dict[aperture_name]
def get_psf( wave, instrument, aperture_name, source_offset=(0, 0), otf_options=None, full_aperture=None): #Make the instrument and determine the mode if instrument.upper() == 'NIRCAM': ins = webbpsf.NIRCam() # WebbPSF needs to know the filter to select the optimal # offset for the bar masks. The filter is not passed into # get_psf but is stored in the full aperture name in self._psfs if aperture_name in ['masklwb', 'maskswb']: # Everything after the aperture name is the filter name. full_aperture = self._psfs[0]['aperture_name'] fname = full_aperture[full_aperture.find(aperture_name) + len(aperture_name):] ins.filter = fname if wave > 2.5: # need to toggle to LW detector. ins.detector='A5' ins.pixelscale = ins._pixelscale_long elif instrument.upper() == 'MIRI': ins = webbpsf.MIRI() else: raise ValueError('Only NIRCam and MIRI are supported instruments!') image_mask, pupil_mask, fov_pixels, trim_fov_pixels, pix_scl = parse_aperture(aperture_name) ins.image_mask = image_mask ins.pupil_mask = pupil_mask # Apply any extra options if specified by the user: for key in options.on_the_fly_webbpsf_options: ins.options[key] = options.on_the_fly_webbpsf_options[key] if options.on_the_fly_webbpsf_opd is not None: ins.pupilopd = options.on_the_fly_webbpsf_opd #get offset ins.options['source_offset_r'] = source_offset[0] ins.options['source_offset_theta'] = source_offset[1] ins.options['output_mode'] = 'oversampled' ins.options['parity'] = 'odd' psf_result = calc_psf_and_center(ins, wave, source_offset[0], source_offset[1], 3, pix_scl, fov_pixels, trim_fov_pixels=trim_fov_pixels) pix_scl = psf_result[0].header['PIXELSCL'] upsamp = psf_result[0].header['OVERSAMP'] diff_limit = psf_result[0].header['DIFFLMT'] psf = psf_result[0].data psf = { 'int': psf, 'wave': wave, 'pix_scl': pix_scl, 'diff_limit': diff_limit, 'upsamp': upsamp, 'instrument': instrument, 'aperture_name': aperture_name, 'source_offset': source_offset } return psf
def main(): # save the figures figdir = 'Figures' # just listing the wide filters nircam_bandpasses = 'F070W,F090W,F115W,F150W,F200W,F277W,F356W,F444W' miri_bandpasses = 'F560W,F770W,F1000W,F1130W,F1280W,F1500W,F1800W,F2100W,F2550W' nircam_bandpasses = nircam_bandpasses.split(',') miri_bandpasses = miri_bandpasses.split(',') # configure the instruments nircam = W.NIRCam() miri = W.MIRI() # load the bandpasses bandpasses = {} for bp in nircam_bandpasses: nircam.filter = bp bpmodel = nircam._getSynphotBandpass(nircam.filter) bandpasses[bp] = bpmodel for bp in miri_bandpasses: miri.filter = bp bpmodel = miri._getSynphotBandpass(miri.filter) bandpasses[bp] = bpmodel # we just need a couple of bandpasses for testing use_bandpasses = nircam_bandpasses + miri_bandpasses[0:3] # init the kilonova model and create some arrays to store output kn = Kilonova() # do this for a few distances for j, dmpc in enumerate(DISTANCE): time = [] rfphase = [] flux = {} if j == 0: fig = plt.figure(figsize=(8, 15)) ax = fig.add_subplot(1, 1, 1) for i, phase in enumerate(kn._times): # get the kilonova model and spectrum for this phase and distance lam, flam = kn.get_model(phase) lamz, fnorm = kn.get_norm_model(phase, dmpc) name = 'kilonova_{:+.2f}'.format(phase) spec = S.ArraySpectrum(wave=lamz, flux=fnorm, waveunits='angstrom', fluxunits='flam', name=name) # get synthetic mags in each passband for bp in use_bandpasses: passband = bandpasses[bp] obs = S.Observation(spec, passband, force='taper') try: mag = obs.effstim('abmag') except ValueError as e: mag = np.nan thispb = flux.get(bp) if thispb is None: thispb = [ mag, ] else: thispb.append(mag) flux[bp] = thispb # keep a track of rest-frame phase + observer frame days (should make much difference at these distances) dist = c.Distance(dmpc * u.megaparsec) z = dist.z rfphase.append(phase) time.append(phase * (1. + z)) # write output photometry tables if i % 5 == 0: # convert flam -> fnu -> mJy (YUCK) lam_micron = lamz * ANGSTROM_TO_MICRON f_nu = (((lamz * ANGSTROM_TO_CM)**2.) / SPEED_OF_LIGHT) * fnorm / ANGSTROM_TO_MICRON f_mjy = f_nu * FNU_TO_MJY table_name = 'Tables/kilonova_orig_{}Mpc_p{:+.2f}.txt'.format( dmpc, phase) this_spec = at.Table([lam_micron, f_mjy], names=['wave_micron', 'flux_mjy']) this_spec.sort('wave_micron') this_spec.write(table_name, format='ascii.fixed_width', delimiter=' ', overwrite='True') # plot output spectral sequence if j == 0: fplot = flam / flam.mean() ax.plot(lam * ANGSTROM_TO_MICRON, fplot + 180 - i, 'k-') # finalize spectral sequence plot if j == 0: ax.tick_params(axis='both', which='major', labelsize='large') ax.set_xlabel(r'Rest Wavelength ($\mu$m)', fontsize='xx-large') ax.set_ylabel(r'Relative F$_{\lambda}$ + constant', fontsize='xx-large') ax.set_xlim(0.5, 9.5) fig.tight_layout(rect=[0, 0, 1, 0.96]) plt.savefig('{}/kilonova_spec.pdf'.format(figdir)) plt.close(fig) # dump output mag tables arrays = [ rfphase, time, ] + [flux[bp] for bp in use_bandpasses] names = ['rfphase', 'ofphase'] + [bp for bp in use_bandpasses] out = at.Table(arrays, names=names) out.write('Tables/kilonova_phottable_{}Mpc.txt'.format(dmpc), delimiter=' ', format='ascii.fixed_width', overwrite=True) # plot up the lightcurves npbs = len(use_bandpasses) color = iter(plt.cm.tab20(np.linspace(0, 1, npbs))) with PdfPages('{}/kilonova_phot_{}Mpc.pdf'.format(figdir, dmpc)) as pdf: fig = plt.figure(figsize=(10, 10)) for i, bp in enumerate(use_bandpasses): # save four passbands per page if i % 4 == 0 and i > 0: fig.suptitle( 'Kilonova Synthetic Photometry {} Mpc'.format(dmpc), fontsize='xx-large') fig.tight_layout(rect=[0, 0, 1, 0.93]) pdf.savefig(fig) plt.close(fig) fig = plt.figure(figsize=(10, 10)) # plot up a passband ax = fig.add_subplot(2, 2, i % 4 + 1) thiscol = next(color) ax.plot(out['ofphase'], out[bp], marker='o', linestyle='-', lw=0.5, label=bp, color=thiscol) ax.tick_params(axis='both', which='major', labelsize='large') ax.set_ylabel('{} (AB mag)'.format(bp), fontsize='xx-large') ax.set_xlabel('Observer-frame Phase (Days)', fontsize='xx-large') ax.legend(loc='upper right', frameon=False) ymin, ymax = ax.get_ylim() ax.set_ylim((ymax, ymin)) # finalize lightcurve plot if i == npbs - 1: fig.suptitle( 'Kilonova Synthetic Photometry {} Mpc'.format(dmpc), fontsize='xx-large') fig.tight_layout(rect=[0, 0, 1, 0.93]) pdf.savefig(fig) plt.close(fig)
def set_sim_params(args): #logging.basicConfig(level=logging.INFO, format='%(name)-12s: %(levelname)-8s %(message)s',) print "WebbPSF",pkg_resources.get_distribution("webbpsf").version," Poppy",pkg_resources.get_distribution("poppy").version #webbpsf.setup_logging(level='ERROR') nruns= args.nruns # filt = args.f.upper() #e.g. F430M mask_coron=args.mask.upper() #e.g. MASK430R pupil_stop=args.stop.upper() #e.g. CIRCLYOT instr=args.I.upper() if instr=='NIRCAM': lambda0=float(filt[1:4])/100 elif instr=='MIRI': lambda0=float(filt[1:5])/100 jitter= args.jitter grid_step=args.gstep gridpoints=args.gnpts side=int(np.sqrt(gridpoints)) max_step=np.floor(side/2) rms= args.rms fovarcsec = args.fov #default 7.04 #fovpixels = 64 sigmaTA = 4.7 sigmaFSM= 2.0 if instr=='NIRCAM': img=webbpsf.NIRCam() elif instr=='MIRI': img=webbpsf.MIRI() if filt not in img.filter_list: if instr == 'MIRI' : print "\nFilter "+mask_coron+" not available. Select from: ",[f for f in img.filter_list if "C" in f[-1]],'\n' if instr == 'NIRCAM': print "\nFilter "+mask_coron+" not available. Select from: ",img.filter_list,'\n' sys.exit() if mask_coron not in img.image_mask_list: print "\nCoronagraphic mask "+mask_coron+" not available. Select from: ",img.image_mask_list,'\n' sys.exit() if pupil_stop not in img.pupil_mask_list[:2]: print "\nPupil mask "+pupil_stop+" not available. Select from: ",img.pupil_mask_list[:2],'\n' sys.exit() opd_rms = [int(img.opd_list[i][-8:-5]) for i in xrange(len(img.opd_list))] if rms not in opd_rms: print "\nOPD rms ("+str(rms)+") not available. Select from: ",opd_rms,'\n' sys.exit() if instr=='NIRCAM' and args.noopd==False: opd='/Users/lajoie/WebbPSF/webbpsf-data/NIRCam/OPD/OPD_RevV_nircam_'+str(rms)+'.fits' if instr=='MIRI' and args.noopd==False: opd='/Users/lajoie/WebbPSF/webbpsf-data/MIRI/OPD/OPD_RevV_miri_'+str(rms)+'.fits' img.filter=filt img._rotation=0. img.options["output_mode"]='detector sampled' if args.noopd==False: img.pupilopd = (opd, 0) #select FITS extension for OPD print opd if instr=='NIRCAM': outdir='./Results'+'/'+instr+'/'+filt+'_'+mask_coron+'/DitherStep'+str(int(grid_step))+'/Jitter'+str(int(jitter))+'/rms'+str(rms)+'nm/' else: outdir='./Results'+'/'+instr+'/'+filt+'/DitherStep'+str(int(grid_step))+'/Jitter'+str(int(jitter))+'/rms'+str(rms)+'nm/' if gridpoints != 9: raw_input(" *** generating grids of %i points: ENTER to continue " %gridpoints) outdir = outdir[:-1]+"_Grid_%i_pts/" %gridpoints if not os.path.exists(outdir): os.makedirs(outdir) x0,y0 = get_source_offset(lambda0, filt, mask_coron) if np.abs(x0) > fovarcsec/2: print "\n optimal bar occulter offset out of FOV. Please fix FOV in code (fovarcsec).\n x_offset=%f Total fov=%f\n" %(x0,fovarcsec) sys.exit() generate_PSF(img, outdir, nruns, x0, y0, grid_step, side, max_step, sigmaTA, sigmaFSM, mask_coron, pupil_stop, lambda0, jitter, rms, fovarcsec) return
def resetPSF(self): import webbpsf if self.filter not in self.FILTERS: raise ValueError("Filter %s is not a valid MIRI filter" % (self.filter)) have_psf = False if os.path.exists(os.path.join(self.out_path, "psf_cache")): if os.path.exists( os.path.join( self.out_path, "psf_cache", "psf_{}_{}_{}.fits".format("MIRI", self.filter, self.oversample))): with pyfits.open( os.path.join( self.out_path, "psf_cache", "psf_{}_{}_{}.fits".format( "MIRI", self.filter, self.oversample))) as psf: if psf[0].header['VERSION'] >= webbpsf.__version__ and ( self.psf_commands is None or self.psf_commands == ''): self.psf = AstroImage(data=psf[0].data, detname="MIRI {} PSF".format( self.filter), logger=self.logger) have_psf = True if not have_psf: base_state = self.getState() self.updateState( base_state + "<br /><span class='indented'>Generating PSF</span>") self._log("info", "Creating PSF") ins = webbpsf.MIRI() self._log("info", "Setting PSF attributes") if self.psf_commands is not None and self.psf_commands != '': for attribute, value in self.psf_commands.iteritems(): self._log( "info", "Setting PSF attribute {} to {}".format( attribute, value)) setattr(ins, attribute, value) self._log("info", "Setting PSF filter to '{}'".format(self.filter)) ins.filter = self.filter max_safe_size = int( np.floor(30. * self.PHOTPLAM[self.filter] / (2. * self.SCALE[0]))) max_ins_size = max(self.DETECTOR_SIZE) * self.oversample max_conv_size = int( np.floor(self.convolve_size / (2 * self.oversample))) psf_size = min(max_safe_size, max_ins_size, max_conv_size) self._log( "info", "PSF choosing between {}, {}, and {}, chose {}".format( max_safe_size, max_ins_size, max_conv_size, psf_size)) psf = ins.calcPSF(oversample=self.oversample, fov_pixels=psf_size) psf[0].header['VERSION'] = webbpsf.__version__ if os.path.exists(os.path.join(self.out_path, "psf_cache")): dest = os.path.join( self.out_path, "psf_cache", "psf_{}_{}_{}.fits".format("MIRI", self.filter, self.oversample)) pyfits.writeto(dest, psf[0].data, header=psf[0].header, overwrite=True) self.psf = AstroImage(data=psf[0].data, detname="MIRI %s PSF" % (self.filter), logger=self.logger) self.updateState(base_state)
# Add mode keyword to header hdulist = pf.open(longname, mode='update') prihdr = hdulist[0].header prihdr['APERTURE'] = ( aperture, 'The observing aperture within the instrument FOV') hdulist.flush() hdulist.close() doMIRI = False doNIRSpec = False doNIRCam = False doNIRISS = True if doMIRI: MIRI_FQPM = wp.MIRI() MIRI_FQPM.pupil_mask = 'MASKFQPM' MIRI_FQPM.image_mask = 'FQPM1065' psf_suite(nw=10, wmin=9.5, wmax=11.5, instrument=MIRI_FQPM, outname='MIRI_FQPM1065', fov_arcsec=12, aperture='FQPM1065') MIRI_FQPM.image_mask = 'FQPM1140' psf_suite(nw=10, wmin=10.5, wmax=12.5, instrument=MIRI_FQPM, outname='MIRI_FQPM1140',