def visibility(self, multiple=False, midnight=None, airmassmodel='Pickering2002', **kwargs): """ Calculate ephemeri. *If 'multiple' = False, a single site definition and startdate (and/or values for the days and dt keywords) are expected. If one (or more) of these keywords is not given a value, it is assumed that it should not change its current value. If several astrophysical objects are given, ephemeri will be given for each object at the defined site and times. If 'midnight' is not None, ephemeri are calculated in the middle of each night, for the whole year. *If 'multiple' = True, a list/array of site names and startdates can be given. Note: the length of keywords 'sitename', 'startdate' and 'objects' can be either N or 1 and should be in the same format as previously. In this case, ephemeri are only calculated at the times given in 'startdate', and thus the keywords 'days', 'dt' and 'midnight' are not used. Sites are currently only accessible throught the keyword 'sitename'. The result of this function is an attribute 'vis', a dictionary containing: - MJDs: Modified Julian Dates - dates calendar dates (Format 1) - alts: altitudes - moon_alts: altitudes of the moon - airmass - moon_airmass: airmasses of the moon - moon_separation: separation to moon - during_night: night time / day time (boolean 1-0) - sun_prevrise: time of previous sun rise - sun_nextrise: time of next sun rise - sun_prevset: time of previous sun set - sun_nextset: time of next sun set NOTE: use the 'get_out_objects', 'get_out_objectnames', 'get_out_sites' and 'get_out_sitenames' functions to retrieve the object, name of the object, site and name of the site corresponding to a particular row in each of the arrays 'vis' contains. """ #-- if no values are given for these keywords, this means nothing should change --> None kwargs.setdefault('sitename', None) kwargs.setdefault('startdate', None) kwargs.setdefault('dt', None) kwargs.setdefault('days', None) #-- set optional additional keywords sun = ephem.Sun() moon = ephem.Moon() #moon_theta = 34.1 # minutes if not multiple: #-- set the site, date and objects self.set_site(**kwargs) self.set_date(**kwargs) self.set_objects(**kwargs) #-- set stuff for calculations timestep_minutes = self.dt total_days = self.days if midnight is None: total_minutes = int(total_days * 24 * 60. / timestep_minutes) else: total_minutes = 365 #-- set initial arrays alts = np.zeros((len(self.objects), total_minutes)) rawdates = np.zeros(total_minutes) during_night = np.zeros(total_minutes, int) moon_separation = np.zeros((len(self.objects), total_minutes)) moon_alts = np.zeros(total_minutes) sun_prevrise = np.zeros(total_minutes) sun_prevset = np.zeros(total_minutes) sun_nextrise = np.zeros(total_minutes) sun_nextset = np.zeros(total_minutes) #-- run over all timesteps if midnight is None: for i in range(total_minutes): sun_prevset[i] = float(self.thesite.previous_setting(sun)) sun_prevrise[i] = float(self.thesite.previous_rising(sun)) sun_nextset[i] = float(self.thesite.next_setting(sun)) sun_nextrise[i] = float(self.thesite.next_rising(sun)) rawdates[i] = float(self.thesite.date) #-- compute the moon position moon.compute(self.thesite) moon_alts[i] = float(moon.alt) if (sun_prevrise[i] <= sun_prevset[i]): during_night[i] = 1 for j, star in enumerate(self.objects): star.compute(self.thesite) alts[j, i] = float(star.alt) moon_separation[j, i] = ephem.separation(moon, star) self.thesite.date += ephem.minute * timestep_minutes else: i = 0 while i < 365: sun_nextrise[i] = float(self.thesite.next_rising(sun)) sun_prevset[i] = float(self.thesite.previous_setting(sun)) sun_prevrise[i] = float(self.thesite.previous_rising(sun)) sun_nextset[i] = float(self.thesite.next_setting(sun)) if sun_prevrise[i] <= sun_prevset[ i]: # now we're in a night self.thesite.date = ephem.Date( (sun_nextrise[i] + sun_prevset[i]) / 2.) else: #-- set 4 hours forwards self.thesite.date += ephem.minute * 60 * 4 continue rawdates[i] = float(self.thesite.date) during_night[i] = 1 for j, star in enumerate(self.objects): star.compute(self.thesite) alts[j, i] = float(star.alt) i += 1 #-- set 1 day forwards self.thesite.date += ephem.minute * 60 * 24 alts = alts.ravel() rawdates = np.outer(np.ones(len(self.objects)), rawdates).ravel() during_night = np.outer(np.ones(len(self.objects), int), during_night).ravel() moon_separation = moon_separation.ravel() # moon_alts = np.outer(np.ones(len(self.objects)), moon_alts).ravel() sun_nextrise = np.outer(np.ones(len(self.objects)), sun_nextrise).ravel() sun_prevrise = np.outer(np.ones(len(self.objects)), sun_prevrise).ravel() sun_nextset = np.outer(np.ones(len(self.objects)), sun_nextset).ravel() sun_prevset = np.outer(np.ones(len(self.objects)), sun_prevset).ravel() self._objectIndices = np.outer(np.arange(len(self.objects)), np.ones(total_minutes)).ravel() self._siteIndices = np.zeros_like(alts) self._uniqueSites = [self.thesite] else: startdate = kwargs.get('startdate', None) sitename = kwargs.get('sitename', 'lapalma') objects = kwargs.get('objects', None) if objects is None: objects = self.get_objectnames() # the other option is to iterate over given 'dates' and/or sites and objects if not type(startdate) == np.ndarray: startdate = np.array([startdate]) if not type(sitename) == np.ndarray: sitename = np.array([sitename]) if not type(objects) == np.ndarray: objects = np.array([objects]).ravel() uniqueObjectNames = np.unique(objects) uniqueSiteNames = np.unique(sitename) self.set_objects(uniqueObjectNames) self._objectIndices = np.zeros_like(objects, int) self._siteIndices = np.zeros_like(sitename, int) self._uniqueSites = [] for i in range(len(uniqueObjectNames)): self._objectIndices = np.where(objects == uniqueObjectNames[i], i, self._objectIndices) for i in range(len(uniqueSiteNames)): self._siteIndices = np.where(sitename == uniqueSiteNames[i], i, self._siteIndices) self.set_site(uniqueSiteNames[i]) self._uniqueSites.append(self.thesite) #-- define the iterator it = np.broadcast(startdate, self._siteIndices, self._objectIndices) #-- set initial arrays alts = np.zeros(it.shape[0]) rawdates = np.zeros(it.shape[0]) during_night = np.zeros(it.shape[0], int) moon_separation = np.zeros(it.shape[0]) moon_alts = np.zeros(it.shape[0]) sun_prevrise = np.zeros(it.shape[0]) sun_prevset = np.zeros(it.shape[0]) sun_nextrise = np.zeros(it.shape[0]) sun_nextset = np.zeros(it.shape[0]) #-- run over all elements for i, element in enumerate(it): #-- set the site and date self.thesite = self._uniqueSites[element[1]] self.set_date(startdate=element[0], days=None, dt=None) #-- determine whether the time corresponds to night or day sun_prevset[i] = float(self.thesite.previous_setting(sun)) sun_prevrise[i] = float(self.thesite.previous_rising(sun)) sun_nextset[i] = float(self.thesite.next_setting(sun)) sun_nextrise[i] = float(self.thesite.next_rising(sun)) if (sun_prevrise[i] <= sun_prevset[i]): during_night[i] = 1 rawdates[i] = float(self.thesite.date) #-- compute the moon position moon.compute(self.thesite) moon_alts[i] = float(moon.alt) #-- compute the star's position star = self.objects[element[2]] star.compute(self.thesite) alts[i] = float(star.alt) moon_separation[i] = ephem.separation(moon, star) #-- calculate airmass airmass = obs_airmass.airmass(90 - alts / pi * 180, model=airmassmodel) moon_airmass = obs_airmass.airmass(90 - moon_alts / pi * 180, model=airmassmodel) #-- calculate dates for plotting and output self._plotdates = np.array( [date2num(ephem.Date(h).datetime()) for h in rawdates]) self._sun_prevset = np.array( [date2num(ephem.Date(h).datetime()) for h in sun_prevset]) self._sun_prevrise = np.array( [date2num(ephem.Date(h).datetime()) for h in sun_prevrise]) self._sun_nextset = np.array( [date2num(ephem.Date(h).datetime()) for h in sun_nextset]) self._sun_nextrise = np.array( [date2num(ephem.Date(h).datetime()) for h in sun_nextrise]) dates = np.array([str(ephem.Date(h).datetime()) for h in rawdates]) MJDs = rawdates + 15019.499999 # the zeropoint of ephem is 1899/12/31 12:00:00.0 15019.499585 #-- the output dictionary self.vis = dict(MJDs=MJDs, dates=dates, alts=alts, airmass=airmass, during_night=during_night, moon_alts=moon_alts, moon_airmass=moon_airmass, moon_separation=moon_separation) self.vis.update( dict(sun_prevrise=np.array(num2date(self._sun_prevrise), dtype='|S19'), sun_prevset=np.array(num2date(self._sun_prevset), dtype='|S19'), sun_nextrise=np.array(num2date(self._sun_nextrise), dtype='|S19'), sun_nextset=np.array(num2date(self._sun_nextset), dtype='|S19'))) for i, obj in enumerate(self.objects): keep = (self._objectIndices == i) & (during_night == 1) & ( 0 <= airmass) & (airmass <= 2.5) logger.info( 'Object %s: %s visible during night time (%.1f<airmass<%.1f)' % (obj.name, ~np.any(keep) and 'not' or '', sum(keep) and airmass[keep].min() or np.nan, sum(keep) and airmass[keep].max() or np.nan))
def make_data_overview(): """ Summarize all Hermes data in a file for easy data retrieval. The file is located in one of date data directories (see C{config.py}), in subdirectories C{catalogs/hermes/HermesFullDataOverview.tsv}. If it doesn't exist, it will be created. It contains the following columns, which are extracted from the Hermes FITS headers (except C{filename}: 1. UNSEQ 2. PROG_ID 3. OBSMODE 4. BVCOR 5. OBSERVER 6. OBJECT 7. RA 8. DEC 9. BJD 10. EXPTIME 11. PMTOTAL 12. DATE-AVG 13. OBJECT 14. airmass 15. filename This file can most easily be read with the L{ivs.inout.ascii} module and the command: >>> hermes_file = config.get_datafile(os.path.join('catalogs','hermes'),'HermesFullDataOverview.tsv') >>> data = ascii.read2recarray(hermes_file,splitchar='\\t') """ logger.info('Collecting files...') #-- all hermes data directories dirs = sorted(glob.glob(os.path.join(config.ivs_dirs['hermes'],'20??????'))) dirs = [idir for idir in dirs if os.path.isdir(idir)] obj_files = [] #-- collect in those directories the raw and relevant reduced files for idir in dirs: obj_files += sorted(glob.glob(os.path.join(idir,'raw','*.fits'))) #obj_files += sorted(glob.glob(os.path.join(idir,'reduced','*OBJ*wavelength_merged.fits'))) #obj_files += sorted(glob.glob(os.path.join(idir,'reduced','*OBJ*wavelength_merged_c.fits'))) #obj_files += sorted(glob.glob(os.path.join(idir,'reduced','*OBJ*log_merged.fits'))) #obj_files += sorted(glob.glob(os.path.join(idir,'reduced','*OBJ*log_merged_c.fits'))) #-- keep track of what is already in the file, if it exists: try: overview_file = config.get_datafile('catalogs/hermes','HermesFullDataOverview.tsv') #overview_file = config.get_datafile(os.path.join('catalogs','hermes'),'HermesFullDataOverview.tsv') overview_data = ascii.read2recarray(overview_file,splitchar='\t') outfile = open(overview_file,'a') logger.info('Found %d FITS files: appending to overview file %s'%(len(obj_files),overview_file)) # if not, begin a new file except IOError: overview_file = 'HermesFullDataOverview.tsv' outfile = open(overview_file,'w') outfile.write('#unseq prog_id obsmode bvcor observer object ra dec bjd exptime pmtotal date-avg airmass filename\n') outfile.write('#i i a20 >f8 a50 a50 >f8 >f8 >f8 >f8 >f8 a30 >f8 a200\n') overview_data = {'filename':[]} logger.info('Found %d FITS files: starting new overview file %s'%(len(obj_files),overview_file)) #-- and summarize the contents in a tab separated file (some columns contain spaces) existing_files = np.sort(overview_data['filename']) for i,obj_file in enumerate(obj_files): sys.stdout.write(chr(27)+'[s') # save cursor sys.stdout.write(chr(27)+'[2K') # remove line sys.stdout.write('Scanning %5d / %5d FITS files'%(i+1,len(obj_files))) sys.stdout.flush() # flush to screen #-- maybe this file is already processed: forget about it then index = existing_files.searchsorted(obj_file) if index<len(existing_files) and existing_files[index]==obj_file: sys.stdout.write(chr(27)+'[u') # reset cursor continue #-- keep track of: UNSEQ, PROG_ID, OBSMODE, BVCOR, OBSERVER, # OBJECT, RA, DEC, BJD, EXPTIME, DATE-AVG, PMTOTAL, # airmass and filename (not part of fitsheader) contents = dict(unseq=-1,prog_id=-1,obsmode='nan',bvcor=np.nan,observer='nan', object='nan',ra=np.nan,dec=np.nan, bjd=np.nan,exptime=np.nan,pmtotal=np.nan,airmass=np.nan, filename=os.path.realpath(obj_file)) contents['date-avg'] = 'nan' header = pf.getheader(obj_file) for key in contents: if key in header and key in ['unseq','prog_id']: try: contents[key] = int(header[key]) except: pass elif key in header and key in ['obsmode','observer','object','date-avg']: contents[key] = str(header[key]) elif key in header and key in ['ra','dec','exptime','pmtotal','bjd','bvcor']: contents[key] = float(header[key]) elif key=='airmass' and 'telalt' in header: if float(header['telalt'])<90: try: contents[key] = airmass.airmass(90-float(header['telalt'])) except ValueError: pass outfile.write('%(unseq)d\t%(prog_id)d\t%(obsmode)s\t%(bvcor)f\t%(observer)s\t%(object)s\t%(ra)f\t%(dec)f\t%(bjd)f\t%(exptime)f\t%(pmtotal)f\t%(date-avg)s\t%(airmass)f\t%(filename)s\n'%contents) outfile.flush() sys.stdout.write(chr(27)+'[u') # reset cursor outfile.close() return overview_file
def visibility(self,multiple=False,midnight=None,airmassmodel='Pickering2002',**kwargs): """ Calculate ephemeri. *If 'multiple' = False, a single site definition and startdate (and/or values for the days and dt keywords) are expected. If one (or more) of these keywords is not given a value, it is assumed that it should not change its current value. If several astrophysical objects are given, ephemeri will be given for each object at the defined site and times. If 'midnight' is not None, ephemeri are calculated in the middle of each night, for the whole year. *If 'multiple' = True, a list/array of site names and startdates can be given. Note: the length of keywords 'sitename', 'startdate' and 'objects' can be either N or 1 and should be in the same format as previously. In this case, ephemeri are only calculated at the times given in 'startdate', and thus the keywords 'days', 'dt' and 'midnight' are not used. Sites are currently only accessible throught the keyword 'sitename'. The result of this function is an attribute 'vis', a dictionary containing: - MJDs: Modified Julian Dates - dates calendar dates (Format 1) - alts: altitudes - moon_alts: altitudes of the moon - airmass - moon_airmass: airmasses of the moon - moon_separation: separation to moon - during_night: night time / day time (boolean 1-0) - sun_prevrise: time of previous sun rise - sun_nextrise: time of next sun rise - sun_prevset: time of previous sun set - sun_nextset: time of next sun set NOTE: use the 'get_out_objects', 'get_out_objectnames', 'get_out_sites' and 'get_out_sitenames' functions to retrieve the object, name of the object, site and name of the site corresponding to a particular row in each of the arrays 'vis' contains. """ #-- if no values are given for these keywords, this means nothing should change --> None kwargs.setdefault('sitename',None) kwargs.setdefault('startdate',None) kwargs.setdefault('dt',None) kwargs.setdefault('days',None) #-- set optional additional keywords sun = ephem.Sun() moon = ephem.Moon() #moon_theta = 34.1 # minutes if not multiple: #-- set the site, date and objects self.set_site(**kwargs) self.set_date(**kwargs) self.set_objects(**kwargs) #-- set stuff for calculations timestep_minutes = self.dt total_days = self.days if midnight is None: total_minutes = int(total_days*24*60./timestep_minutes) else: total_minutes = 365 #-- set initial arrays alts = np.zeros((len(self.objects),total_minutes)) rawdates = np.zeros(total_minutes) during_night = np.zeros(total_minutes,int) moon_separation = np.zeros((len(self.objects),total_minutes)) moon_alts = np.zeros(total_minutes) sun_prevrise = np.zeros(total_minutes) sun_prevset = np.zeros(total_minutes) sun_nextrise = np.zeros(total_minutes) sun_nextset = np.zeros(total_minutes) #-- run over all timesteps if midnight is None: for i in range(total_minutes): sun_prevset[i] = float(self.thesite.previous_setting(sun)) sun_prevrise[i] = float(self.thesite.previous_rising(sun)) sun_nextset[i] = float(self.thesite.next_setting(sun)) sun_nextrise[i] = float(self.thesite.next_rising(sun)) rawdates[i] = float(self.thesite.date) #-- compute the moon position moon.compute(self.thesite) moon_alts[i] = float(moon.alt) if (sun_prevrise[i]<=sun_prevset[i]): during_night[i] = 1 for j,star in enumerate(self.objects): star.compute(self.thesite) alts[j,i] = float(star.alt) moon_separation[j,i] = ephem.separation(moon,star) self.thesite.date += ephem.minute*timestep_minutes else: i = 0 while i<365: sun_nextrise[i] = float(self.thesite.next_rising(sun)) sun_prevset[i] = float(self.thesite.previous_setting(sun)) sun_prevrise[i] = float(self.thesite.previous_rising(sun)) sun_nextset[i] = float(self.thesite.next_setting(sun)) if sun_prevrise[i]<=sun_prevset[i]: # now we're in a night self.thesite.date = ephem.Date((sun_nextrise[i]+sun_prevset[i])/2.) else: #-- set 4 hours forwards self.thesite.date += ephem.minute*60*4 continue rawdates[i] = float(self.thesite.date) during_night[i] = 1 for j,star in enumerate(self.objects): star.compute(self.thesite) alts[j,i] = float(star.alt) i += 1 #-- set 1 day forwards self.thesite.date += ephem.minute*60*24 alts = alts.ravel() rawdates = np.outer(np.ones(len(self.objects)),rawdates).ravel() during_night = np.outer(np.ones(len(self.objects),int),during_night).ravel() moon_separation = moon_separation.ravel() # moon_alts = np.outer(np.ones(len(self.objects)),moon_alts).ravel() sun_nextrise = np.outer(np.ones(len(self.objects)),sun_nextrise).ravel() sun_prevrise = np.outer(np.ones(len(self.objects)),sun_prevrise).ravel() sun_nextset = np.outer(np.ones(len(self.objects)),sun_nextset).ravel() sun_prevset = np.outer(np.ones(len(self.objects)),sun_prevset).ravel() self._objectIndices = np.outer(np.arange(len(self.objects)),np.ones(total_minutes)).ravel() self._siteIndices = np.zeros_like(alts) self._uniqueSites = [self.thesite] else: startdate = kwargs.get('startdate',None) sitename = kwargs.get('sitename','lapalma') objects = kwargs.get('objects',None) if objects is None: objects = self.get_objectnames() # the other option is to iterate over given 'dates' and/or sites and objects if not type(startdate) == np.ndarray: startdate = np.array([startdate]) if not type(sitename) == np.ndarray: sitename = np.array([sitename]) if not type(objects) == np.ndarray: objects = np.array([objects]).ravel() uniqueObjectNames = np.unique(objects) uniqueSiteNames = np.unique(sitename) self.set_objects(uniqueObjectNames) self._objectIndices = np.zeros_like(objects,int) self._siteIndices = np.zeros_like(sitename,int) self._uniqueSites = [] for i in range(len(uniqueObjectNames)): self._objectIndices = np.where(objects == uniqueObjectNames[i],i,self._objectIndices) for i in range(len(uniqueSiteNames)): self._siteIndices = np.where(sitename == uniqueSiteNames[i],i,self._siteIndices) self.set_site(uniqueSiteNames[i]) self._uniqueSites.append(self.thesite) #-- define the iterator it = np.broadcast(startdate,self._siteIndices,self._objectIndices) #-- set initial arrays alts = np.zeros(it.shape[0]) rawdates = np.zeros(it.shape[0]) during_night = np.zeros(it.shape[0],int) moon_separation = np.zeros(it.shape[0]) moon_alts = np.zeros(it.shape[0]) sun_prevrise = np.zeros(it.shape[0]) sun_prevset = np.zeros(it.shape[0]) sun_nextrise = np.zeros(it.shape[0]) sun_nextset = np.zeros(it.shape[0]) #-- run over all elements for i,element in enumerate(it): #-- set the site and date self.thesite = self._uniqueSites[element[1]] self.set_date(startdate=element[0],days=None,dt=None) #-- determine whether the time corresponds to night or day sun_prevset[i] = float(self.thesite.previous_setting(sun)) sun_prevrise[i] = float(self.thesite.previous_rising(sun)) sun_nextset[i] = float(self.thesite.next_setting(sun)) sun_nextrise[i] = float(self.thesite.next_rising(sun)) if (sun_prevrise[i]<=sun_prevset[i]): during_night[i] = 1 rawdates[i] = float(self.thesite.date) #-- compute the moon position moon.compute(self.thesite) moon_alts[i] = float(moon.alt) #-- compute the star's position star = self.objects[element[2]] star.compute(self.thesite) alts[i] = float(star.alt) moon_separation[i] = ephem.separation(moon,star) #-- calculate airmass airmass = obs_airmass.airmass(90-alts/pi*180,model=airmassmodel) moon_airmass = obs_airmass.airmass(90-moon_alts/pi*180,model=airmassmodel) #-- calculate dates for plotting and output self._plotdates = np.array([date2num(ephem.Date(h).datetime()) for h in rawdates]) self._sun_prevset = np.array([date2num(ephem.Date(h).datetime()) for h in sun_prevset]) self._sun_prevrise = np.array([date2num(ephem.Date(h).datetime()) for h in sun_prevrise]) self._sun_nextset = np.array([date2num(ephem.Date(h).datetime()) for h in sun_nextset]) self._sun_nextrise = np.array([date2num(ephem.Date(h).datetime()) for h in sun_nextrise]) dates = np.array([str(ephem.Date(h).datetime()) for h in rawdates]) MJDs = rawdates+15019.499999 # the zeropoint of ephem is 1899/12/31 12:00:00.0 15019.499585 #-- the output dictionary self.vis = dict(MJDs=MJDs,dates=dates,alts=alts,airmass=airmass,during_night=during_night,moon_alts=moon_alts,moon_airmass=moon_airmass,moon_separation=moon_separation) self.vis.update(dict(sun_prevrise=np.array(num2date(self._sun_prevrise),dtype='|S19'),sun_prevset=np.array(num2date(self._sun_prevset),dtype='|S19'),sun_nextrise=np.array(num2date(self._sun_nextrise),dtype='|S19'),sun_nextset=np.array(num2date(self._sun_nextset),dtype='|S19'))) for i,obj in enumerate(self.objects): keep = (self._objectIndices == i) & (during_night==1) & (0<=airmass) & (airmass<=2.5) logger.info('Object %s: %s visible during night time (%.1f<airmass<%.1f)'%(obj.name,~np.any(keep) and 'not' or '',sum(keep) and airmass[keep].min() or np.nan,sum(keep) and airmass[keep].max() or np.nan))