def project(self, cube, cutoff): # TODO Make all this with astropy units from the call functions table = Table(names=("Line Code", "Mol", "Ch Name", "Rest Freq", "Obs Freq", "Intensity"),dtype=('S80','S40','S40','f8','f8','f8')) dba = db.lineDB(self.dbpath) # Maybe we can have an always open DB dba.connect() fwin = axis_range(cube.data,cube.wcs,axis=2) # print "fwin",fwin cor_fwin = np.array(fwin/(1 + self.z))*u.Hz cor_fwin = cor_fwin.to(u.MHz).value # print "cor_fwin",cor_fwin counter = 0 used = False for mol in self.mol_list: # For each molecule specified in the dictionary # load its spectral lines linlist = dba.getSpeciesLines(mol, cor_fwin[0], cor_fwin[1]) # Selected spectral lines for this molecule # rinte = INTEN_VALUES[0] # for j in range(len(INTEN_GROUP)): # TODO: baaad python, try a more pythonic way.. # if mol in INTEN_GROUP[j]: # rinte = INTEN_VALUES[j] abun = random.uniform(self.mol_list[mol][0], self.mol_list[mol][1])*u.Jy/u.beam for lin in linlist: counter += 1 trans_temp = lin[5]*u.K inten = lin[4] if inten != 0: inten = 10 ** inten flux = np.exp(-abs(trans_temp - self.temp) / trans_temp) * inten * abun flux = flux.value * u.Jy/u.beam # print trans_temp, self.temp, flux freq = (1 + self.z) * lin[3]*u.MHz # TODO: astropy # print flux, cutoff if flux < cutoff: # TODO: astropy units! log.info(' - Discarding ' + str(lin[1]) + ' at freq=' + str(freq) + '('+str(lin[3]*u.MHz)+') because I='+str(flux)+' < '+str(cutoff)) continue if self._draw(cube,flux,freq,cutoff)==False: log.info(' - Discarding ' + str(lin[1]) + ' at freq=' + str(freq) + '('+str(lin[3]*u.MHz)+') because it is too thin for the resolution') continue log.info(' - Projecting ' + str(lin[2]) + ' (' + str(lin[1]) + ') at freq=' + str(freq) + '('+str(lin[3]*u.MHz)+') intens='+ str(flux)) used = True # add line to the table. # TODO: modificar ultimo valor, que corresponde a la intensidad. table.add_row((self.comp_name + "-l" + str(counter), mol, str(lin[2]), str(lin[3]),freq, flux)) dba.disconnect() if not used: return None return table
def _gen_sources_table(self): """ Will generate a resumed table of each component. :return: an Astropy Table. """ table = Table(names=("Source Name", "Comp ID", "Model", "Alpha", "Delta", "Redshift", "Radial Vel"), dtype=('S80', 'S80', 'S40', 'f8', 'f8', 'f8', 'f8')) for source in self.sources: for component in self.sources[source].comp: table.add_row( (self.sources[source].name, component.comp_name, component.get_model_name(), component.pos[0].value + component.offset[1].value, component.pos[1].value + component.offset[0].value, component.get_redshift().value, component.get_velocity().value)) return table
def sdss_check(x, y): """ Check whether stars are in the SDSS catalogue. This function accepts either a single x and y coordinate, or an array of each. """ w = WCS('a100.fits') sfilt = [] # Check which format x and y are given in. if not (isinstance(x, (np.ndarray, list, float, int)) & isinstance(y, (np.ndarray, list, float, int)) & (np.shape(x) == np.shape(y))): print('Error: Need a set of pixel coordinates.') print(' X and Y must have same non-zero size.') raise TypeError x = [x] if (np.shape(x) == ()) else x y = [y] if (np.shape(y) == ()) else y lon, lat = w.all_pix2world(x, y, 1) pos = coords.SkyCoord(lon, lat, unit="deg") if len(pos) == 1: pos = [pos] table_fields = ['RA', 'Dec', 'psfMag_r', 'psfMagErr_r', 'psffwhm_r', 'nDetect', 'X_pixel', 'Y_pixel'] sfilt = AstroTable(names=table_fields) for index, position in enumerate(pos): sfull = SDSS.query_region(position, radius='1arcsec', data_release=13, photoobj_fields=table_fields[:-2]) try: sline = (sfull[np.where((sfull['nDetect'] > 0) & (sfull['psfMag_r'] > -99))[0]][0]) slist = [sl for sl in sline] slist.append(x[index]) slist.append(y[index]) sfilt.add_row(slist) except (TypeError, IndexError): print("Star at " + str(position)[39:-1] + " not found :-(.") slist = np.zeros(len(table_fields)) slist[-2:] = x[index], y[index] sfilt.add_row(slist) return sfilt
def usno_check(x, y): """ Check whether stars are in the USNO catalogue. This function accepts either a single x and y coordinate, or an array of each. """ w = WCS('a100.fits') sfilt = [] # Check which format x and y are given in. if not (isinstance(x, (np.ndarray, list, float, int)) & isinstance(y, (np.ndarray, list, float, int)) & (np.shape(x) == np.shape(y))): print('Error: Need a set of pixel coordinates.') print(' X and Y must have same non-zero size.') raise TypeError x = [x] if (np.shape(x) == ()) else x y = [y] if (np.shape(y) == ()) else y lon, lat = w.all_pix2world(x, y, 1) pos = coords.SkyCoord(lon, lat, unit="deg") if len(pos) == 1: pos = [pos] table_fields = ['RAJ2000', 'DEJ2000', 'R2mag', 'Ndet', 'X_pixel', 'Y_pixel'] sfilt = AstroTable(names=table_fields) vizier = Vizier(columns=table_fields, catalog="I/284") for index, position in enumerate(pos): try: sfull = vizier.query_region(position, radius='2s')[0][table_fields[:-2]] sline = (sfull[np.where((sfull['Ndet'] > 0) & (sfull['R2mag'] > -99))[0]][0]) slist = [sl for sl in sline] slist.append(x[index]) slist.append(y[index]) sfilt.add_row(slist) except TypeError: print("Star at " + str(position)[39:-1] + " not found in USNO :-(.") slist = np.zeros(len(table_fields)) slist[-2:] = x[index], y[index] sfilt.add_row(slist) except IndexError: print("Star at " + str(position)[39:-1] + " has no USNO magnitude :-(.") slist = np.zeros(len(table_fields)) slist[-2:] = x[index], y[index] sfilt.add_row(slist) return sfilt
class ImageCreator(object): TRANSMISSION_MAP_IDEAL = 'TRANSMISSION_IDEAL' TRANSMISSION_MAP_REALISTIC = 'TRANSMISSION_REALISTIC' SKY_NO = 'SKY_NO' SKY_IDEAL = 'SKY_IDEAL' SKY_REALISTIC = 'SKY_REALISTIC' def __init__(self, shape, detectorSpecifications=None): self._shape = shape self._usePoissonNoise = False self._seed = check_random_state(12345) self.resetTable() if detectorSpecifications is None: detectorSpecifications = IdealDetector(self._shape) self.setDetector(detectorSpecifications) self.setExposureTime(1.0) self._skyPhotonsPerPxPerSecond = 100. self.setTransmissionMap(self.TRANSMISSION_MAP_IDEAL) self.setSkyBackground(self.SKY_NO) @property def shape(self): return self._shape def setDetector(self, detectorSpecifications): self._detectorSpecifications = detectorSpecifications def detector(self): """ Return the detector specifications Returns: detector (DetectorSpecification): the detector characteristics used to create the image """ return self._detectorSpecifications def setExposureTime(self, exposureTimeInSeconds): """Set the exposure time of the image. Args: exposureTimeInSeconds (float) : set the exposure time in seconds. """ self._exposureTimeInSeconds = exposureTimeInSeconds self.detector().setExposureTime(exposureTimeInSeconds) def exposureTimeInSec(self): return self._exposureTimeInSeconds def usePoissonNoise(self, trueOrFalse): self._usePoissonNoise = trueOrFalse def createGaussianImage(self, posX, posY, fluxInPhotons, stdX, stdY=None): table = Table() table['x_mean'] = [posX] table['y_mean'] = [posY] table['x_stddev'] = [stdX] if stdY is None: table['y_stddev'] = [stdX] else: table['y_stddev'] = [stdY] table['flux'] = [fluxInPhotons] self._table = table ima = np.zeros(self._shape) ima += make_gaussian_sources_image(self._shape, self._table) if self._usePoissonNoise: ima = self._addShotNoise(ima) return ima # return self.createImage() def createIntegratedGaussianPRFImage(self, sigma, flux, x0, y0): table = Table() table['sigma'] = [sigma] table['flux'] = [flux] table['x_0'] = [x0] table['y_0'] = [y0] self._table = table ima = make_model_sources_image(self._shape, IntegratedGaussianPRF(), table) return ima def createMoffatImage(self, posX, posY, gamma, alpha, peak): table = Table() table['x_0'] = [posX] table['y_0'] = [posY] table['gamma'] = [gamma] table['alpha'] = [alpha] table['amplitude'] = [peak] self._table = table return self.createImage() def createMultipleIntegratedGaussianPRFImage(self, stddevRange=[2., 3], fluxInPhotons=[1000., 10000], nStars=100): xMean = np.random.uniform(1, self._shape[1] - 1, nStars) yMean = np.random.uniform(1, self._shape[0] - 1, nStars) sx = np.random.uniform(stddevRange[0], stddevRange[1], nStars) flux = np.random.uniform(fluxInPhotons[0], fluxInPhotons[1], nStars) self._table = Table() self._table['x_0'] = xMean self._table['y_0'] = yMean self._table['sigma'] = sx self._table['flux'] = flux ima = make_model_sources_image(self._shape, IntegratedGaussianPRF(), self._table) return ima def createMultipleGaussian(self, stddevXRange=[2., 3], stddevYRange=None, fluxInPhotons=[1000., 10000], nStars=100, withSeed=False): if withSeed is True: np.random.seed(seed=12345) xMean = np.random.uniform(1, self._shape[1] - 1, nStars) yMean = np.random.uniform(1, self._shape[0] - 1, nStars) sx = np.random.uniform(stddevXRange[0], stddevXRange[1], nStars) if stddevYRange is None: sy = sx else: sy = np.random.uniform(stddevYRange[0], stddevYRange[1], nStars) theta = np.arctan2(yMean - 0.5 * self._shape[0], xMean - 0.5 * self._shape[1]) - np.pi / 2 flux = np.random.uniform(fluxInPhotons[0], fluxInPhotons[1], nStars) self._table = Table() self._table['x_mean'] = xMean self._table['y_mean'] = yMean self._table['x_stddev'] = sx self._table['y_stddev'] = sy self._table['theta'] = theta self._table['flux'] = flux ima = self.createImage() return ima def createMultipleGaussianInCentralRegion(self, stddevXRange=[2., 3], stddevYRange=None, fluxInPhotons=[1000., 10000], nStars=100): xMean = np.random.uniform(self._shape[1] / 4, self._shape[1] - self._shape[1] / 4, nStars) yMean = np.random.uniform(self._shape[0] / 4, self._shape[0] - self._shape[0] / 4, nStars) sx = np.random.uniform(stddevXRange[0], stddevXRange[1], nStars) if stddevYRange is None: sy = sx else: sy = np.random.uniform(stddevYRange[0], stddevYRange[1], nStars) theta = np.arctan2(yMean - 0.5 * self._shape[0], xMean - 0.5 * self._shape[1]) - np.pi / 2 flux = np.random.uniform(fluxInPhotons[0], fluxInPhotons[1], nStars) self._table = Table() self._table['x_mean'] = xMean self._table['y_mean'] = yMean self._table['x_stddev'] = sx self._table['y_stddev'] = sy self._table['theta'] = theta self._table['flux'] = flux ima = self.createImage() return ima def createMultipleGaussianIntegerCentroids(self, stddevXRange=[2., 3], stddevYRange=None, fluxInPhotons=[1000., 10000], nStars=100): xMean = np.random.randint(1, self._shape[1] - 1, nStars) yMean = np.random.randint(1, self._shape[0] - 1, nStars) sx = np.random.uniform(stddevXRange[0], stddevXRange[1], nStars) if stddevYRange is None: sy = sx else: sy = np.random.uniform(stddevYRange[0], stddevYRange[1], nStars) theta = np.arctan2(yMean - 0.5 * self._shape[0], xMean - 0.5 * self._shape[1]) - np.pi / 2 flux = np.random.uniform(fluxInPhotons[0], fluxInPhotons[1], nStars) self._table = Table() self._table['x_mean'] = xMean self._table['y_mean'] = yMean self._table['x_stddev'] = sx self._table['y_stddev'] = sy self._table['theta'] = theta self._table['flux'] = flux ima = self.createImage() return ima def addGaussianSource(self, posX, posY, stdX, stdY, theta, fluxInPhotons): self._table.add_row([posX, posY, stdX, stdY, theta, fluxInPhotons]) def resetTable(self): self._table = Table(names=('x_mean', 'y_mean', 'x_stddev', 'y_stddev', 'theta', 'flux')) def createImage(self): """createImage Create source images. Add transmission and differential sensitivity effects. Add shot noise, if asked. Convert photons to ADU using the detector model, accounting for quantum efficiency, dark current, bias, gain, clipping. """ sourceImage = self._createSourcesImage() image = self._addSensitivityAndVignetting(sourceImage) if self._usePoissonNoise: image = self._addShotNoise(image) return self.detector().photons2Adu(image) def _createSourcesImage(self): image = np.zeros(self._shape) if self._table is not None: image += make_gaussian_sources_image(self._shape, self._table) return image + self._skyImage * self.exposureTimeInSec() def _realisticTransmissionMap(self): ima = np.ones(self._shape) y, x = np.indices(ima.shape) vign_model = Gaussian2D(amplitude=1, x_mean=self._shape[1] / 2, y_mean=self._shape[0] / 2, x_stddev=2 * self._shape[1], y_stddev=2 * self._shape[0]) vign_im = vign_model(x, y) ima *= vign_im return ima def _realisticSky(self): ima = self._idealSky() y, x = np.indices(ima.shape) def f(x, y, ampl): return y * ampl / y.max() + x * ampl * 0.1 / x.max() ima += f(x, y, ima.mean() * 0.1) return ima def _idealSky(self): sky = np.ones(self._shape) * self._skyPhotonsPerPxPerSecond return sky def setTransmissionMap(self, nameOrMap): """setTransmissionMap Args: nameOrMap (str or ndarray): if nameOrMap is a string the corresponding predefined transmission map is used. Available names are %s (corresponding to an uniform transmission of 1) and and %s (corresponding to a vignetting transmission following a gaussian shape). If nameOrMap is a numpy array, that array is used. Raises: KeyError if nameOrMap is a string not corresponding to any predefined transmission map. """ % (self.TRANSMISSION_MAP_IDEAL, self.TRANSMISSION_MAP_REALISTIC) if isinstance(nameOrMap, str): if nameOrMap == self.TRANSMISSION_MAP_IDEAL: transmissionMap = np.ones(self._shape) elif nameOrMap == \ self.TRANSMISSION_MAP_REALISTIC: transmissionMap = self._realisticTransmissionMap() else: raise KeyError('Unknown transmission map %s' % nameOrMap) self._transmissionMap = transmissionMap else: self._transmissionMap = nameOrMap def setSkyBackground(self, nameOrMap): """setSkyBackground Args: nameOrMap (str or ndarray): if nameOrMap is a string the corresponding predefined sky background is used. Available names are %s (no sky background), %s (corresponding to a uniform background of 100 photons/px/sec) and and %s (adding some gradient and spot-like features). If nameOrMap is a numpy array, the passed array is used as background after scaling by the exposure time Raises: KeyError if nameOrMap is a string not corresponding to any predefined sky background. """ % (self.SKY_NO, self.SKY_IDEAL, self.SKY_REALISTIC) if isinstance(nameOrMap, str): if nameOrMap == self.SKY_NO: sky = np.zeros(self._shape) elif nameOrMap == self.SKY_IDEAL: sky = self._idealSky() elif nameOrMap == self.SKY_REALISTIC: sky = self._realisticSky() else: raise KeyError('Unknown sky background map %s' % nameOrMap) self._skyImage = sky else: self._skyImage = nameOrMap def _addSensitivityAndVignetting(self, image): return image * self._transmissionMap def _addShotNoise(self, photonNoNoiseImage): return (apply_poisson_noise(photonNoNoiseImage, self._seed)).astype(float64)
def project(self, cube, cutoff): # TODO Make all this with astropy units from the call functions table = Table(names=("Line Code", "Mol", "Ch Name", "Rest Freq", "Obs Freq", "Intensity"), dtype=('S80', 'S40', 'S40', 'f8', 'f8', 'f8')) dba = db.lineDB(self.dbpath) # Maybe we can have an always open DB dba.connect() fwin = axis_range(cube.data, cube.wcs, axis=2) # print "fwin",fwin cor_fwin = np.array(fwin / (1 + self.z)) * u.Hz cor_fwin = cor_fwin.to(u.MHz).value # print "cor_fwin",cor_fwin counter = 0 used = False for mol in self.mol_list: # For each molecule specified in the dictionary # load its spectral lines linlist = dba.getSpeciesLines( mol, cor_fwin[0], cor_fwin[1]) # Selected spectral lines for this molecule # rinte = INTEN_VALUES[0] # for j in range(len(INTEN_GROUP)): # TODO: baaad python, try a more pythonic way.. # if mol in INTEN_GROUP[j]: # rinte = INTEN_VALUES[j] abun = random.uniform(self.mol_list[mol][0], self.mol_list[mol][1]) * u.Jy / u.beam for lin in linlist: counter += 1 trans_temp = lin[5] * u.K inten = lin[4] if inten != 0: inten = 10**inten flux = np.exp( -abs(trans_temp - self.temp) / trans_temp) * inten * abun flux = flux.value * u.Jy / u.beam # print trans_temp, self.temp, flux freq = (1 + self.z) * lin[3] * u.MHz # TODO: astropy # print flux, cutoff if flux < cutoff: # TODO: astropy units! log.info(' - Discarding ' + str(lin[1]) + ' at freq=' + str(freq) + '(' + str(lin[3] * u.MHz) + ') because I=' + str(flux) + ' < ' + str(cutoff)) continue if self._draw(cube, flux, freq, cutoff) == False: log.info(' - Discarding ' + str(lin[1]) + ' at freq=' + str(freq) + '(' + str(lin[3] * u.MHz) + ') because it is too thin for the resolution') continue log.info(' - Projecting ' + str(lin[2]) + ' (' + str(lin[1]) + ') at freq=' + str(freq) + '(' + str(lin[3] * u.MHz) + ') intens=' + str(flux)) used = True # add line to the table. # TODO: modificar ultimo valor, que corresponde a la intensidad. table.add_row((self.comp_name + "-l" + str(counter), mol, str(lin[2]), str(lin[3]), freq, flux)) dba.disconnect() if not used: return None return table