Esempio n. 1
0
    def test_rad(self):
        nside = 64
        hpids = np.arange(hp.nside2npix(nside))
        ra, dec = utils._hpid2RaDec(nside, hpids)
        mjd = 59852.
        obs = utils.ObservationMetaData(mjd=mjd)

        alt1, az1, pa1 = utils._altAzPaFromRaDec(ra, dec, obs)

        alt2, az2 = utils._approx_RaDec2AltAz(ra, dec, obs.site.latitude_rad,
                                              obs.site.longitude_rad, mjd)

        # Check that the fast is similar to the more precice transform
        tol = np.radians(2)
        tol_mean = np.radians(1.)
        separations = utils._angularSeparation(az1, alt1, az2, alt2)

        self.assertLess(np.max(separations), tol)
        self.assertLess(np.mean(separations), tol_mean)

        # Check that the fast can nearly round-trip
        ra_back, dec_back = utils._approx_altAz2RaDec(alt2, az2, obs.site.latitude_rad,
                                                      obs.site.longitude_rad, mjd)
        separations = utils._angularSeparation(ra, dec, ra_back, dec_back)
        self.assertLess(np.max(separations), tol)
        self.assertLess(np.mean(separations), tol_mean)
Esempio n. 2
0
    def test_rad(self):
        nside = 64
        hpids = np.arange(hp.nside2npix(nside))
        ra, dec = utils._hpid2RaDec(nside, hpids)
        mjd = 59852.
        obs = utils.ObservationMetaData(mjd=mjd)

        alt1, az1, pa1 = utils._altAzPaFromRaDec(ra, dec, obs)

        alt2, az2 = utils._approx_RaDec2AltAz(ra, dec, obs.site.latitude_rad,
                                              obs.site.longitude_rad, mjd)

        # Check that the fast is similar to the more precice transform
        tol = np.radians(2)
        tol_mean = np.radians(1.)
        separations = utils._angularSeparation(az1, alt1, az2, alt2)

        self.assertLess(np.max(separations), tol)
        self.assertLess(np.mean(separations), tol_mean)

        # Check that the fast can nearly round-trip
        ra_back, dec_back = utils._approx_altAz2RaDec(alt2, az2,
                                                      obs.site.latitude_rad,
                                                      obs.site.longitude_rad,
                                                      mjd)
        separations = utils._angularSeparation(ra, dec, ra_back, dec_back)
        self.assertLess(np.max(separations), tol)
        self.assertLess(np.mean(separations), tol_mean)
Esempio n. 3
0
 def __call__(self, ra, dec, mjd):
     alt, az, pa = _approx_RaDec2AltAz(ra,
                                       dec,
                                       self.location.lat_rad,
                                       self.location.lon_rad,
                                       mjd,
                                       return_pa=True)
     return alt, az, pa
Esempio n. 4
0
    def _update_rotSkyPos(self, observation):
        """If we have an undefined rotSkyPos, try to fill it out.
        """
        alt, az = _approx_RaDec2AltAz(observation['RA'], observation['dec'],
                                      self.site.latitude_rad,
                                      self.site.longitude_rad, self.mjd)
        obs_pa = approx_altaz2pa(alt, az, self.site.latitude_rad)
        observation['rotSkyPos'] = (obs_pa +
                                    observation['rotTelPos']) % (2 * np.pi)
        observation['rotTelPos'] = 0.

        return observation
Esempio n. 5
0
    def __call__(self, observation_list, conditions):

        # XXX--should I convert the list into an array and get rid of this loop?
        for obs in observation_list:
            alt, az = _approx_RaDec2AltAz(obs['RA'], obs['dec'],
                                          conditions.site.latitude_rad,
                                          conditions.site.longitude_rad,
                                          conditions.mjd)
            obs_pa = _approx_altaz2pa(alt, az, conditions.site.latitude_rad)
            obs['rotSkyPos'] = obs_pa

        return observation_list
Esempio n. 6
0
 def slewtime_map(self):
     """
     Return a map of how long it would take to slew to lots of positions
     """
     if self.ra is None:
         return 0.
     alt, az = _approx_RaDec2AltAz(self.ra_all_sky, self.dec_all_sky,
                                   self.obs.lat, self.obs.lon, self.mjd)
     good = np.where(alt >= self.alt_limit)
     result = np.empty(self.ra_all_sky.size, dtype=float)
     result.fill(hp.UNSEEN)
     result[good] = self.slew_time(alt[good], az[good])
     return result
    def request_observation(self, mjd=None):
        """
        Ask the scheduler what it wants to observe next

        Paramters
        ---------
        mjd : float (None)
            The Modified Julian Date. If None, it uses the MJD from the conditions from the last conditions update.

        Returns
        -------
        observation object (ra,dec,filter,rotangle)
        Returns None if the queue fails to fill
        """
        if mjd is None:
            mjd = self.conditions.mjd
        if len(self.queue) == 0:
            self._fill_queue()

        if len(self.queue) == 0:
            return None
        else:
            # If the queue has gone stale, flush and refill. Zero means no flush_by was set.
            if (int_rounded(mjd) > int_rounded(self.queue[0]['flush_by_mjd'])
                ) & (self.queue[0]['flush_by_mjd'] != 0):
                self.flushed += len(self.queue)
                self.flush_queue()
                self._fill_queue()
            if len(self.queue) == 0:
                return None
            observation = self.queue.pop(0)
            # If we are limiting the camera rotator
            if self.rotator_limits is not None:
                alt, az = _approx_RaDec2AltAz(
                    observation['RA'], observation['dec'],
                    self.conditions.site.latitude_rad,
                    self.conditions.site.longitude_rad, mjd)
                obs_pa = approx_altaz2pa(alt, az,
                                         self.conditions.site.latitude_rad)
                rotTelPos_expected = (obs_pa -
                                      observation['rotSkyPos']) % (2. * np.pi)
                if (int_rounded(rotTelPos_expected) > int_rounded(
                        self.rotator_limits[0])) & (
                            int_rounded(rotTelPos_expected) < int_rounded(
                                self.rotator_limits[1])):
                    diff = np.abs(self.rotator_limits - rotTelPos_expected)
                    limit_indx = np.min(np.where(diff == np.min(diff))[0])
                    observation['rotSkyPos'] = (
                        obs_pa - self.rotator_limits[limit_indx]) % (2. *
                                                                     np.pi)
            return observation
    def _check_alts(self, observation, conditions):
        result = False
        # Just do a fast ra,dec to alt,az conversion. Can use LMST from a feature.

        alt, az = _approx_RaDec2AltAz(observation['RA'],
                                      observation['dec'],
                                      self.lat,
                                      None,
                                      conditions.mjd,
                                      lmst=conditions.lmst)
        in_range = np.where((alt < self.max_alt) & (alt > self.min_alt))[0]
        if np.size(in_range) > 0:
            result = True
        return result
    def check_feasibility(self, conditions):

        result =True
        alt, az = _approx_RaDec2AltAz(self.ra, self.dec,
                                      conditions.site.latitude_rad,
                                      conditions.site.longitude_rad, conditions.mjd)
        if az > np.pi:
            az = az - 2*np.pi

        val = np.abs(60. - 30.*(np.abs(np.degrees(az))/60.)**2-np.degrees(alt))
        if val < 10.:
            result = False

        return result
    def __call__(self, observation_list, conditions):

        # Generate offsets in RA and Dec
        offsets = self._generate_offsets(len(observation_list),
                                         conditions.night)

        for i, obs in enumerate(observation_list):
            alt, az = _approx_RaDec2AltAz(obs['RA'], obs['dec'],
                                          conditions.site.latitude_rad,
                                          conditions.site.longitude_rad,
                                          conditions.mjd)
            obs_pa = approx_altaz2pa(alt, az, conditions.site.latitude_rad)
            obs['rotSkyPos'] = (obs_pa + offsets[i]) % (2. * np.pi)

        return observation_list
Esempio n. 11
0
    def slew_time(self, alt, az, mintime=2.):
        """
        Compute slew time to new ra, dec position
        """

        current_alt, current_az = _approx_RaDec2AltAz(np.array([self.ra]),
                                                      np.array([self.dec]),
                                                      self.obs.lat, self.obs.lon,
                                                      self.mjd)
        # Interpolation can be off by ~.1 seconds if there's no slew.
        if (np.max(current_alt) == np.max(alt)) & (np.max(current_az) == np.max(az)):
            time = mintime
        else:
            time = self.slew_interp(current_alt, current_az, alt, az)
        return time
Esempio n. 12
0
    def __call__(self, observation_list, conditions):
        obs_array = np.concatenate(observation_list)
        alt, az = _approx_RaDec2AltAz(obs_array['RA'], obs_array['dec'],
                                      conditions.site.latitude_rad,
                                      conditions.site.longitude_rad,
                                      conditions.mjd)
        alt_diff = np.abs(alt - conditions.telAlt)
        in_band = np.where(int_rounded(alt_diff) <= self.alt_band)[0]
        if in_band.size == 0:
            in_band = np.arange(alt.size)

        # Find the closest in angular distance of the points that are in band
        ang_dist = _angularSeparation(az[in_band], alt[in_band],
                                      conditions.telAz, conditions.telAlt)
        good = np.min(np.where(ang_dist == ang_dist.min())[0])
        indx = in_band[good]
        result = observation_list[indx:] + observation_list[:indx]
        return result
Esempio n. 13
0
    def __call__(self, observation_list, conditions):
        favored_rotSkyPos = np.radians([0., 90., 180., 270.,
                                        360.]).reshape(5, 1)
        obs_array = np.concatenate(observation_list)
        alt, az = _approx_RaDec2AltAz(obs_array['RA'], obs_array['dec'],
                                      conditions.site.latitude_rad,
                                      conditions.site.longitude_rad,
                                      conditions.mjd)
        parallactic_angle = _approx_altaz2pa(alt, az,
                                             conditions.site.latitude_rad)
        # If we set rotSkyPos to parallactic angle, rotTelPos will be zero. So, find the
        # favored rotSkyPos that is closest to PA to keep rotTelPos as close as possible to zero.
        ang_diff = np.abs(parallactic_angle - favored_rotSkyPos)
        min_indxs = np.argmin(ang_diff, axis=0)
        # can swap 360 and zero if needed?
        final_rotSkyPos = favored_rotSkyPos[min_indxs]
        # Set all the observations to the proper rotSkyPos
        for rsp, obs in zip(final_rotSkyPos, observation_list):
            obs['rotSkyPos'] = rsp

        return observation_list
    def _check_alts_HA(self, observation, conditions):
        """Given scheduled observations, check which ones can be done in current conditions.

        Parameters
        ----------
        observation : np.array
            An array of scheduled observations. Probably generated with lsst.sims.featureScheduler.utils.scheduled_observation
        """
        # Just do a fast ra,dec to alt,az conversion.
        alt, az = _approx_RaDec2AltAz(observation['RA'],
                                      observation['dec'],
                                      conditions.site.latitude_rad,
                                      None,
                                      conditions.mjd,
                                      lmst=conditions.lmst)
        HA = conditions.lmst - observation['RA'] * 12. / np.pi
        HA[np.where(HA > 24)] -= 24
        HA[np.where(HA < 0)] += 24
        in_range = np.where((alt < observation['alt_max'])
                            & (alt > observation['alt_min'])
                            & ((HA > observation['HA_max'])
                               | (HA < observation['HA_min'])))[0]
        return in_range
Esempio n. 15
0
 def calc_altAz(self):
     self._alt, self._az = _approx_RaDec2AltAz(self.ra, self.dec,
                                               self.site.latitude_rad,
                                               self.site.longitude_rad, self._mjd)
Esempio n. 16
0
    def generate_observations_rough(self, conditions):
        """
        Find a good block of observations.
        """

        self.reward = self.calc_reward_function(conditions)

        # Check if we need to spin the tesselation
        if self.dither & (conditions.night != self.night):
            self._spin_fields()
            self.night = conditions.night.copy()

        if self.grow_blob:
            # Note, returns highest first
            ordered_hp = hp_grow_argsort(self.reward)
            ordered_fields = self.hp2fields[ordered_hp]
            orig_order = np.arange(ordered_fields.size)
            # Remove duplicate field pointings
            _u_of, u_indx = np.unique(ordered_fields, return_index=True)
            new_order = np.argsort(orig_order[u_indx])
            best_fields = ordered_fields[u_indx[new_order]]

            if np.size(best_fields) < self.nvisit_block:
                # Let's fall back to the simple sort
                self.simple_order_sort()
            else:
                self.best_fields = best_fields[0:self.nvisit_block]
        else:
            self.simple_order_sort()

        if len(self.best_fields) == 0:
            # everything was nans, or self.nvisit_block was zero
            return []

        # Let's find the alt, az coords of the points (right now, hopefully doesn't change much in time block)
        pointing_alt, pointing_az = _approx_RaDec2AltAz(
            self.fields['RA'][self.best_fields],
            self.fields['dec'][self.best_fields],
            conditions.site.latitude_rad,
            conditions.site.longitude_rad,
            conditions.mjd,
            lmst=conditions.lmst)

        # Let's find a good spot to project the points to a plane
        mid_alt = (np.max(pointing_alt) - np.min(pointing_alt)) / 2.

        # Code snippet from MAF for computing mean of angle accounting for wrap around
        # XXX-TODO: Maybe move this to sims_utils as a generally useful snippet.
        x = np.cos(pointing_az)
        y = np.sin(pointing_az)
        meanx = np.mean(x)
        meany = np.mean(y)
        angle = np.arctan2(meany, meanx)
        radius = np.sqrt(meanx**2 + meany**2)
        mid_az = angle % (2. * np.pi)
        if radius < 0.1:
            mid_az = np.pi

        # Project the alt,az coordinates to a plane. Could consider scaling things to represent
        # time between points rather than angular distance.
        pointing_x, pointing_y = gnomonic_project_toxy(pointing_az,
                                                       pointing_alt, mid_az,
                                                       mid_alt)
        # Round off positions so that we ensure identical cross-platform performance
        scale = 1e6
        pointing_x = np.round(pointing_x * scale).astype(int)
        pointing_y = np.round(pointing_y * scale).astype(int)
        # Now I have a bunch of x,y pointings. Drop into TSP solver to get an effiencent route
        towns = np.vstack((pointing_x, pointing_y)).T
        # Leaving optimize=False for speed. The optimization step doesn't usually improve much.
        better_order = tsp_convex(towns, optimize=False)
        # XXX-TODO: Could try to roll better_order to start at the nearest/fastest slew from current position.
        observations = []
        counter2 = 0
        approx_end_time = np.size(better_order) * (
            self.slew_approx + self.exptime + self.read_approx *
            (self.nexp - 1))
        flush_time = conditions.mjd + approx_end_time / 3600. / 24. + self.flush_time
        for i, indx in enumerate(better_order):
            field = self.best_fields[indx]
            obs = empty_observation()
            obs['RA'] = self.fields['RA'][field]
            obs['dec'] = self.fields['dec'][field]
            obs['rotSkyPos'] = 0.
            obs['filter'] = self.filtername1
            if self.nexp_dict is None:
                obs['nexp'] = self.nexp
            else:
                obs['nexp'] = self.nexp_dict[self.filtername1]
            obs['exptime'] = self.exptime
            obs['field_id'] = -1
            obs['note'] = '%s' % (self.survey_note)
            obs['block_id'] = self.counter
            obs['flush_by_mjd'] = flush_time
            # Add the mjd for debugging
            # obs['mjd'] = conditions.mjd
            # XXX temp debugging line
            obs['survey_id'] = i
            observations.append(obs)
            counter2 += 1

        result = observations
        return result
Esempio n. 17
0
    def attempt_observe(self, observation_in, indx=None):
        """
        Check an observation, if there is enough time, execute it and return it, otherwise, return None.
        """
        # If we were in a parked position, assume no time lost to slew, settle, filter change
        observation = observation_in.copy()
        alt, az = _approx_RaDec2AltAz(np.array([observation['RA']]),
                                      np.array([observation['dec']]),
                                      self.obs.lat, self.obs.lon, self.mjd)
        if self.ra is not None:
            if self.filtername != observation['filter']:
                ft = self.f_change_time
                st = 0.
            else:
                ft = 0.
                st = self.slew_time(alt, az)
        else:
            st = 0.
            ft = 0.

        # Assume we can slew while reading the last exposure (note that slewtime calc gives 2 as a minimum. So this 
        # will not fail for DD fields, etc.)
        # So, filter change time, slew to target time, expose time, read time
        rt = (observation['nexp']-1.)*self.readtime
        shutter_time = self.shutter_time*observation['nexp']
        total_time = (ft + st + observation['exptime'] + rt + shutter_time)*sec2days
        check_result, jump_mjd = self.check_mjd(self.mjd + total_time)
        if check_result:
            # XXX--major decision here, should the status be updated after every observation? Or just assume
            # airmass, seeing, and skybrightness do not change significantly?
            if self.ra is None:
                update_status = True
            else:
                update_status = False
            # This should be the start of the exposure.
            observation['mjd'] = self.mjd + (ft + st)*sec2days
            self.set_mjd(self.mjd + (ft + st)*sec2days)
            self.ra = observation['RA']
            self.dec = observation['dec']

            if update_status:
                # What's the name for temp variables?
                status = self.return_status()

            observation['night'] = self.night
            # XXX I REALLY HATE THIS! READTIME SHOULD NOT BE LUMPED IN WITH SLEWTIME!
            # XXX--removing that so I may not be using the same convention as opsim.
            observation['slewtime'] = ft+st

            self.filtername = observation['filter'][0]
            hpid = _raDec2Hpid(self.sky_nside, self.ra, self.dec)
            observation['skybrightness'] = self.sky.returnMags(observation['mjd'], indx=[hpid],
                                                               extrapolate=True)[self.filtername]
            observation['FWHMeff'] = self.status['FWHMeff_%s' % self.filtername][hpid]
            observation['FWHM_geometric'] = self.status['FWHM_geometric_%s' % self.filtername][hpid]
            observation['airmass'] = self.status['airmass'][hpid]
            observation['fivesigmadepth'] = m5_flat_sed(observation['filter'][0],
                                                        observation['skybrightness'],
                                                        observation['FWHMeff'],
                                                        observation['exptime'],
                                                        observation['airmass'])
            observation['alt'] = alt
            observation['az'] = az
            observation['clouds'] = self.status['clouds']
            observation['sunAlt'] = self.status['sunAlt']
            observation['moonAlt'] = self.status['moonAlt']
            # We had advanced the slew and filter change, so subtract that off and add the total visit time.
            self.set_mjd(self.mjd + total_time - (ft + st)*sec2days)

            return observation
        else:
            self.mjd = jump_mjd
            self.night = self.mjd2night(self.mjd)
            self.ra = None
            self.dec = None
            self.status = None
            self.filtername = None
            return None
Esempio n. 18
0
    def setRaDecMjd(self, lon, lat, mjd, degrees=False, azAlt=False, solarFlux=130.,
                    filterNames=['u', 'g', 'r', 'i', 'z', 'y']):
        """
        Set the sky parameters by computing the sky conditions on a given MJD and sky location.



        lon: Longitude-like (RA or Azimuth). Can be single number, list, or numpy array
        lat: Latitude-like (Dec or Altitude)
        mjd: Modified Julian Date for the calculation. Must be single number.
        degrees: (False) Assumes lon and lat are radians unless degrees=True
        azAlt: (False) Assume lon, lat are RA, Dec unless azAlt=True
        solarFlux: solar flux in SFU Between 50 and 310. Default=130. 1 SFU=10^4 Jy.
        filterNames: list of fitlers to return magnitudes for (if initialized with mags=True).
        """
        self.filterNames = filterNames
        if self.mags:
            self.npix = len(self.filterNames)
        # Wrap in array just in case single points were passed
        if np.size(lon) == 1:
            lon = np.array([lon]).ravel()
            lat = np.array([lat]).ravel()
        else:
            lon = np.array(lon)
            lat = np.array(lat)
        if degrees:
            self.ra = np.radians(lon)
            self.dec = np.radians(lat)
        else:
            self.ra = lon
            self.dec = lat
        if np.size(mjd) > 1:
            raise ValueError('mjd must be single value.')
        self.mjd = mjd
        if azAlt:
            self.azs = self.ra.copy()
            self.alts = self.dec.copy()
            if self.preciseAltAz:
                self.ra, self.dec = _raDecFromAltAz(self.alts, self.azs,
                                                    ObservationMetaData(mjd=self.mjd, site=self.telescope))
            else:
                self.ra, self.dec = _approx_altAz2RaDec(self.alts, self.azs,
                                                        self.telescope.latitude_rad,
                                                        self.telescope.longitude_rad, mjd)
        else:
            if self.preciseAltAz:
                self.alts, self.azs, pa = _altAzPaFromRaDec(self.ra, self.dec,
                                                            ObservationMetaData(mjd=self.mjd,
                                                                                site=self.telescope))
            else:
                self.alts, self.azs = _approx_RaDec2AltAz(self.ra, self.dec,
                                                          self.telescope.latitude_rad,
                                                          self.telescope.longitude_rad, mjd)

        self.npts = self.ra.size
        self._initPoints()

        self.solarFlux = solarFlux
        self.points['solarFlux'] = self.solarFlux

        self._setupPointGrid()

        self.paramsSet = True

        # Assume large airmasses are the same as airmass=2.5
        to_fudge = np.where((self.points['airmass'] > 2.5) & (self.points['airmass'] < self.airmassLimit))
        self.points['airmass'][to_fudge] = 2.499
        self.points['alt'][to_fudge] = np.pi/2-np.arccos(1./self.airmassLimit)

        # Interpolate the templates to the set paramters
        self.goodPix = np.where((self.airmass <= self.airmassLimit) & (self.airmass >= 1.))[0]
        if self.goodPix.size > 0:
            self._interpSky()
        else:
            warnings.warn('No valid points to interpolate')
Esempio n. 19
0
def obs2sqlite(observations_in, location='LSST', outfile='observations.sqlite', slewtime_limit=5.,
               full_sky=False, radians=True):
    """
    Utility to take an array of observations and dump it to a sqlite file, filling in useful columns along the way.

    observations_in: numpy array with at least columns of
        ra : RA in degrees
        dec : dec in degrees
        mjd : MJD in day
        filter : string with the filter name
        exptime : the exposure time in seconds
    slewtime_limit : float
        Consider all slewtimes larger than this to be closed-dome time not part of a slew.
    """

    # Set the location to be LSST
    if location == 'LSST':
        telescope = Site('LSST')

    # Check that we have the columns we need
    needed_cols = ['ra', 'dec', 'mjd', 'filter']
    in_cols = observations_in.dtype.names
    for col in needed_cols:
        if needed_cols not in in_cols:
            ValueError('%s column not found in observtion array' % col)

    n_obs = observations_in.size
    sm = None
    # make sure they are in order by MJD
    observations_in.sort(order='mjd')

    # Take all the columns that are in the input and add any missing
    names = ['filter', 'ra', 'dec', 'mjd', 'exptime', 'alt', 'az', 'skybrightness',
             'seeing', 'night', 'slewtime', 'fivesigmadepth', 'airmass', 'sunAlt', 'moonAlt']
    types = ['|S1']
    types.extend([float]*(len(names)-1))

    observations = np.zeros(n_obs, dtype=list(zip(names, types)))

    # copy over the ones we have
    for col in in_cols:
        observations[col] = observations_in[col]

    # convert output to be in degrees like expected
    if radians:
        observations['ra'] = np.degrees(observations['ra'])
        observations['dec'] = np.degrees(observations['dec'])

    if 'exptime' not in in_cols:
        observations['exptime'] = 30.

    # Fill in the slewtime. Note that filterchange time gets included in slewtimes
    if 'slewtime' not in in_cols:
        # Assume MJD is midpoint of exposures
        mjd_sec = observations_in['mjd']*24.*3600.
        observations['slewtime'][1:] = mjd_sec[1:]-mjd_sec[0:-1] - observations['exptime'][0:-1]*0.5 - observations['exptime'][1:]*0.5
        closed = np.where(observations['slewtime'] > slewtime_limit*60.)
        observations['slewtime'][closed] = 0.

    # Let's just use the stupid-fast to get alt-az
    if 'alt' not in in_cols:
        alt, az = _approx_RaDec2AltAz(np.radians(observations['ra']), np.radians(observations['dec']),
                                      telescope.latitude_rad, telescope.longitude_rad, observations['mjd'])
        observations['alt'] = np.degrees(alt)
        observations['az'] = np.degrees(az)

    # Fill in the airmass
    if 'airmass' not in in_cols:
        observations['airmass'] = 1./np.cos(np.pi/2. - np.radians(observations['alt']))

    # Fill in the seeing
    if 'seeing' not in in_cols:
        # XXX just fill in a dummy val
        observations['seeing'] = 0.8

    if 'night' not in in_cols:
        m2n = mjd2night()
        observations['night'] = m2n(observations['mjd'])

    # Sky Brightness
    if 'skybrightness' not in in_cols:
        if full_sky:
            sm = SkyModel(mags=True)
            for i, obs in enumerate(observations):
                sm.setRaDecMjd(obs['ra'], obs['dec'], obs['mjd'], degrees=True)
                observations['skybrightness'][i] = sm.returnMags()[obs['filter']]
        else:
            # Let's try using the pre-computed sky brighntesses
            sm = sb.SkyModelPre(preload=False)
            full = sm.returnMags(observations['mjd'][0])
            nside = hp.npix2nside(full['r'].size)
            imax = float(np.size(observations))
            for i, obs in enumerate(observations):
                indx = raDec2Hpid(nside, obs['ra'], obs['dec'])
                observations['skybrightness'][i] = sm.returnMags(obs['mjd'], indx=[indx])[obs['filter']]
                sunMoon = sm.returnSunMoon(obs['mjd'])
                observations['sunAlt'][i] = sunMoon['sunAlt']
                observations['moonAlt'][i] = sunMoon['moonAlt']
                progress = i/imax*100
                text = "\rprogress = %.2f%%"%progress
                sys.stdout.write(text)
                sys.stdout.flush()
            observations['sunAlt'] = np.degrees(observations['sunAlt'])
            observations['moonAlt'] = np.degrees(observations['moonAlt'])


    # 5-sigma depth
    for fn in np.unique(observations['filter']):
        good = np.where(observations['filter'] == fn)
        observations['fivesigmadepth'][good] = m5_flat_sed(fn, observations['skybrightness'][good],
                                                           observations['seeing'][good],
                                                           observations['exptime'][good],
                                                           observations['airmass'][good])

    conn = sqlite3.connect(outfile)
    df = pd.DataFrame(observations)
    df.to_sql('observations', conn)