def model_t3amp_uv(tri_uv, ratio, separation, pa, inv_wavl): """ Takes 3 cp uv coords, or a set of them and returns model cps based on contrast ratio and position specified, at some wavelength. tri_uv = array( [[u1, v1], [u2, v2], [u3, v3],] ) shape: [2, 3, ncp, nwavl] contrast, separation, pa all should be len(inv_wavl) or scalar """ uvs = inv_wavl*tri_uv model_t3amp = visamp(uvs[:,0, ...], ratio, mas2rad(separation), np.pi*pa/180.) * \ visamp(uvs[:,1, ...], ratio, mas2rad(separation), np.pi*pa/180.) * \ visamp(uvs[:,2, ...], ratio, mas2rad(separation), np.pi*pa/180.) # Return in deg to match oifits standard return model_t3amp
def model_allvis_uv(tri_uv, vis_uv, ratio, separation, pa, inv_wavl): """ Same as above but returns visibility information too """ model_cps = model_cp_uv(tri_uv, ratio, separation, pa, inv_wavl) uvs = inv_wavl*tri_uv uvs_vis = inv_wavl*vis_uv model_vis = visamp(uvs_vis, ratio, mas2rad(separation), np.pi*pa/180.) return model_cps, model_vis**2
def model_pha_uv(uvs, ratio, separation, pa, inv_wavl): # uvs are size 2, nwavl uvs = inv_wavl*uvs #model_visphi = visphase(uvs, ratio, separation, pa) #model_visamp = visamp(uvs[:,0, ...], ratio, mas2rad(separation), np.pi*pa/180.)*\ # visamp(uvs[:,0, ...], ratio, mas2rad(separation), np.pi*pa/180.)*\ # visamp(uvs[:,0, ...], ratio, mas2rad(separation), np.pi*pa/180.) model_vispha = visphase(uvs, ratio, mas2rad(separation), np.pi*pa/180.) return 180.*model_vispha/np.pi
def set_pscale(self, pscalex_deg=None, pscaley_deg=None): """ Override pixel scale in header """ if pscalex_deg is not None: self.pscalex_deg = pscalex_deg if pscaley_deg is not None: self.pscaley_deg = pscaley_deg self.pscale_mas = 0.5 * (pscalex_deg + pscaley_deg) * (60 * 60 * 1000) self.pscale_rad = utils.mas2rad(self.pscale_mas)
def updatewithheaderinfo(self, ph, sh): """ input: primary header, science header MAST""" # The info4oif_dict will get pickled to disk when we write txt files of results. # That way we don't drag in objects like InstrumentData into code that reads text results # and writes oifits files - a simple built-in dictionary is the only object used in this transfer. info4oif_dict = {} info4oif_dict['telname'] = self.telname info4oif_dict['filt'] = self.filt info4oif_dict['lam_c'] = self.lam_c info4oif_dict['lam_w'] = self.lam_w info4oif_dict['lam_bin'] = self.lam_bin # Target information - 5/21 targname UNKNOWN in nis019 rehearsal data # Name in the proposal always non-trivial, targname still UNKNOWN...: if ph["TARGNAME"] == 'UNKNOWN': objname = ph['TARGPROP'] else: objname = ph[ 'TARGNAME'] # allegedly apt name for archive, standard form # # if target name has confusing-to-astroquery dash self.objname = objname.replace('-', ' ') info4oif_dict['objname'] = self.objname # AB Dor, ab dor, AB DOR, ab dor are all acceptable. # self.ra = ph["TARG_RA"] info4oif_dict['ra'] = self.ra self.dec = ph["TARG_DEC"] info4oif_dict['dec'] = self.dec # / axis 1 DS9 coordinate of the reference pixel (always POS1) # / axis 2 DS9 coordinate of the reference pixel (always POS1) self.crpix1 = sh["CRPIX1"] info4oif_dict['crpix1'] = self.crpix1 self.crpix2 = sh["CRPIX2"] info4oif_dict['crpix2'] = self.crpix2 # need Paul Goudfrooij's table for actual crval[1,2] for true pointing to detector pixel coords (DS9) self.instrument = ph["INSTRUME"] info4oif_dict['instrument'] = self.instrument self.pupil = ph["PUPIL"] info4oif_dict['pupil'] = self.pupil # "ImPlaneIA internal mask name" - oifwriter looks for 'mask'... self.arrname = "jwst_g7s6c" # implaneia internal name - historical info4oif_dict['arrname'] = 'g7s6' # for oif info4oif_dict['mask'] = info4oif_dict[ 'arrname'] # Soulain mask goes into oif arrname # if data was generated on the average pixel scale of the header # then this is the right value that gets read in, and used in fringe fitting pscalex_deg, pscaley_deg = self.degrees_per_pixel(sh) # info4oif_dict['pscalex_deg'] = pscalex_deg info4oif_dict['pscaley_deg'] = pscaley_deg # Whatever we did set is averaged for isotropic pixel scale here self.pscale_mas = 0.5 * (pscalex_deg + pscaley_deg) * (60 * 60 * 1000) \ info4oif_dict['pscale_mas'] = self.pscale_mas self.pscale_rad = utils.mas2rad(self.pscale_mas) info4oif_dict['pscale_rad'] = self.pscale_rad self.mask = NRM_mask_definitions( maskname=self.arrname, chooseholes=self.chooseholes, holeshape=self.holeshape) # for STAtions x y in oifs self.date = ph["DATE-OBS"] + "T" + ph["TIME-OBS"] info4oif_dict['date'] = self.date datestr = ph["DATE-OBS"] self.year = datestr[:4] info4oif_dict['year'] = self.year self.month = datestr[5:7] info4oif_dict['month'] = self.month self.day = datestr[8:10] info4oif_dict['day'] = self.day self.parangh = sh["ROLL_REF"] info4oif_dict['parangh'] = self.parangh self.pa = sh["PA_V3"] info4oif_dict['pa'] = self.pa self.vparity = sh["VPARITY"] info4oif_dict['vparity'] = self.vparity # An INTegration is NGROUPS "frames", not relevant here but context info. # 2d => "cal" file combines all INTegrations (ramps) # 3d=> "calints" file is a cube of all INTegrations (ramps) if sh["NAXIS"] == 2: # all INTegrations or 'ramps' self.itime = ph["EFFINTTM"] * ph["NINTS"] info4oif_dict['itime'] = self.itime elif sh["NAXIS"] == 3: # each slice is one INTegration or 'ramp' self.itime = ph["EFFINTTM"] info4oif_dict['itime'] = self.itime np.set_printoptions(precision=5, suppress=True, linewidth=160, formatter={'float': lambda x: "%10.5f," % x}) self.v3i_yang = sh[ 'V3I_YANG'] # Angle from V3 axis to Ideal y axis (deg) # rotate mask hole center coords by PAV3 # RAC 2021 ctrs_sky = self.mast2sky() oifctrs = np.zeros(self.mask.ctrs.shape) oifctrs[:, 0] = ctrs_sky[:, 1].copy() * -1 oifctrs[:, 1] = ctrs_sky[:, 0].copy() * -1 info4oif_dict[ 'ctrs_eqt'] = oifctrs # mask centers rotated by PAV3 (equatorial coords) info4oif_dict[ 'ctrs_inst'] = self.mask.ctrs # as-built instrument mask centers info4oif_dict['hdia'] = self.mask.hdia info4oif_dict[ 'nslices'] = self.nwav # nwav: number of image slices or IFU cube slices - AMI is imager self.info4oif_dict = info4oif_dict # save it when writing extracted observables txt