def test_centerpoint(self): """Testing finding a centerpoint from a bounding box of locations""" box = [[-93.207783, 44.89076], [-93.003514, 44.89076], [-93.003514, 44.992279], [-93.207783, 44.992279]] average = utils.centerpoint(box) self.assertEqual(average[0], 44.9415195) self.assertEqual(average[1], -93.1056485)
def get_location_from_user_timeline(username, fallback): """ :param username: the string of the twitter username to follow :param fallback: a dict in the form of {'lat': 45.585, 'lng': -95.91, 'name': 'Morris, MN'} containing a fallback in case no location can be found :return: a location dict in the form of {'lat': 45.585, 'lng': -95.91, 'name': 'Morris, MN'} """ api = get_tweepy_api() # gets the 20 most recent tweets from the given profile timeline = api.user_timeline(screen_name=username, include_rts=False, count=20) for tweet in timeline: # if tweet has coordinates (from a smartphone) if tweet.coordinates is not None: loc = dict() loc['lat'] = tweet.coordinates['coordinates'][1] loc['lng'] = tweet.coordinates['coordinates'][0] loc['name'] = tweet.place.full_name logging.debug('Found {0}: {1}, {2}'.format(loc['name'], loc['lat'], loc['lng'])) return loc # if the location is a place, not coordinates elif tweet.place is not None: point = utils.centerpoint(tweet.place.bounding_box.coordinates[0]) loc = dict() loc['lat'] = point[0] loc['lng'] = point[1] loc['name'] = tweet.place.full_name logging.debug('Found the center of bounding box at {0}: {1}, {2}' .format(loc['name'], loc['lat'], loc['lng'])) return loc # fallback to hardcoded location if there is no valid data logging.warning('Could not find tweet with location, falling back to hardcoded location') return fallback
def get_location_from_user_timeline(username, fallback): """ Load the 20 most recent tweets of a given twitter handle and return a models.WeatherLocation object of the most recent location. This function will find a tweet with coordinates or a place, preferring coordinates. If a location is not found in the most recent 20 tweets, the given fallback location will be returned. :type username: str :param username: twitter username to follow :type fallback: models.WeatherLocation :param fallback: a fallback in case no location can be found :return: models.WeatherLocation """ api = get_tweepy_api() # gets the 20 most recent tweets from the given profile try: timeline = api.user_timeline(screen_name=username, include_rts=False, count=20) for tweet in timeline: # if tweet has coordinates (from a smartphone) if tweet.coordinates is not None: lat = tweet.coordinates['coordinates'][1] lng = tweet.coordinates['coordinates'][0] name = CONFIG['variable_location']['unnamed_location_name'] # sometimes a tweet contains a coordinate, but is not in a Twitter place # for example, https://twitter.com/BrianMitchL/status/982664157857271810 has coordinates, but no place if tweet.place is not None: name = tweet.place.full_name logging.debug('Found %s: %f, %f', name, lat, lng) return models.WeatherLocation(lat=lat, lng=lng, name=name) # if the location is a place, not coordinates if tweet.place is not None: point = utils.centerpoint( tweet.place.bounding_box.coordinates[0]) lat = point[0] lng = point[1] name = tweet.place.full_name logging.debug('Found the center of bounding box at %s: %f, %f', name, lat, lng) return models.WeatherLocation(lat=lat, lng=lng, name=name) # fallback to hardcoded location if there is no valid data logging.warning( 'Could not find tweet with location, falling back to hardcoded location' ) return fallback except tweepy.TweepError as err: logging.error(err) logging.warning( 'Could not find tweet with location, falling back to hardcoded location' ) return fallback
def get_location_from_user_timeline(username, fallback): """ Load the 20 most recent tweets of a given twitter handle and return a models.WeatherLocation object of the most recent location. This function will find a tweet with coordinates or a place, preferring coordinates. If a location is not found in the most recent 20 tweets, the given fallback location will be returned. :type username: str :param username: twitter username to follow :type fallback: models.WeatherLocation :param fallback: a fallback in case no location can be found :return: models.WeatherLocation """ api = get_tweepy_api() # gets the 20 most recent tweets from the given profile try: timeline = api.user_timeline(screen_name=username, include_rts=False, count=20) for tweet in timeline: # if tweet has coordinates (from a smartphone) if tweet.coordinates is not None: lat = tweet.coordinates['coordinates'][1] lng = tweet.coordinates['coordinates'][0] name = CONFIG['variable_location']['unnamed_location_name'] # sometimes a tweet contains a coordinate, but is not in a Twitter place # for example, https://twitter.com/BrianMitchL/status/982664157857271810 has coordinates, but no place if tweet.place is not None: name = tweet.place.full_name logging.debug('Found %s: %f, %f', name, lat, lng) return models.WeatherLocation(lat=lat, lng=lng, name=name) # if the location is a place, not coordinates elif tweet.place is not None: point = utils.centerpoint(tweet.place.bounding_box.coordinates[0]) lat = point[0] lng = point[1] name = tweet.place.full_name logging.debug('Found the center of bounding box at %s: %f, %f', name, lat, lng) return models.WeatherLocation(lat=lat, lng=lng, name=name) # fallback to hardcoded location if there is no valid data logging.warning('Could not find tweet with location, falling back to hardcoded location') return fallback except tweepy.TweepError as err: logging.error(err) logging.warning('Could not find tweet with location, falling back to hardcoded location') return fallback
def create_input_datafiles_bumps(rfn=None): """ returns: list of mgsdtasets Didactic case, no input parameters: create the pupil & monochromatic image on appropriate pixel scales. Pupil and image arrays of same size, ready to FT into each other losslessly. For real data you'll need to worry about adjusting sizes to satify this sampling relation between the two planes. For finite bandwidth data image simulation will loop over wavelengths. For coarsely sampled pixels image simulation will need to use finer sampling and rebin to detector pixel sizes. [email protected] Jan 2019 """ mft = matrixDFT.MatrixFourierTransform() pupilradius = 50 pupil = utils.makedisk(250, radius=pupilradius) # D=100 pix, array 250 pix pupilindex = np.where(pupil >= 1) pupilfn = rfn + "__input_pup.fits" fits.writeto(pupilfn, pupil, overwrite=True) mgsdatasets = [] defocus_list = (-12.0, 12.0, -10.0, 10.0, -8.0, 8.0, -6.0, 6.0, -4.0, 4.0, -2.0, 2.0) print(defocus_list) number_of_d_across_D = range( 1, 16) # different aberrations - dia of bump in pupil rippleamp = 1.0 # radians, 1/6.3 waves, about 340nm at 2.12 micron Bump height. bad var name # for a variety of bumps across the pupil: for nwaves in number_of_d_across_D: # preserve var name nwaves from ripple case - bad varname here. pupil = fits.getdata(pupilfn) mgsdataset = [pupilfn] # an mgsdataset starts with the pupil file... rbump = 4.0 * float( pupilradius) / nwaves # sigma of gaussian bump in pupil #print("{:.1e}".format(rbump)) bump = utils.makegauss(250, ctr=(145.0, 145.0), sigma=rbump) # D=100 pix, array 250 pix rbump = 0.5 * float(pupilradius) / nwaves # rad of disk bump in pupil #print("{:.1e}".format(rbump)) bump = utils.makedisk(250, radius=rbump, ctr=(145.0, 145.0)) # D=100 pix, array 250 pix bump = (1.0 / np.sqrt(2)) * bump / bump[pupilindex].std( ) # 0.5 variance aberration, same SR hit ripplephase = rippleamp * bump # bad var name phasefn = rfn + "bump_{0:d}acrossD_peak_{1:.1f}_pha.fits".format( int(nwaves), rippleamp) fits.PrimaryHDU(ripplephase).writeto(phasefn, overwrite=True) mgsdataset.append( phasefn) # an mgsdataset now pupil file, phase abberration file, # Now create images for each defocus in the list # # First a utility array, parabola P2V unity over pupil, zero outside pupil prad = pupilradius # for parabola=unity at edge of active pupil 2% < unity center = utils.centerpoint(pupil.shape[0]) unityP2Vparabola = np.fromfunction( utils.parabola2d, pupil.shape, cx=center[0], cy=center[1]) / (prad * prad) * pupil fits.writeto(rfn + "unityP2Vparabola.fits", unityP2Vparabola, overwrite=True) # sanity check - write it out for defoc in defocus_list: # defoc units are waves, Peak-to-Valley defocusphase = unityP2Vparabola * 2 * np.pi * defoc aberfn = "pup__bump_defoc_{:.1f}wav.fits".format(defoc) fits.writeto(rfn + aberfn, defocusphase, overwrite=True) aberfn = rfn + "pup_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn = rfn + "__input_" + "img_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) aber = defocusphase + ripplephase fits.writeto(aberfn, aber, overwrite=True) imagefield = mft.perform(pupil * np.exp(1j * aber), pupil.shape[0], pupil.shape[0]) image = (imagefield * imagefield.conj()).real fits.writeto(imagfn, image / image.sum(), overwrite=True) mgsdataset.append((defoc, imagfn, aberfn)) mgsdatasets.append(mgsdataset) # Prepare a quicklook at signal in the pairs of defocussed images: side = 2.0 # inches, quicklook at curvatue signal imshow ndefoc = len(defocus_list) // 2 nspatfreq = len(number_of_d_across_D) magnif = 2.0 fig = plt.figure(1, (nspatfreq * magnif, ndefoc * magnif)) grid = ImageGrid( fig, 111, # similar to subplot(111) nrows_ncols=(ndefoc, nspatfreq), # creates 2x2 grid of axes axes_pad=0.02, # pad between axes in inch. ) i = 0 iwav = 0 for nwaves in number_of_d_across_D: ifoc = 0 maxlist = [] for defoc in defocus_list: # defoc units are waves, Peak-to-Valley if defoc > 0: imagfn_pos = rfn + "__input_" + "img_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn_neg = rfn + "__input_" + "img_bump_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, -defoc) datapos = fits.getdata(imagfn_pos).flatten() dataneg = fits.getdata(imagfn_neg).flatten() quicklook = (datapos - dataneg[::-1]).reshape((250, 250)) * ( defoc * defoc) # normalize to equal brightness signal maxlist.append(quicklook.max()) print("max {:.1e}".format(quicklook.max()) ) # print me out and fix the limits for imshow by hand. #fits.writeto(imagfn_pos.replace("img","qlk"), quicklook, overwrite=True) i = iwav + (ndefoc - ifoc - 1) * nspatfreq grid[i].imshow( quicklook, origin='lower', cmap=plt.get_cmap( 'ocean'), # RdBu, gist_rainbow, ocean, none vmin=-3.0e-3, vmax=3.0e-3) # The AxesGrid object work as a list of axes. grid[i].set_xticks([]) grid[i].set_yticks([]) grid[i].text(20, 220, "D/{:d} dia bump".format(int(nwaves + 1)), color='y', weight='bold') grid[i].text(20, 20, "+/-{:d}w PV".format(int(defoc)), color='w', weight='bold') #print('iwav', iwav, 'ifoc', ifoc, 'i:', i) ifoc += 1 iwav += 1 strtop = "Wavefront signal from piston phase bumps of different diameters vs. defocus either side of focus" strbot = "Anand S. 2019, after Dean & Bowers, JOSA A 2003 (figs. 4 & 7)" fig.text(0.02, 0.94, strtop, fontsize=18, weight='bold') fig.text(0.02, 0.05, strbot, fontsize=14) plt.tight_layout() plt.savefig("DeanBowers2003_signal_vs_defocus_bump.png", dpi=150, pad_inches=1.0) plt.show() #print("Unity P-V parabola:", arraystats(unityP2Vparabola)) """ for dataset in mgsdatasets: print("MGS data set: pupilfn, aber, (defoc/PVwaves, imagefn, defoc+aber), (repeats)") for thing in dataset: print("\t", thing) print("") """ return mgsdatasets
def create_input_datafiles(rfn=None): """ returns: list of mgsdtasets pupilfn: name of pupil file Pupil and image data, true (zero mean) phase map (rad) No de-tilting of the thase done. Didactic case, no input parameters: create the pupil & monochromatic image on appropriate pixel scales. Pupil and image arrays of same size, ready to FT into each other losslessly. For real data you'll need to worry about adjusting sizes to satify this sampling relation between the two planes. For finite bandwidth data image simulation will loop over wavelengths. For coarsely sampled pixels image simulation will need to use finer sampling and rebin to detector pixel sizes. [email protected] Jan 2019 """ mft = matrixDFT.MatrixFourierTransform() pupilradius = 50 pupil = utils.makedisk(250, radius=pupilradius) # D=100 pix, array 250 pix pupilfn = rfn + "__input_pup.fits" fits.writeto(pupilfn, pupil, overwrite=True) mgsdatasets = [] dfoc_max = 12 nfoci = 8 # number of defocus steps, in geo prog ffac = pow(10, np.log10(dfoc_max) / nfoci) defocus_list = [] for i in range(nfoci): defocus_list.append(ffac) defocus_list.append(-ffac) ffac *= pow(10, np.log10(dfoc_max) / nfoci) defocus_list.reverse() defocus_list = (-12.0, 12.0, -10.0, 10.0, -8.0, 8.0, -6.0, 6.0, -4.0, 4.0, -2.0, 2.0) print(defocus_list) number_of_waves_across_D = range( 1, 16) # different aberrations - number of waves across pupil print(number_of_waves_across_D) rippleamp = 1.0 # radians, 1/6.3 waves, about 340nm at 2.12 micron ripplepha = 30.0 # degrees, just for fun rippleangle = 15.0 # degrees # for a variety of ripples across the pupil: for nwaves in number_of_waves_across_D: pupil = fits.getdata(pupilfn) mgsdataset = [pupilfn] # an mgsdataset starts with the pupil file... spatialwavelen = 2.0 * pupilradius / nwaves khat = np.array((np.sin(rippleangle * np.pi / 180.0), np.cos(rippleangle * np.pi / 180.0))) # unit vector kwavedata = np.fromfunction(utils.kwave2d, pupil.shape, spatialwavelen=spatialwavelen, center=utils.centerpoint(pupil.shape[0]), offset=ripplepha, khat=khat) ripplephase = pupil * rippleamp * kwavedata #imagefield = ft.perform(pupilarray, fp_size_reselt, npup) # remove this #image_intensity = (imagefield*imagefield.conj()).real # remove this #psf = image_intensity / image_intensity.sum() # total intensity unity # remove this phasefn = rfn + "ripple_{0:d}acrossD_peak_{1:.1f}_pha.fits".format( int(nwaves), rippleamp) fits.PrimaryHDU(ripplephase).writeto(phasefn, overwrite=True) mgsdataset.append( phasefn) # an mgsdataset now pupil file, phase abberration file, # Now create images for each defocus in the list # # First a utility array, parabola P2V unity over pupil, zero outside pupil prad = pupilradius # for parabola=unity at edge of active pupil 2% < unity center = utils.centerpoint(pupil.shape[0]) unityP2Vparabola = np.fromfunction( utils.parabola2d, pupil.shape, cx=center[0], cy=center[1]) / (prad * prad) * pupil fits.writeto(rfn + "unityP2Vparabola.fits", unityP2Vparabola, overwrite=True) # sanity check - write it out for defoc in defocus_list: # defoc units are waves, Peak-to-Valley defocusphase = unityP2Vparabola * 2 * np.pi * defoc aberfn = "pup_defoc_{:.1f}wav.fits".format(defoc) fits.writeto(rfn + aberfn, defocusphase, overwrite=True) aberfn = rfn + "pup_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn = rfn + "__input_" + "img_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) aber = defocusphase + ripplephase #fits.writeto(aberfn, aber, overwrite=True) imagefield = mft.perform(pupil * np.exp(1j * aber), pupil.shape[0], pupil.shape[0]) image = (imagefield * imagefield.conj()).real fits.writeto(imagfn, image / image.sum(), overwrite=True) mgsdataset.append((defoc, imagfn, aberfn)) mgsdatasets.append(mgsdataset) """ phase = de_mean(phase, pupil) # zero mean phase - doesn't change image fits.writeto(rfn+"{:1d}__input_truepha.fits".format(pnum), phase, overwrite=True) mft = matrixDFT.MatrixFourierTransform() imagefield = mft.perform(pupil * np.exp(1j*phase), pupil.shape[0], pupil.shape[0]) image = (imagefield*imagefield.conj()).real fits.writeto(rfn+"{:1d}__input_img.fits".format(pnum), image/image.sum(), overwrite=True) del mft """ # Prepare a quicklook at signal in the pairs of defocussed images: side = 2.0 # inches, quicklook at curvatue signal imshow ndefoc = len(defocus_list) // 2 nspatfreq = len(number_of_waves_across_D) magnif = 2.0 fig = plt.figure(1, (nspatfreq * magnif, ndefoc * magnif)) grid = ImageGrid( fig, 111, # similar to subplot(111) nrows_ncols=(ndefoc, nspatfreq), # creates 2x2 grid of axes axes_pad=0.02, # pad between axes in inch. ) i = 0 iwav = 0 for nwaves in number_of_waves_across_D: ifoc = 0 maxlist = [] for defoc in defocus_list: # defoc units are waves, Peak-to-Valley if defoc > 0: imagfn_pos = rfn + "__input_" + "img_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, defoc) imagfn_neg = rfn + "__input_" + "img_ripple_{0:d}acrossD_peak_{1:.1f}_defoc_{2:.1f}wav.fits".format( int(nwaves), rippleamp, -defoc) datapos = fits.getdata(imagfn_pos).flatten() dataneg = fits.getdata(imagfn_neg).flatten() quicklook = (datapos - dataneg[::-1]).reshape((250, 250)) * ( defoc * defoc) # normalize to equal brightness signal maxlist.append(quicklook.max()) #print("max {:.1e}".format(quicklook.max())) #fits.writeto(imagfn_pos.replace("img","qlk"), quicklook, overwrite=True) i = iwav + (ndefoc - ifoc - 1) * nspatfreq grid[i].imshow( quicklook, origin='lower', cmap=plt.get_cmap( 'ocean'), # RdBu, gist_rainbow, ocean, none vmin=-1.3e-2, vmax=1.3e-2) # The AxesGrid object work as a list of axes. grid[i].set_xticks([]) grid[i].set_yticks([]) grid[i].text(20, 220, "{:d} ripples ax D".format(int(nwaves)), color='y', weight='bold') grid[i].text(20, 20, "+/-{:d}w PV".format(int(defoc)), color='w', weight='bold') ifoc += 1 iwav += 1 strtop = "Wavefront signal from phase ripples across the pupil vs. defocus either side of focus" strbot = "Anand S. 2019, illustrating Dean & Bowers, JOSA A 2003 (figs. 4 & 7)" fig.text(0.02, 0.94, strtop, fontsize=18, weight='bold') fig.text(0.02, 0.05, strbot, fontsize=14) plt.tight_layout() plt.savefig("DeanBowers2003_signal_vs_defocus_ripple.pdf", dpi=150, pad_inches=1.0) plt.show() #print("Unity P-V parabola:", arraystats(unityP2Vparabola)) """ for dataset in mgsdatasets: print("MGS data set: pupilfn, aber, (defoc/PVwaves, imagefn, defoc+aber), (repeats)") for thing in dataset: print("\t", thing) print("") """ return mgsdatasets
def exer6(odir): """ Coronagraph train, no optimization for speed. 2nd order BLC, didactic example, fftlike """ # instantiate an mft object: ft = matrixDFT.MatrixFourierTransform() npup = 250 # Size of all arrays radius = 50.0 # Numerical reselts in DFT setup cf telescope reselts: # reselts of telescope - here its 0.4 reselts per DFT output image pixel if npup=250,radius=50. dftpixel = 2.0 * radius / npup # Jinc first zero in reselts of telescope... firstzero_optical_reselts = 10.0 firstzero_numericalpixels = firstzero_optical_reselts / dftpixel print("Jinc firstzero_numericalpixels", firstzero_numericalpixels) jinc = np.fromfunction(utils.Jinc, (npup,npup), c=utils.centerpoint(npup), scale=firstzero_numericalpixels) fpm_blc2ndorder = 1 - jinc*jinc print("Jinc fpm min = ", fpm_blc2ndorder.min(), "Jinc fpm max = ", fpm_blc2ndorder.max()) # Pupil, Pupilphase, Apodizer, FP intensity, Intensity after FPM, # Lyot intensity, Lyot Stop, Post-Lyot Stop Intensity, Final image. # # Set up optical train for a typical Lyot style or phase mask coronagraph: Cordict = { "Pupil": utils.makedisk(npup, radius=radius), "Pupilphase": None, "Apodizer": None, "FPintensity": None, "FPM": fpm_blc2ndorder, "LyotIntensity": None, "LyotStop": utils.makedisk(npup, radius=41), "PostLyotStopIntensity": None, "FinalImage": None, "ContrastImage": None} # Propagate through the coronagraph train... # Start with perfect incoming plane wave, no aberrations efield = Cordict["Pupil"] # Put in phase aberrations: if Cordict["Pupilphase"] is not None: efield *= np.exp(1j*Cordict["Pupilphase"]) # Apodize the entrance pupil: if Cordict["Apodizer"] is not None: efield *= Cordict["Apodizer"] # PROPAGATE TO FIRST FOCAL PLANE: efield = ft.perform(efield, npup, npup) # Store FPM intensity: Cordict["FPintensity"] = (efield * efield.conj()).real # Save no-Cor efield for normalization of cor image by peak of no-FPM image efield_NC = efield.copy() # Multiply by FPM transmission function # Lyot style - zero in center, phase mask style: zero integral over domain efield *= Cordict["FPM"] # PROPAGATE TO LYOT PLANE: efield_NC = ft.perform(efield_NC, npup, npup) efield = ft.perform(efield, npup, npup) # Save Cor Lyot intensity; Cordict["LyotIntensity"] = (efield * efield.conj()).real # Apply Lyot stop: if Cordict["LyotStop"] is not None: efield_NC *= Cordict["LyotStop"] if Cordict["LyotStop"] is not None: efield *= Cordict["LyotStop"] # Save Cor Lyot intensity after applying Lyot stop; Cordict["PostLyotStopIntensity"] = (efield * efield.conj()).real # PROPAGATE TO FINAL IMAGE PLANE: efield_NC = ft.perform(efield_NC, npup, npup) efield = ft.perform(efield, npup, npup) final_image_intensity_NC = (efield_NC * efield_NC.conj()).real final_image_intensity = (efield * efield.conj()).real Cordict["FinalImage"] = (efield * efield.conj()).real Cordict["ContrastImage"] = (efield * efield.conj()).real / final_image_intensity_NC.max() # Write our coronagraph planes: planenames, cube = corcube(Cordict) # write planemames as fits keywords print(odir+"/ex6_BLC_2ndOrder.fits") fits.PrimaryHDU(cube).writeto(odir+"/ex6_BLC_2ndOrder.fits", overwrite=True) fobj = fits.open(odir+"/ex6_BLC_2ndOrder.fits") fobj[0].header["Pupil"] = 1 fobj[0].header["FPI"] = (2, "focal plane Intensity") fobj[0].header["FPM"] = (3, "focal plane mask") fobj[0].header["LyotIntn"] = (4, "Lyot Intensity") fobj[0].header["LyotStop"] = 5 fobj[0].header["PostLyot"] = (6, "Post Lyot Stop Intensity") fobj[0].header["CorIm"] = (7, "Raw cor image") fobj[0].header["Contrast"] = (8, "Cor image in contrast units") fobj.writeto(odir+"/ex6_BLC_2ndOrder.fits", overwrite=True)