Пример #1
0
    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))
Пример #2
0
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
Пример #3
0
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))