diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..91f2d9ed --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "barycorr"] + path = barycorr + url = https://github.com/vterron/barycorr.git + branch = init diff --git a/Doc/user/install.rst b/Doc/user/install.rst index 3a0e9b62..873b5428 100644 --- a/Doc/user/install.rst +++ b/Doc/user/install.rst @@ -13,7 +13,7 @@ These are the steps to install LEMON on a fresh `Debian 7`_ machine: #. ``apt-get build-dep python-matplotlib python-scipy`` #. ``apt-get install openmpi-dev`` #. ``easy_install -U distribute`` -#. ``git clone --branch v0.3 git://github.com/vterron/lemon.git ~/lemon`` +#. ``git clone --recurse-submodules git://github.com/vterron/lemon.git ~/lemon`` #. ``cd ~/lemon`` #. ``pip install "numpy>=1.7.1"`` #. ``pip install -r pre-requirements.txt`` # :download:`[View] <../../pre-requirements.txt>` diff --git a/README.rst b/README.rst index f425a6c8..1a660a89 100644 --- a/README.rst +++ b/README.rst @@ -21,6 +21,13 @@ Homepage http://lemon.readthedocs.org/ +Acknowledgments +--------------- + +LEMON uses `Eastman et al. (2010), PASP 122, pp. 935–946`__ for Barycentric Julian Date calculations. + +__ http://adsabs.harvard.edu/abs/2010PASP..122..935E + Acknowledging us ---------------- diff --git a/barycorr b/barycorr new file mode 160000 index 00000000..942c6794 --- /dev/null +++ b/barycorr @@ -0,0 +1 @@ +Subproject commit 942c67949e0a3634179c5c9d00ff3bcd4c9e1636 diff --git a/fitsimage.py b/fitsimage.py index 2593d911..456b5390 100644 --- a/fitsimage.py +++ b/fitsimage.py @@ -28,8 +28,10 @@ # tasks which attempt to display graphics will fail, of course, but we are not # going to make use of any of them, anyway. -import astropy.io + +import astropy.time import astropy.wcs +import barycorr import calendar import collections import datetime @@ -187,7 +189,9 @@ def read_keyword(self, keyword): if not keyword: raise ValueError("keyword cannot be empty") try: - return self._header[keyword.upper()] + value = self._header[keyword.upper()] + logging.debug("%s: %s = %s", self.path, keyword, value) + return value except KeyError: msg = "%s: keyword '%s' not found" % (self.path, keyword) raise KeyError(msg) @@ -326,15 +330,66 @@ def add_history(self, history): finally: handler.close(output_verify = 'ignore') - def date(self, date_keyword = 'DATE-OBS', time_keyword = 'TIME-OBS', - exp_keyword = 'EXPTIME'): + def date(self, + date_keyword=keywords.datek, + time_keyword=keywords.timek, + exp_keyword=keywords.exptimek, + barycentric=False, + bjd_keyword=keywords.bjdk, + ra_keyword=keywords.rak, + dec_keyword=keywords.deck, + ): + """ Return the date at mid-exposure (UTC), in Unix time. + + This function always returns a UTC Unix timestamp. By default, the date + at mid-exposure is derived using the traditional, standard FITS keywords + (e.g. DATE-OBS, EXPTIME). However, if 'barycentric' is set to True, the + value used is the Barycentric Julian Date in Barycentric Dynamical Time + (BJD_TDB)). This is a non-standard FITS keyword, but commonly used in + the exoplanet community for high-accuracy observations. For more + information, see http://astroutils.astronomy.ohio-state.edu/time/. + """ + + if barycentric: + return self._read_barycentric_date( + bjd_keyword, ra_keyword, dec_keyword) + return self._read_uncorrected_date( + date_keyword, time_keyword, exp_keyword=exp_keyword) + + def _read_barycentric_date(self, bjd_keyword, ra_keyword, dec_keyword): + """Returns the Barycentric Julian Date as a UTC timestamp.""" + + bjd_tdb = self.read_keyword(bjd_keyword) + ra = self.ra(ra_keyword=ra_keyword) + dec = self.dec(dec_keyword=dec_keyword) + + logging.debug( + "Converting %f (%s, α=%f, δ=%f) to JD UTC", + bjd_tdb, bjd_keyword, ra, dec) + + jd_utc = barycorr.bjd2utc(bjd_tdb, ra, dec) + + logging.debug( + "%f (%s, α=%f, δ=%f) = %f (JD UTC)", + bjd_tdb, bjd_keyword, ra, dec, jd_utc) + + t = astropy.time.Time(jd_utc, format='jd', scale='utc') + logging.debug("%f (JD UTC) = %f (UTC timestamp)", jd_utc, t.unix) + return t.unix + + def _read_uncorrected_date(self, date_keyword, time_keyword, exp_keyword): """ Return the date of observation (UTC), in Unix time. This method returns, in seconds after the Unix epoch (the time 00:00:00 UTC on 1 January 1970), the date at the 'midpoint' of the observation. This is defined as the time of the start of the exposure plus one-half - the exposure duration. It must be pointed out that these dates are - *always* interpreted as Coordinated Universal Time (UTC). + the exposure duration. + + This function makes no assumptions or corrections for the time reference + frame (e.g. geocentric, heliocentric or barycentric; i.e. the different + geometric locations from which one could measure time, differing by the + light-travel time between them). It simply just returns the date found + in the header as a UTC timestamp. The KeyError exception is raised if any of the specified keywords cannot be found in the FITS header. NonStandardFITS is thrown if the @@ -541,7 +596,7 @@ def ra(self, ra_keyword = keywords.rak): logging.debug(msg3) # HH:MM:SS[.sss] - regexp = '^(?P\d{2}):(?P\d{2}):(?P\d{2}(\.\d{0,3})?)$' + regexp = '^(?P\d{2})[:\s](?P\d{2})[:\s](?P\d{2}(\.\d{0,3})?)$' match = re.match(regexp, ra_str.strip()) if match: hh = int(match.group('hh')) @@ -556,8 +611,8 @@ def ra(self, ra_keyword = keywords.rak): logging.debug("{0}: α = {1:.5f}".format(self.path, ra)) return ra else: - msg = "{0}: '{1}' not in decimal degrees or 'HH:MM:SS.sss' format" - raise ValueError(msg.format(self.path, ra_keyword)) + msg = "{0}: '{1}' not in decimal degrees or 'HH:MM:SS.sss' format (got = {2!r})" + raise ValueError(msg.format(self.path, ra_keyword, ra_str)) def dec(self, dec_keyword = keywords.deck): """ Return the declination, in decimal degrees. @@ -590,7 +645,7 @@ def dec(self, dec_keyword = keywords.deck): logging.debug(msg3) # DD:MM:SS[.sss] - regexp = '^(?P
([-+])?\d{2}):(?P\d{2}):(?P\d{2}(\.\d{0,3})?)$' + regexp = '^(?P
([-+])?\d{2})[:\s](?P\d{2})[:\s](?P\d{2}(\.\d{0,3})?)$' match = re.match(regexp, dec_str.strip()) if match: dd = int(match.group('dd')) @@ -605,8 +660,8 @@ def dec(self, dec_keyword = keywords.deck): logging.debug("{0}: δ = {1:.5f}".format(self.path, dec)) return dec else: - msg = "{0}: '{1}' not in decimal degrees or 'DD:MM:SS.sss' format" - raise ValueError(msg.format(self.path, dec_keyword)) + msg = "{0}: '{1}' not in decimal degrees or 'DD:MM:SS.sss' format (got = {2!r}" + raise ValueError(msg.format(self.path, dec_keyword, dec_str)) @property def prefix(self): diff --git a/keywords.py b/keywords.py index c63aa9dc..24509ab3 100644 --- a/keywords.py +++ b/keywords.py @@ -104,3 +104,11 @@ "determine the number of counts at which saturation arises in coadded " \ "observations. If the keyword is missing, we assume a value of one (that " \ "is, that the observation consisted of a single exposure) [default: %default]" + +bjdk = 'BJD_TDB' +desc['bjdk'] = ( +"keyword for the barycentric JD (TDB, Barycentric Dynamical Time) at " +"mid-exposure. Internally, LEMON stores all times as UTC Unix timestamps, so " +"BJD_TDB is converted to JD_UTC using Jason Eastman's web applet for time " +"correction (htttp://astroutils.astronomy.ohio-state.edu/time/bjd2utc.html) " +"[default: %default]") diff --git a/photometry.py b/photometry.py index 28bba225..b0496dc7 100644 --- a/photometry.py +++ b/photometry.py @@ -190,9 +190,15 @@ def parallel_photometry(args): pfilter = image.pfilter(options.filterk) logging.debug("%s: filter = %s" % (image.path, pfilter)) - kwargs = dict(date_keyword = options.datek, - time_keyword = options.timek, - exp_keyword = options.exptimek) + kwargs = dict( + date_keyword=options.datek, + time_keyword=options.timek, + exp_keyword=options.exptimek, + barycentric=options.barycentric, + bjd_keyword=options.bjdk, + ra_keyword=options.rak, + dec_keyword=options.deck, + ) unix_time = image.date(**kwargs) msg = "%s: observation date: %.2f (%s)" args = (image.path, unix_time, util.utctime(unix_time)) @@ -460,6 +466,36 @@ def parallel_photometry(args): dest = 'uncimgk', default = keywords.uncimgk, help = keywords.desc['uncimgk']) +key_group.add_option('--rak', action = 'store', type = 'str', + dest = 'rak', default = keywords.rak, + help = keywords.desc['rak']) + +key_group.add_option('--deck', action = 'store', type = 'str', + dest = 'deck', default = keywords.deck, + help = keywords.desc['deck']) + +bjd_group = optparse.OptionGroup(parser, + "Barycentric Julian Dates [experimental]" , + "By default, LEMON determines the date of mid-exposure via the --datek, " + "--timek and --expk keywords in the FITS header. However, high-accuracy " + "observations (e.g. transits of binaries or exoplanets) commonly use " + "Barycentric Julian Dates in Barycentric Dynamical Time (BJD_TDB). This " + "corrects for the amount of time it took light to travel to the changing " + "location of the observatory. For a brief, non-technical explanation, see " + "http://astroutils.astronomy.ohio-state.edu/time/bjd_explanation.html") + +bjd_group.add_option('--use_barycentric', action = 'store_true', + dest = 'barycentric', + help = "Use Barycentric Julian Dates in Barycentric " + "Dynamical Time (BJD_TDB). These dates are read from " + "the --bjdk FITS keyword.") + +bjd_group.add_option('--bjdk', action = 'store', type = 'str', + dest = 'bjdk', default = keywords.bjdk, + help = keywords.desc['bjdk']) + +parser.add_option_group(bjd_group) + parser.add_option_group(key_group) customparser.clear_metavars(parser) @@ -675,9 +711,15 @@ def main(arguments = None): def get_date(img): """ Return the date() of a FITSImage object """ - return img.date(date_keyword = options.datek, - time_keyword = options.timek, - exp_keyword = options.exptimek) + return img.date( + date_keyword=options.datek, + time_keyword=options.timek, + exp_keyword=options.exptimek, + barycentric=options.barycentric, + bjd_keyword=options.bjdk, + ra_keyword=options.rak, + dec_keyword=options.deck, + ) files = fitsimage.InputFITSFiles() img_dates = {} diff --git a/requirements.txt b/requirements.txt index d8b77b56..4f305604 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ # setup.py files, not pip's fault. Serial installation is the only # answer here [https://github.com/pypa/pip/issues/25] +absl-py>=0.9.0 APLpy>=0.9.9 scipy>=0.12.0 matplotlib>=1.2.1 @@ -17,3 +18,5 @@ unittest2>=0.5.1 montage-wrapper>=0.9.7 requests>=2.0.1 subprocess32>=3.2.6 +requests-cache>=0.5.2 +requests-mock>=1.7.0 diff --git a/test/test_data/fits/HD23642_20200222_0050u.fit b/test/test_data/fits/HD23642_20200222_0050u.fit new file mode 100644 index 00000000..12a543b6 --- /dev/null +++ b/test/test_data/fits/HD23642_20200222_0050u.fit @@ -0,0 +1,9278 @@ +SIMPLE = T / Created by ImageJ FITS_Writer BITPIX = 16 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 533 / length of data axis 1 NAXIS2 = 400 / length of data axis 2 BZERO = 32768.0 / data range offset BSCALE = 1.0 / scaling factor DATE-OBS= '2020-02-22T19:41:54' / [ISO 8601] UTC date/time of exposure start EXPTIME = 9.00000000000E+001 / [sec] Duration of exposure EXPOSURE= 9.00000000000E+001 / [sec] Duration of exposure SET-TEMP= -20.000000000000000 /CCD temperature setpoint in C CCD-TEMP= -20.417621345447451 /CCD temperature at start of exposure in C XPIXSZ = 22.199999999999999 /Pixel Width in microns (after binning) YPIXSZ = 22.199999999999999 /Pixel Height in microns (after binning) XBINNING= 3 / Binning level along the X-axis YBINNING= 3 / Binning level along the Y-axis XORGSUBF= 0 /Subframe X position in binned pixels YORGSUBF= 0 /Subframe Y position in binned pixels READOUTM= 'Raw ' / Readout mode of image FILTER = 'u'' ' / Filter name IMAGETYP= 'LIGHT ' / Type of image FOCALLEN= 1200.0000000000000 /Focal length of telescope in mm APTDIA = 150.00000000000000 /Aperture diameter of telescope in mm APTAREA = 17671.459168195724 /Aperture area of telescope in mm^2 EGAIN = 0.93000000715255737 /Electronic gain in e-/ADU SWCREATE= 'MaxIm DL Version 6.11 141223 1VH7F' /Name of software SWSERIAL= '1VH7F-K9Y6J-9C35K-TUXJ7-6J8QF-V2' /Software serial number OBJECT = 'Autosave Image' / Target object name OBJCTRA = '03 47 24.00' / [hms J2000] Target right ascension OBJCTDEC= '+24 15 19.0' / [dms +N J2000] Target declination OBJCTALT= ' 54.0234' / Nominal altitude of center of image OBJCTAZ = '244.0597' / Nominal azimuth of center of image OBJCTHA = ' 2.3619' / Nominal hour angle of center of image PIERSIDE= 'EAST ' / Side of pier telescope is on SITELAT = 46.62716944444445 / geographic latitude of observatory SITELONG= 4.5404583333333335 / geographic longitude of observatory JD = 2458902.3207638888 /Julian Date at start of exposure JD-HELIO= 2458902.3209503954 /Heliocentric Julian Date at exposure midpoint AIRMASS = 1.2322413297700756 / Target airmass at mid-exposure TELESCOP= '6 inch achromatic refractor F8' / Telescope name image INSTRUME= 'SBIG ST-2K 3 CCD Camera' / Detector instrument name OBSERVER= 'Vivien Pic' / Observer name NOTES = ' ' FLIPSTAT= ' ' SWMODIFY= 'MaxIm DL Version 6.11 141223 1VH7F' /Name of software HISTORY Bias Subtraction (Bias 2, 533 x 400, Bin3 x 3, Temp -20C, HISTORY Exp Time 0ms) CALSTAT = 'BDF ' HISTORY Dark Subtraction (Dark 2, 533 x 400, Bin3 x 3, Temp -20C, HISTORY Exp Time 90s) HISTORY Flat Field (Flat 1, 533 x 400, Bin3 x 3, Temp -20C, Exp Time 300ms) HISTORY Flat-Bias(Bias 2,533 x 400,Bin3 x 3,Temp -20C,Exp Time 0ms) HISTORY Flat-Dark (Dark 2,533 x 400,Bin3 x 3,Temp -20C,Exp Time 90s) PEDESTAL= 0 / Correction to add for zero-based ADU SWOWNER = 'Tan Yong Liang' / Licensed owner of software HISTORY File was processed by PinPoint 6.0.5 at 2020-02-22T19:43:30 DATE = '22/02/20' / [old format] UTC date of exposure start TIME-OBS= '19:41:54' / [old format] UTC time of exposure start UT = '19:41:54' / [old format] UTC time of exposure start TIMESYS = 'UTC ' / Default time system RADECSYS= 'FK5 ' / Equatorial coordinate system RA = '03 47 24.00' / [hms J2000] Target right ascension DEC = '+24 15 19.0' / [dms +N J2000] Target declination FWHM = 1.72772622705E+000 / [pixels] Mean Full-Width-Half-Max of image starZMAG = 1.31188288243E+001 / Mag zero point for 1 sec exposure COMMENT Original key: "EQUINOX" _QUINOX = 2000.0 / Equatorial coordinates are J2000 EPOCH = 2000.0 / (incorrect but needed by old programs) PA = 1.99270276808E+002 / [deg, 0-360 CCW] Position angle of plate HISTORY WCS added by PinPoint 6.0.5 at 2020-02-22T19:43:30 HISTORY Matched 21 stars from the Gray GSC-ACT Catalog HISTORY Average residual was 0.83 arc-seconds INPUTFMT= 'FITS ' / Format of file from which image was read HISTORY Align Images CSTRETCH= 'Medium ' / Initial display stretch mode CBLACK = 100 /Initial display black level in ADUs CWHITE = 231 /Initial display white level in ADUs HISTORY Removed pedestal value of -100.0 from image Autosave Image -0050u.fi HISTORY ... t JD_SOBS = 2458902.320763889 / Julian Date at start of exposure JD_UTC = 2458902.321284722 / Julian Date (UTC) at mid-exposure HJD_UTC = 2458902.3209500727 / Heliocentric JD (UTC) at mid-exposure BJD_TDB = 2458902.321777873 / Barycentric JD (TDB) at mid-exposure ALT_OBJ = 54.190615117683144 / Target altitude at mid-exposure AZ_OBJ = 243.85281945180117 / Target azimuth at mid-exposure HA_OBJ = 2.3477086833935705 / Target hour angle at mid-exposure ZD_OBJ = 35.809384882316856 / Target zenith distance at mid-exposure RAOBJ2K = 3.791515 / J2000 right ascension of target (hours) DECOBJ2K= 24.28833888888889 / J2000 declination of target (degrees) RA_OBJ = 3.8112177929805324 / EOD right ascension of target (hours) DEC_OBJ = 24.348687098600077 / EOD declination of target (degrees) HISTORY Previous Filename = Autosave Image -0050u.fit COMMENT Original key: "END" COMMENT COMMENT --Start of Astrometry.net WCS solution-- COMMENT --Put in by the new-wcs program-- COMMENT WCSAXES = 2 / no comment CTYPE1 = 'RA---TAN-SIP' / TAN (gnomic) projection + SIP distortions CTYPE2 = 'DEC--TAN-SIP' / TAN (gnomic) projection + SIP distortions EQUINOX = 2000.0 / Equatorial coordinates definition (yr) LONPOLE = 180.0 / no comment LATPOLE = 0.0 / no comment CRVAL1 = 56.981131259 / RA of reference point CRVAL2 = 24.2637840631 / DEC of reference point CRPIX1 = 349.875751495 / X reference pixel CRPIX2 = 209.236545563 / Y reference pixel CUNIT1 = 'deg ' / X pixel scale units CUNIT2 = 'deg ' / Y pixel scale units CD1_1 = 0.000992828526848 / Transformation matrix CD1_2 = 0.000346183138867 / no comment CD2_1 = -0.000346748126831 / no comment CD2_2 = 0.000992674074969 / no comment IMAGEW = 533 / Image width, in pixels. IMAGEH = 400 / Image height, in pixels. A_ORDER = 2 / Polynomial order, axis 1 A_0_0 = 0 / no comment A_0_1 = 0 / no comment A_0_2 = -2.45947747586E-06 / no comment A_1_0 = 0 / no comment A_1_1 = -2.09268658969E-07 / no comment A_2_0 = -3.89422629306E-08 / no comment B_ORDER = 2 / Polynomial order, axis 2 B_0_0 = 0 / no comment B_0_1 = 0 / no comment B_0_2 = 1.60066913822E-05 / no comment B_1_0 = 0 / no comment B_1_1 = 3.58742064329E-07 / no comment B_2_0 = -6.95662561738E-06 / no comment AP_ORDER= 2 / Inv polynomial order, axis 1 AP_0_0 = -1.30934748958E-05 / no comment AP_0_1 = -1.35156665198E-06 / no comment AP_0_2 = 2.46201449006E-06 / no comment AP_1_0 = -8.56676631634E-08 / no comment AP_1_1 = 2.03655664928E-07 / no comment AP_2_0 = 3.82569252693E-08 / no comment BP_ORDER= 2 / Inv polynomial order, axis 2 BP_0_0 = 0.000133679693051 / no comment BP_0_1 = 8.87912981034E-06 / no comment BP_0_2 = -1.60249099309E-05 / no comment BP_1_0 = 1.01689137826E-06 / no comment BP_1_1 = -3.23017999325E-07 / no comment BP_2_0 = 6.9591760734E-06 / no comment HISTORY Created by the Astrometry.net suite. HISTORY For more details, see http://astrometry.net. HISTORY Git URL https://github.com/dstndstn/astrometry.net HISTORY Git revision 0.73 HISTORY Git date Thu_Nov_16_08:30:44_2017_-0500 HISTORY This WCS header was created by the program "blind". HISTORY Astrometry done via LEMON on Sun Feb 23 15:21:54 2020 UTC HISTORY [Astrometry] WCS solution found by Astrometry.net HISTORY [Astrometry] Original image: 20200222/HD23642-0050u_out.fit COMMENT Original WCS key: "DATE" _ATE = '2020-02-23T16:21:54' / Date this file was created. COMMENT -- blind solver parameters: -- COMMENT Index(0): /usr/local/astrometry/data/index-4219.fits COMMENT Index(1): /usr/local/astrometry/data/index-4218.fits COMMENT Index(2): /usr/local/astrometry/data/index-4217.fits COMMENT Index(3): /usr/local/astrometry/data/index-4216.fits COMMENT Index(4): /usr/local/astrometry/data/index-4215.fits COMMENT Index(5): /usr/local/astrometry/data/index-4214.fits COMMENT Index(6): /usr/local/astrometry/data/index-4213.fits COMMENT Index(7): /usr/local/astrometry/data/index-4212.fits COMMENT Index(8): /usr/local/astrometry/data/index-4211.fits COMMENT Index(9): /usr/local/astrometry/data/index-4210.fits COMMENT Index(10): /usr/local/astrometry/data/index-4209.fits COMMENT Index(11): /usr/local/astrometry/data/index-4208.fits COMMENT Index(12): /usr/local/astrometry/data/index-4207-11.fits COMMENT Index(13): /usr/local/astrometry/data/index-4207-10.fits COMMENT Index(14): /usr/local/astrometry/data/index-4207-09.fits COMMENT Index(15): /usr/local/astrometry/data/index-4207-08.fits COMMENT Index(16): /usr/local/astrometry/data/index-4207-07.fits COMMENT Index(17): /usr/local/astrometry/data/index-4207-06.fits COMMENT Index(18): /usr/local/astrometry/data/index-4207-05.fits COMMENT Index(19): /usr/local/astrometry/data/index-4207-04.fits COMMENT Index(20): /usr/local/astrometry/data/index-4207-03.fits COMMENT Index(21): /usr/local/astrometry/data/index-4207-02.fits COMMENT Index(22): /usr/local/astrometry/data/index-4207-01.fits COMMENT Index(23): /usr/local/astrometry/data/index-4207-00.fits COMMENT Index(24): /usr/local/astrometry/data/index-4206-11.fits COMMENT Index(25): /usr/local/astrometry/data/index-4206-10.fits COMMENT Index(26): /usr/local/astrometry/data/index-4206-09.fits COMMENT Index(27): /usr/local/astrometry/data/index-4206-08.fits COMMENT Index(28): /usr/local/astrometry/data/index-4206-07.fits COMMENT Index(29): /usr/local/astrometry/data/index-4206-06.fits COMMENT Index(30): /usr/local/astrometry/data/index-4206-05.fits COMMENT Index(31): /usr/local/astrometry/data/index-4206-04.fits COMMENT Index(32): /usr/local/astrometry/data/index-4206-03.fits COMMENT Index(33): /usr/local/astrometry/data/index-4206-02.fits COMMENT Index(34): /usr/local/astrometry/data/index-4206-01.fits COMMENT Index(35): /usr/local/astrometry/data/index-4206-00.fits COMMENT Index(36): /usr/local/astrometry/data/index-4205-11.fits COMMENT Index(37): /usr/local/astrometry/data/index-4205-10.fits COMMENT Index(38): /usr/local/astrometry/data/index-4205-09.fits COMMENT Index(39): /usr/local/astrometry/data/index-4205-08.fits COMMENT Index(40): /usr/local/astrometry/data/index-4205-07.fits COMMENT Index(41): /usr/local/astrometry/data/index-4205-06.fits COMMENT Index(42): /usr/local/astrometry/data/index-4205-05.fits COMMENT Index(43): /usr/local/astrometry/data/index-4205-04.fits COMMENT Index(44): /usr/local/astrometry/data/index-4205-03.fits COMMENT Index(45): /usr/local/astrometry/data/index-4205-02.fits COMMENT Index(46): /usr/local/astrometry/data/index-4205-01.fits COMMENT Index(47): /usr/local/astrometry/data/index-4205-00.fits COMMENT Index(48): /usr/local/astrometry/data/index-4204-47.fits COMMENT Index(49): /usr/local/astrometry/data/index-4204-46.fits COMMENT Index(50): /usr/local/astrometry/data/index-4204-45.fits COMMENT Index(51): /usr/local/astrometry/data/index-4204-44.fits COMMENT Index(52): /usr/local/astrometry/data/index-4204-43.fits COMMENT Index(53): /usr/local/astrometry/data/index-4204-42.fits COMMENT Index(54): /usr/local/astrometry/data/index-4204-41.fits COMMENT Index(55): /usr/local/astrometry/data/index-4204-40.fits COMMENT Index(56): /usr/local/astrometry/data/index-4204-39.fits COMMENT Index(57): /usr/local/astrometry/data/index-4204-38.fits COMMENT Index(58): /usr/local/astrometry/data/index-4204-37.fits COMMENT Index(59): /usr/local/astrometry/data/index-4204-36.fits COMMENT Index(60): /usr/local/astrometry/data/index-4204-35.fits COMMENT Index(61): /usr/local/astrometry/data/index-4204-34.fits COMMENT Index(62): /usr/local/astrometry/data/index-4204-33.fits COMMENT Index(63): /usr/local/astrometry/data/index-4204-32.fits COMMENT Index(64): /usr/local/astrometry/data/index-4204-31.fits COMMENT Index(65): /usr/local/astrometry/data/index-4204-30.fits COMMENT Index(66): /usr/local/astrometry/data/index-4204-29.fits COMMENT Index(67): /usr/local/astrometry/data/index-4204-28.fits COMMENT Index(68): /usr/local/astrometry/data/index-4204-27.fits COMMENT Index(69): /usr/local/astrometry/data/index-4204-26.fits COMMENT Index(70): /usr/local/astrometry/data/index-4204-25.fits COMMENT Index(71): /usr/local/astrometry/data/index-4204-24.fits COMMENT Index(72): /usr/local/astrometry/data/index-4204-23.fits COMMENT Index(73): /usr/local/astrometry/data/index-4204-22.fits COMMENT Index(74): /usr/local/astrometry/data/index-4204-21.fits COMMENT Index(75): /usr/local/astrometry/data/index-4204-20.fits COMMENT Index(76): /usr/local/astrometry/data/index-4204-19.fits COMMENT Index(77): /usr/local/astrometry/data/index-4204-18.fits COMMENT Index(78): /usr/local/astrometry/data/index-4204-17.fits COMMENT Index(79): /usr/local/astrometry/data/index-4204-16.fits COMMENT Index(80): /usr/local/astrometry/data/index-4204-15.fits COMMENT Index(81): /usr/local/astrometry/data/index-4204-14.fits COMMENT Index(82): /usr/local/astrometry/data/index-4204-13.fits COMMENT Index(83): /usr/local/astrometry/data/index-4204-12.fits COMMENT Index(84): /usr/local/astrometry/data/index-4204-11.fits COMMENT Index(85): /usr/local/astrometry/data/index-4204-10.fits COMMENT Index(86): /usr/local/astrometry/data/index-4204-09.fits COMMENT Index(87): /usr/local/astrometry/data/index-4204-08.fits COMMENT Index(88): /usr/local/astrometry/data/index-4204-07.fits COMMENT Index(89): /usr/local/astrometry/data/index-4204-06.fits COMMENT Index(90): /usr/local/astrometry/data/index-4204-05.fits COMMENT Index(91): /usr/local/astrometry/data/index-4204-04.fits COMMENT Index(92): /usr/local/astrometry/data/index-4204-03.fits COMMENT Index(93): /usr/local/astrometry/data/index-4204-02.fits COMMENT Index(94): /usr/local/astrometry/data/index-4204-01.fits COMMENT Index(95): /usr/local/astrometry/data/index-4204-00.fits COMMENT Index(96): /usr/local/astrometry/data/index-4203-47.fits COMMENT Index(97): /usr/local/astrometry/data/index-4203-46.fits COMMENT Index(98): /usr/local/astrometry/data/index-4203-45.fits COMMENT Index(99): /usr/local/astrometry/data/index-4203-44.fits COMMENT Index(100): /usr/local/astrometry/data/index-4203-43.fits COMMENT Index(101): /usr/local/astrometry/data/index-4203-42.fits COMMENT Index(102): /usr/local/astrometry/data/index-4203-41.fits COMMENT Index(103): /usr/local/astrometry/data/index-4203-40.fits COMMENT Index(104): /usr/local/astrometry/data/index-4203-39.fits COMMENT Index(105): /usr/local/astrometry/data/index-4203-38.fits COMMENT Index(106): /usr/local/astrometry/data/index-4203-37.fits COMMENT Index(107): /usr/local/astrometry/data/index-4203-36.fits COMMENT Index(108): /usr/local/astrometry/data/index-4203-35.fits COMMENT Index(109): /usr/local/astrometry/data/index-4203-34.fits COMMENT Index(110): /usr/local/astrometry/data/index-4203-33.fits COMMENT Index(111): /usr/local/astrometry/data/index-4203-32.fits COMMENT Index(112): /usr/local/astrometry/data/index-4203-31.fits COMMENT Index(113): /usr/local/astrometry/data/index-4203-30.fits COMMENT Index(114): /usr/local/astrometry/data/index-4203-29.fits COMMENT Index(115): /usr/local/astrometry/data/index-4203-28.fits COMMENT Index(116): /usr/local/astrometry/data/index-4203-27.fits COMMENT Index(117): /usr/local/astrometry/data/index-4203-26.fits COMMENT Index(118): /usr/local/astrometry/data/index-4203-25.fits COMMENT Index(119): /usr/local/astrometry/data/index-4203-24.fits COMMENT Index(120): /usr/local/astrometry/data/index-4203-23.fits COMMENT Index(121): /usr/local/astrometry/data/index-4203-22.fits COMMENT Index(122): /usr/local/astrometry/data/index-4203-21.fits COMMENT Index(123): /usr/local/astrometry/data/index-4203-20.fits COMMENT Index(124): /usr/local/astrometry/data/index-4203-19.fits COMMENT Index(125): /usr/local/astrometry/data/index-4203-18.fits COMMENT Index(126): /usr/local/astrometry/data/index-4203-17.fits COMMENT Index(127): /usr/local/astrometry/data/index-4203-16.fits COMMENT Index(128): /usr/local/astrometry/data/index-4203-15.fits COMMENT Index(129): /usr/local/astrometry/data/index-4203-14.fits COMMENT Index(130): /usr/local/astrometry/data/index-4203-13.fits COMMENT Index(131): /usr/local/astrometry/data/index-4203-12.fits COMMENT Index(132): /usr/local/astrometry/data/index-4203-11.fits COMMENT Index(133): /usr/local/astrometry/data/index-4203-10.fits COMMENT Index(134): /usr/local/astrometry/data/index-4203-09.fits COMMENT Index(135): /usr/local/astrometry/data/index-4203-08.fits COMMENT Index(136): /usr/local/astrometry/data/index-4203-07.fits COMMENT Index(137): /usr/local/astrometry/data/index-4203-06.fits COMMENT Index(138): /usr/local/astrometry/data/index-4203-05.fits COMMENT Index(139): /usr/local/astrometry/data/index-4203-04.fits COMMENT Index(140): /usr/local/astrometry/data/index-4203-03.fits COMMENT Index(141): /usr/local/astrometry/data/index-4203-02.fits COMMENT Index(142): /usr/local/astrometry/data/index-4203-01.fits COMMENT Index(143): /usr/local/astrometry/data/index-4203-00.fits COMMENT Index(144): /usr/local/astrometry/data/index-4202-47.fits COMMENT Index(145): /usr/local/astrometry/data/index-4202-46.fits COMMENT Index(146): /usr/local/astrometry/data/index-4202-45.fits COMMENT Index(147): /usr/local/astrometry/data/index-4202-44.fits COMMENT Index(148): /usr/local/astrometry/data/index-4202-43.fits COMMENT Index(149): /usr/local/astrometry/data/index-4202-42.fits COMMENT Index(150): /usr/local/astrometry/data/index-4202-41.fits COMMENT Index(151): /usr/local/astrometry/data/index-4202-40.fits COMMENT Index(152): /usr/local/astrometry/data/index-4202-39.fits COMMENT Index(153): /usr/local/astrometry/data/index-4202-38.fits COMMENT Index(154): /usr/local/astrometry/data/index-4202-37.fits COMMENT Index(155): /usr/local/astrometry/data/index-4202-36.fits COMMENT Index(156): /usr/local/astrometry/data/index-4202-35.fits COMMENT Index(157): /usr/local/astrometry/data/index-4202-34.fits COMMENT Index(158): /usr/local/astrometry/data/index-4202-33.fits COMMENT Index(159): /usr/local/astrometry/data/index-4202-32.fits COMMENT Index(160): /usr/local/astrometry/data/index-4202-31.fits COMMENT Index(161): /usr/local/astrometry/data/index-4202-30.fits COMMENT Index(162): /usr/local/astrometry/data/index-4202-29.fits COMMENT Index(163): /usr/local/astrometry/data/index-4202-28.fits COMMENT Index(164): /usr/local/astrometry/data/index-4202-27.fits COMMENT Index(165): /usr/local/astrometry/data/index-4202-26.fits COMMENT Index(166): /usr/local/astrometry/data/index-4202-25.fits COMMENT Index(167): /usr/local/astrometry/data/index-4202-24.fits COMMENT Index(168): /usr/local/astrometry/data/index-4202-23.fits COMMENT Index(169): /usr/local/astrometry/data/index-4202-22.fits COMMENT Index(170): /usr/local/astrometry/data/index-4202-21.fits COMMENT Index(171): /usr/local/astrometry/data/index-4202-20.fits COMMENT Index(172): /usr/local/astrometry/data/index-4202-19.fits COMMENT Index(173): /usr/local/astrometry/data/index-4202-18.fits COMMENT Index(174): /usr/local/astrometry/data/index-4202-17.fits COMMENT Index(175): /usr/local/astrometry/data/index-4202-16.fits COMMENT Index(176): /usr/local/astrometry/data/index-4202-15.fits COMMENT Index(177): /usr/local/astrometry/data/index-4202-14.fits COMMENT Index(178): /usr/local/astrometry/data/index-4202-13.fits COMMENT Index(179): /usr/local/astrometry/data/index-4202-12.fits COMMENT Index(180): /usr/local/astrometry/data/index-4202-11.fits COMMENT Index(181): /usr/local/astrometry/data/index-4202-10.fits COMMENT Index(182): /usr/local/astrometry/data/index-4202-09.fits COMMENT Index(183): /usr/local/astrometry/data/index-4202-08.fits COMMENT Index(184): /usr/local/astrometry/data/index-4202-07.fits COMMENT Index(185): /usr/local/astrometry/data/index-4202-06.fits COMMENT Index(186): /usr/local/astrometry/data/index-4202-05.fits COMMENT Index(187): /usr/local/astrometry/data/index-4202-04.fits COMMENT Index(188): /usr/local/astrometry/data/index-4202-03.fits COMMENT Index(189): /usr/local/astrometry/data/index-4202-02.fits COMMENT Index(190): /usr/local/astrometry/data/index-4202-01.fits COMMENT Index(191): /usr/local/astrometry/data/index-4202-00.fits COMMENT Field name: COMMENT /tmp/HD23642-0050u_out_91BXbL_astrometry.net/HD23642-0050u COMMENT _out.axy COMMENT Field scale lower: 0.675422 arcsec/pixel COMMENT Field scale upper: 1215.76 arcsec/pixel COMMENT X col name: X COMMENT Y col name: Y COMMENT Start obj: 0 COMMENT End obj: 0 COMMENT Solved_in: (null) COMMENT Solved_out: COMMENT /tmp/HD23642-0050u_out_91BXbL_astrometry.net/HD23642-0050u COMMENT _out.solved COMMENT Solvedserver: (null) COMMENT Parity: 2 COMMENT Codetol: 0.01 COMMENT Verify pixels: 1 pix COMMENT Maxquads: 0 COMMENT Maxmatches: 0 COMMENT Cpu limit: 300.000000 s COMMENT Time limit: 0 s COMMENT Total time limit: 0 s COMMENT Total CPU limit: 0.000000 s COMMENT Tweak: yes COMMENT Tweak AB order: 2 COMMENT Tweak ABP order: 2 COMMENT -- COMMENT -- properties of the matching quad: -- COMMENT index id: 4206 COMMENT index healpix: 0 COMMENT index hpnside: 1 COMMENT log odds: 92.8158 COMMENT odds: 2.0388e+40 COMMENT quadno: 472178 COMMENT stars: 229924,229941,229926,229771 COMMENT field: 2,0,12,3 COMMENT code error: 0.00880733 COMMENT nmatch: 21 COMMENT nconflict: 2 COMMENT nfield: 54 COMMENT nindex: 41 COMMENT scale: 3.7853 arcsec/pix COMMENT parity: 1 COMMENT quads tried: 70849 COMMENT quads matched: 109654 COMMENT quads verified: 108168 COMMENT objs tried: 13 COMMENT cpu time: 3.46173 COMMENT -- COMMENT COMMENT --End of Astrometry.net WCS-- COMMENT --(Put in by the new-wcs program)-- COMMENT END         +         +    + + + + +      + +    +    +   + +   + +      + &@     &"!& ##,-#'#$!*&-!, 4!**,+5>.8*?.77+>05)4?)<1=IOAG656;/COF4NXJ:7B4>?B@@II=M,COGECN081;?BE1,6?7$*:P9-8&.=@:6.966:9370/:"3&)" #  +         +     +   +    +                +              + +   2&% $2&/:+'."($4+33?83,)11///$.):3 /S;95I05CAEHBG=DD4=?8:FFH:.?HP;N56>:/5:7?9,74.1$.)6!% +2+ +&!     +    +    +      +     + +       +    +   +        +   +    +  + +  +  + +   +    +       !  $*#$# %$*/.0$*+)%,.!"*#066+.F81>&68;2>+:A:/=31>#=?FF=J??;>H:9F8-8B>F72M8:HB5CE=I,*CNC8J29=B-@<,50-F.?90011C2;8,,$61,;(G0&=)+ )#$%           +  +# + +   +     +    +         +       + +     +    + +   "$(! # ($+&, 03))-.;&-;.630;5161D44'1=7+I82:CZXO@>HDDDU0P62RBCHE9K;28<+="/"#. ' + +        1  +  +        +   + +   +  +  + +   +      +    +      +  +  +    +   +     !##' !$$"2'$/) (*%,"3-#5--(0066//9;E4761-5<>4B298;6I7@E2<@4"0-(-.,"&$!!   "  + + +      + + +  (   +   +       + + +    + +      +    +          +      +.!! +&$ $(7#"/(I+!%70'76##9'3*=,6%4:*A>3666?974@5:A40DG.4@:F:@B`@?A;D9:ZJPLJGBICKl?e6D4>ER&4C4==>#!:/<:'2)%<=85-:/5$ ,/2;/ $$' +      +    +  +>   +         +  +  +                +    +            + c%#%%$"$$"-+-0,$+''0*#J;63%$1:84&:6C-B5=H=74F6GI+6&:3CB893<96P@CBhQE?417BA,9;;>35B1&A039987*@$838'4)'-%!  +  + + + ""  +  +  !  +     +   )   +  +   +         + +   +  +  +    +   +  + +   + +      +     9(# !&"&$'%# <-.)# &46'5>-+2"6=733*.?47<9BBH640N=9H<17K:@7>8B51826B@FK58:02:?KZU^PI=RSTNPRTAD7ET??KO9JW:G7>DMBDGC=3382-36:1,67H6,'..%85$('"   +  !!/  +  + + +      + +    + +         +         +     +  +     +  +!"(!" "7A)*1"'52&>3,()+$1*)++/D?*/7>:.BE78/DM314;E(>/l6CM?L_1U>KUS_eC[DU@SWhWQX?P7RH+A>4>7793A7E(;)L888A=J<-+,669&*357,%*!/"" %"!%. $,   $   )  +   +        +  +    +  +   +  +      + +   +     + + +    +    +  % ! *&*)&42#$#/=.*5,2' '#/4*28$21/)8+58;+1I/W>BF+A<2D|:a@8A?)ED;7DPTT\ObDQaS]PNXF>^OT=F?I>34Y;C&M63DE<=.7F214,29<<=7CD#4=+)0!5"4  / 1 +   +    +   +  +         + +  + +       +  + + +  +    +    +   +           +     #$ 4%4)!2&;%+%6/<-7%2/.#%(/)1=5A7C<;4-F#+& 7+4<85"3$*C("*3"4 + $", ! %    % + +         +   +   +  + +    + + +    + +  +     +  + + +     + + +       + + +      +   ""%".,2 9$9)6'<(3/2>',A53D0:<5AI01E=@DBC"7'C9&21F?)842@6*-2+$./+"%     +#   + + +    +   +  +    + +  +       +      + +        +               +  +     (&#!$ #*"/.%-&+#$0'=2=51:813D1.??0%,*##'! +!  %"   +             + +      +  + + +     + + ! +  +   + +   +   + +       +   +  + %  "  "%#)!&-+(,!-,8.8";09B32B'A1?.:/I94B544?A?7.KF>OSQFE@LgHQRWEq`kbcm~|}{mmkT\[TaKW8;86D>IG>KH4;;8043/9B27>-2=)%5(,* 22- 2,  +%0 +#  $   +   +    +  +        +       + +  +   G   + +   +     +     ' '% #&-($ 33/"*$$+6,%&:-H,4&O68>->8;95JA5K@A==*X=QLSXTk`XOZhtyu{wvvurQ]OVFM;U@I?=I@9:4G=LB1/<';'7:%01/-7*$, , ! -- #  +#C     +      ++  +  +  +       +          = +   +  +   +   +  +      + +   +&'"" '** &&&).%+)>(47.<25;.@N,F48O5UELB@RTW]bagpX[Urjyrh|ec]O?`L5S6:PDAD:/1PM?;;B8.4=='8;>+3&5+"( %4#% )  $ -# +" $  $     # +   #     +     +    +  +    +  ),#  + +      + +       + +            -'#*$/7##%(+../43',607C/D:5C3>*2A)G5@C4@78CBFIP=N[EF`d\Ky}RaixÀۀ̀ǀƀjwdhePLK@?RJKFK/328>3@R8J?A554?B<:APSFeJJiV|jch|݀Ȁ€р€̀vt|]lbnn^BFGHS/8>3?=@9?DZ?6GEA=;7410)#"##$+)"( + "    +  + +    + +     +    + +    +  +   + 20v̀݀v;   +  +      +             +   +  +    +  +  +% ,,&!*#2'#2830%-6/$(=(*:((9)C2%L1A@J;A@I>A94E1,11-#*#* %  %/  .         +    +$   + +   +   +     ,L bDW7$    +    +  +   +      + +   + +     +  +         ) $))#$-*+/*9(5;'3.<'59:-;&GK->L20#>9;@==J:>ED?8BTCKUkXeslĀ΀'SŁz?ˀucp`RTL?TcB7274DQCJ5?B;5K;1D7)<8.H4+'")> %)-!#"  "A  $  $##5           + + + + + +              +-JrZm:     +  + + +  + +  + +       + +      +    +  +  + !&&# + +&42,!<$2::%4'2.$%,D@)CHBQHA4++E;1N:^DKFCFJFQJNQ`kXnuˀցQwڂ KhKU$ʁw4瀿xlrEaKDQ:>F6D/BF7#25I53=+5<-$$2 ()'( $0#!)#" '   )    + +   + +  +   $    +    +   %AD`/c,   + + +  +  +   +       +        +  + +% $  %!&%#( ,,02(00!33=70)!,+8,+/S:=U5:9>>H4;SAWZQcX8J^LTZBiW^jȀڀI҂#׃^U񁒁D&߀рkoRh=RAMQHLS@7HRL:+7:9$2/%!;8%6?5%*& $'! #+,$+       + +     #  -&  !            8F#&yրlB# +  +  +       +   +    +    +  + +  +   + + + +    $# '"" #%"$!()!$1/104A1)+4.7317B)E17]1CCG7STBVGmS\ULNBAOQZN\Vyjƀ ?pӃM D/Pqpc`\?SNP?JD?7BO>TDH3;:D>-5H?.8(+*+$$  ((.& !$    + +! &       +      + +    -9#;Fc41    + +      + +         + + +         $'&-'-12#"#,9'-60',*0;C3,0@70;@/F517ZKWgZbPb\o[_E<[]^f{t^{p΀ X兄.CπƀusWgaOOOP@A:)@O6-E8C3<&GF*/,+%*(//-6$(,* "$)& *   $#    #     +   + +  +           +     +4΀> &!4!  + +  +          + + +   + +   +    +  +       +  +% + %$ $*3:,G357,642,5(>+/6)(&2@516-@>?E;M_ZpjuupbkRL`X[Nbwoz܁aʂi򃸄v} ,u! x ԀȀ~lbWUXDTD8VC7FAEJF84"4.*,5>*0=0#.'$!%"!$"$ +$    +  + +       &  +       +  + 7Y% '     +   +   +       +       + +      %&%) 4-#$'&3.&%,+&?<(#)';,58/:02*1@>J]MZcq~lzhnTQ fXY{jw.7؃SڌڈSMX|ovjlTARTS+NK@K=@=K@51F<5.9-"?,:((+'+<) )#+*&-%    +  % +  $        +  +     +   +    +    + +    + +   +  + +         + +     + +  +       !   '((/*" 6$$(&-.,#7*;=%.)62&BA+@*:5:=HBX^bjbosz[m5>,3?3+$-1D58ABMKamЁȀejXxk`Āԁvp0nA]ēÍr OK<46ŀodYid8RLQ2DK:FA;=84AG63( ;&=,.&.$*+.#") +  +  +      +       +  + +       +     + +      +        +    +  + + + +   +   + +&5-/1/ %#,3)"/).55490NB:.01>E;-/1;0.'%2-1"&%%'5%*!  $ +  +  +  +   + +,   +      +       +      +      +                 +   +       3&+/520: (/6/C0;340AA/@QFT?:PUQZdBktQ5Ԁusyirv{w(uۃvڧJJnϊg4ـwUee>]RHA9N/ICH@;C9O,)=5+>P#)=K.;++"'*)% &  " +%     ,     + +   + +  +  +  +R  +   + +  +             + + +     + +   + + +   +       + +    $ ,! #&).,-5008&22-,*(;85FMF,FG.BHCE9c_f΁섖2t0€{rxb~r{΂>l5+ ܎ֆ ˂!ɀ~mf`[EqPSFC`AO=?3*+A7:;15,.I260;"5$>!-=4& (  + +   !       +    #  + +     +  + +  +     +  +  +     +    +      +  +   + ! +  +   + +!#& !" 0*)+/27:*,6+%KS0MHO6GA/BGEFIEXylށLTjohPgmdRl7UK([ 6P˂k0ـwsoISX^V:NcD:X86,;7KDWaOcuɁπ̀~j\SQiYp{0LтaMBc{ZˇƂh!3+΀yeIYIWFHOL@2<7A-19:4M)5D/K*//,( '(1"#   "    $  ! + + +  + +    +     + +  +  + + +  +    +   +  +  +           +    !   !##050#27/#'1;0B2%JRˀ׀QVJ;53N3!J(iyhVOL>1$3N8:."D5>90!)''$((&/ $(       +      +  + + + +     +  + +        +   +   +      + +   +     + +   +  +        $"$%06-/)#/0""'95,(FKa[iFC.;?^hOohibgXKPW^]Pez{GR%cQs"c?ҀԀzl^WLD;E;/L="90W/M6F-*+CDHE2% %**1&'-    "      + #   +    $   '    + + +                   +  +  +              + +  +  + + +      + +  &       #! & $!)=0. /..23576?GDKyހ߀fW40;B79F=MRUJMNqj^`S`TXOe__UUVlՀ^ +CЄ >ۂ恌!Հ}suzI_YS@?HK:*16@22:>A>5&J<<&*0$!,F!-"%"4% + !  #   "%    % +   +   + +   + +       + +   + +  +      +  +  +  + + +  +    +    " " + + % "#()*8*6++%51+?6,(-65AHHu[BBF:,BQ:+J8LEHER@SZ_ga[IQ[SISZRTpف.X_UCW-W0рqYrLMLAOB>GBB69.EA4.745)>3;3,)>1(%!$)2%%%2 + ! %4 + + +$   !    + +        + + + +   + +  +    +    +  + +      +   + + +   + + +   !8!"-. !'2)&6%9B86(@H/=9?ED8I7;:AFIB/=7GCT\C:RQ@JIGUDMJ_`N\UyÀ΁ +QF{N:j9yybZTKQQ>V7G42@:@73%:$9'F'-3%?0@0&9%"$# %14!   % '       +       +  + !      +  +  +       +   +      +  + +  +  +        +     !#3 %!),-+ 2,7'.0,+^BK0<;MH]NEKWBRJLwPZco (ysԁo>2π€_wZ\^SEHWRVDL3N>27A(13/2>3>B7$06 0-)9C54 )0)) 8!  $ #     + +   +   #       +     + +       +  +     +  +    +  +     + +     +  +        +)-"*'$#2:..A:6:=?A59A87>DE>UIDL?=IOKiaVhu}ASSlZA逯svkjZSXEEdFG@SM4.::.D<-+@45B221.I12''(/5/! +,+2 +  + ++ ! & + +  !7 +     +       " +      + +  +   +  +       + +  +  +  + +  +      +  +   !2#%''* 5!)4&2#,#)<2,-=?;O2HT6>@I>*M2DD4I@B=F@OG=E7=N?JHR8BH:7SE5=6305C1H50KF=HK3I5E=? ./17-,+?432: 26!!,", -6     + +     +%         '  +   + +         + +                   + + + +      #"&(0 '2'!),1$!'&7,+8@'71;R23LPfHX/MC05B1@751174>B;JDUBOEVIa]e][`oy{{lh|ob^LHGIOQMMNAL.>757&93I(4L/..43(F%8(,1(#+3 "       +    +   +     0$  + +   +   +    +            +   +     +      +  + +   !    $'0)# 6.)!$6"."/#/>/1=2.@DQ>7C6;6<5?8>:5,3+!0#+ #) # % 0 !     +(   + +   +  +   +   + + + + $    +            +  +  +    +  +    +     + +       #.)2%!1)+%,%++0,5-3,8D:8@Ull؀}EC>4<=4%<812;AC>>3;LTy߃S_L:GP4047K/C66E=AI+7@KKMCOFBHQN[ykrhdqjZuXqwtp__kdX>O\InR1JA4&6ID+ZC7#% /#"+0,?=,9;G0^jȂ vWP:4=:0-,589D B8/=7R&AB999;^YHYK^UXnacKV^^cnrcji\NOmeHBC@QV/3Q>;E4=-0:440GO;55?E;P;T\9_QUavQxv\NSK8&#'%+,$&", * + +!$ +  $0    +  #        +   + +           + + +    +   +       +   + +     +    +        ##'5*-%+,-0A(,&<+9/M&=A4=PcMXJO@9H;=64=88:;C2B88ADFF=966DC;4N1YHWERMOLZOPDQ]WEZ4IGWKOH?L=DI:D$A68,3952)-*)-- (%.!))$$,/"#+"$ *# +  %  +     +           +'=    +   +       +        +      +    +   +      +   + +      +  " #+%. 9).-"(20'.1*'4L),A991JIJN:?5296/74261:*/38>@?E8<442RVKQUFUB)980.<4D1L=QKNQDCA>64+H3A@=3?@53'.-:0-&2-,*" " ,!6+"!'.  +  +   + (  "   !   +             + +  +    +     + +     +      +  +   +  +    +        + +  !)"!$"!13" 2,-)A+!;.6B1D53961-69D609?78D:*@@:<5-0(<&2(2%)#"%" %&(-&(( ,(!   &  +"    +  +    +             +    + +          +         +      +   +   + +  +      "" +!%"/!"A!0!*?#6410;;(>+1//"9240-?/2=86EN?IDJLFJ=I@BF68Z6@=3?>=4JA@K/.OCD2;/9EE32;/3*%,#1$&.&/++!& , "'  %  +(              +    ?       +     +   +      +     +      + +     +   +    +    #,0+&+%3,4/=>+%)&@C/2"6$3+&$*-=90>704:E75)&0-)93(3'C9(-==7@B/O=LGFCFIHF9KH>QC6F6IG*5275>,3,.:/<:63.0:?89=.:3-/>":=D8BN95;45'H):5298$D@J==:ODD67B1E=@D?6&2:0,@875?38>2452$=$3+ .%-(0 /# #" - + + $9:#  + !  +  +      +    + +      +  +         +                      +     +# #"!&$!)."" " 7*&))62053'.-)*5.1,,<):54F9<:=5.7<3.0BG;?8AEA48D(^6>1L-ESK:A91854-C2+*@3167/?0-+1F: 3"7-%$"', "& +#&  #"'&     /ŀ'!   +  +   +  +    +    +  .     + +      + +       + +   + +    +   + +  +    +  +     ("(5)%'&('%C#!$6.96,(0',0277/671(1(0,6%'C(@775.6;5?018B0>87:A5AB;@5LOJ+E3+3'/=D;JC8AJG0*0513)?8,/GF70+2* ,.>#%#,# $ #  "   aZ  4    +   + #* +,    +   + +     + + +      +  +      +        +  + +          +       *$!!#/'! #"&8)$2/837 -'0)81-+!6/.2=1*";+9$2*(4I.6+=1167C-+-691FD@-QN?9<63O1*7EMBEB8>YC0-E4*%1,/#M6+*%4/,!7  +))!&&# + !. +  +   :          +      +        +          +  +   + +   +   + +  +    +      + "!,*&&%--!%":%070".69%6'$-41)/2+4',.2:"B1010A,4>:$7>-<;,%A<674E@9>0;5KC=FC=BC@1N3C-@_;'06G=+(99C49(/">$*$.*#0#$$   "     +   +   +   +        +        + +   +  +      +       + + +  +     +  +  + $!#& ')+,*.#;'!-3=&3"(.)'%-641&5'%.8/-:A(J3)30/589;7>41>=.?$=17;)>CH;H95=<2,.&3-/:H7Q4-$.+22;(E1/"-A+2+')) +(0 +, +!      %(      + '     + +  +    + +         +        +       +   +     *  +    + +   +    ! +$ '' %-(1-4&:?@5)1*?7 '*!4,-';#,;=F3?)0/:4@3,>)+R--7+0"436F+6B4F@5480@CB>=*(7/*1$: 39,3$(+8%)%/!  +   +    + + +)   )  + '    6        + +  + + +  +  +      +   +          + +    +    +. & %( ++((2+-92*.,.+.40=B)40/23>3&2=0B482(B9>).D862!8,:/<7105:50T776F>4BD3D;?<:5"1*30<9;230*/+'-).-  +) +" +  #  +  (           +   +    +      +      + +  +  +   + + +         +    + +       +   +  + +!)" (-131$-*&:40:.#,$'(%(/ ."/-&BE,732N1322>68.2;&747:+=/A+&/2/45*3**,,+;21#-&'+'#>854$*#  " # +  +   + +    +    +        +    +  +    +   +  +   +  +  +    +     +   +    +   + + +   & )$"",<22+(!&;52+/).4A2)!?)&'2"*011++,:@?7@70:4A336@5%77:x2187673/88@958-0549'//7(-'*!('#!#' +!& $             +      +   +  +   +    +    + +   +       +      +        +   +  +  !  #!#$&!$/&&7.%&C:,-.,L-435$%$'%""//* 33*/687:00=5245$;;-81*=2B*.4681-3+@8+MDS/*<8)*,*3*'"!! $#- +  +  ,    + + + +   +  +    %  +      + +  +  +  "   +    +  +   +  +  +   +   +       + +    #(")//,%05%2'&+219/47/36+'.=5('=0+-2(6#4-+F1@-%!0295&4639DD*LF2<,813LM:,9:3 /<;7 +-7&--("#  /# %"  "      &   +     +  +  !     + + +        +   +      +   +  +   +      +        %"%$("0,3$ +43/>1)62**0.+4*2$2-%%-84-LB466BFI;P7/60533.;DA1B-;R/&>29762?,*#/# "" +"+  " #           +   + +  +       +                +      +     +  +  +   +    + +  +  + *%'"*!'$+#*- 08/-0$,1. 75-");/-4*133125&9;,8?,G9-@%4+.3&&7804+/-:2;(&13(7'&<02>!'6&)((#,)/+     "*    +  +  .      +   +   + +        +      +        +     +  + +     +   +  +  +    + +   !$)"&"$!)!(5'+*+'5+)4":6%0('/)($././11@<7)3(%;318H?-,9+8*80/1;:',!:%(F$+*I7$'*!"%  $   &    +  +  (   +  +    +    +' + + +  +  +    + +   +     +  + +           +  +   +     "#   $ &'- &$,"+#4*) +?7.1*340"2*+- (+053'-;(D25&'*38+5.,94,6*;!8?+(*,3,,"?4)*')(!)$$&$ +#)#    &   + + ! +   + +  + +  +     +  +  +    +   + + + + +  + +        +          +   + +   + #'#&%(*###&1"/,555#-,(93% ')*2 28"))$,B !9<#+1;2)68;83%9'( 05925%50/0-')*&((A,%+%" %% "# " !     + +   +    +   +      +    +       +  + +  + +    +   + + + +   +  +  + + +  +         +  +    $&*.!#%&#%$*//615"2++*&+$$.+*8*3*$=!)66 8+3(-?53#84,%?AB7-),,((3/$*,*)1$-.)0.-#$!#  + + +  & $ + +   + + +     +  +   + +      + +   +             +  +       +   +  +  + +     + + +       + -,$#(*"##!"#*/%01-1+$(,,.7@5)";+*5- ;../0.8*9#.00& 04#4.),(,'1<*%'+-?(7)-#! + &  +  + +    +   +         +    +  + + +   +  +    +       +          +   +   + +  + +   +   +  # +!   $"#(%%$&.$(/&)#-27+*2)+%,F44#-(*9*-2 #.+3-*, 4%/!*754',*;"&0!"")$0*7&2/ ((-* + )& 2 !  ! +-  + +#      +  + + +     + "  +   +     +        + + +     +       + +      + +   +    +  " +!"#, ) (&$"5&+)#3$$-,.%06/)3(,:'0>/1+(7;( -2(4('2%*5A#-1,/67,'&*2.!#%-/$$'*'#" 2 &&        +     +  +  +1  + +         +  +      +     +        + +  +     +     +    +  +   + + " $%$&!'-),"'&!5+3/5%&%#G)+$;!""!67/2500)-$)=-(.A&&,+6"#/%$*((#%,' 1 0#"""! !% +   +  &      + "   +                + + +   + +   + +         +     +  +   +   +  + +   +   $ -$"2 '/6 &!*)19,$"!24')-1/J.45)+'(-+,*$ +-,",1%#-(! +!-% ,#   ""# + + ++"       + + + +  +  +  "  + +  +     +          + + + + + +        + +               + +  #!%&-!"("&$6'(/#"-#/-#4%<+"&)*(7# *%#,(#:($,1 +,""1&$)'6 $  &#+    !   + + +&  "   +        + +3  +   +  +    +     + + !     + +    +  +      +  +  +  +  +  +   +    +     &(*""".' &%%0.0!1-<)('4*+&)/)4+!.+&%!()/#?1*0*$-@&&)!'  )# $(#   +  &          +   )  + +  +   +  +         +   +     + +      +          +   +  +   +  +  +! # " % .'"$$%%/*'"&64#-((+$("7$=/&'")#'8) $.8) ,/+/&#) %( %#" #(  " +!  +  "" $ + $"       +      +        +  +  +  +    & + +   +  +    +       +           +    &# +!!"& '$#$"&%**-&"#+1-08"+0!)%8',, &3"((.),+-#( (#''! +)   ! +   +   "        +    +    + +  + + + "        #,54    ̀#   +  + +  !  + + +     + +     +  + +   +   +       %$$#!" ),$"!"#(/##(;/!&$-%'!&& (1&)%,#'#-*$!* (! ') &  !  )   +    +  + +      %      +     +    +0gǁǂ+0H(  +   +  +  +     + +    +   +  +   +      + +  "-#$#&%%5(  '%1#+' /&-"#$.*("+!) # # ! !"!    !        !     + +  !       +    + +      +  +    +  + (Oc0&  +    +           + +     +      +  +    $  '!#!$-$#+ %( ,'%(%#,#1#"&$'("## & #%'- + + +  !  +       +    + +    + +   +  +  +   +   "Tz߁)v./ +         +  +       +  + +     +  +       "   %' # ( ''#/,%0 .2+ # #! ""$ +! + %  !   +&   +   + + +  +  +"   + '  + + +    +      +   +  +  +  + +;|Io݀b/7  + +       +              + + +   / " && #' #"'+.)& 3#$- +)  $   + + !%   + !    +      +          +  +     + "#L4rI+3 +  + + +    +     +  +   +  + +  & "  + $   & !&&!),%41- !" #$( " "   %      +!  "! + + + +&    + +    +           +,CcaA9!      +  +  + +         + + +       +     + +  + #   !  ".%'"%&! + %,(,!) #"%&" %+! +  + - +    +  +      +        + +  +  -0,B1'"      +        +   +    + +  +    + $    +         &   * +%$&%!"/%)! &)&" 0 +    +   +   +   +   +              + + +   "#!'+    +    +  +   +    +    + + +       +        +    +   '    ) $   )    +-    $    + + + + +        + + +  +   + +   +   +   +    +  + +,#                   + +   +      + + +   + +  $ +    !  !" !* + #%#$  #%" $   #          +         + +  + +       +       +   +   + +    +   +  +       + +  +    +     +#  # ! +  !   "$ #,%  !  %  +*                    + +    +    + + + +     + +       + +      +  +  +             +         '!   +!$" # '#$ (   +!# +! ,  + +     + + + +       + + ( +    +  +  +        +      +      + +  +  +      + +   +   + + +    +  ,  $"  "$ %  + +  +   $!           +    +    +  +  +  +  +   +   +      +  +      + +      +   + +   + + +  +      +         + !  #5 #% +!   + + #  '  +    +     + +  + +     '       + + + + +  +  + +   + + +  + +    +      +   +            +  +    +  +        + +"  % , %    ! *     + + +  +   + )    +   +    + +   +      "  +        +        +    +       +   +      + +      !       " "     +  )    + +"         ! +   +       +  +         +          + +  +  + +       +    + +          +    +   +   +       * "       + + +  +)      +          + +        +         +  +   +     +  +       + + + +           + +             +     !   # "%  +   +   +   #(!$'   + +     +             +  + +        +  +          +  + +  +     +        +  +  + +      '' + !"  +! +    + + +  (..    +  +   +  + +          + +  +          +    +   +         +  +  +    + + +   +    + +    %   !  + ' +   +   + +  +     + + +  +   $èj, "  +    + o +                  + +    +  +    +    +  +  +  +  +       +   +   + +         +" +    + +       +  + +$   " +   "%  + +^ 1      + * -́D     + +`c +   +   +     + +  +  + +  + +      + + + +     +   + +  +    +  + + +    + ! +  +    (   + +"   . # +#  !"   " !  +   +   +  +    !Ỳ  +        + %     + +  +  +     + +  +     + +   + + +   +  +    + +     +  + +  +   + +     *       +         + (    +   + + #; !     +    + +    +    +  +  + + +         + +        + +  +  +     +   +  +       +   +  + +    + +  +  %   *     $         $   +   +    +  +      +       +  + +      +       +               +     +          +  + + +  +    +" +  "  $ + (  $  %!    +  +  + +"     +    + +    +        +   + +  +      +    + +       +           + +   + +      + #$               !    +   + 0  + +   +  +     + +         + +            +     +     +      +   +    +     +  +   +  瀻$ +  +  + #      +  + + "   + "   + + + ! +  +  +    +    + +  +  +   +  + +      +  + +     +      +  + +   + +   +   $      #   ! % ʀ/     +       +S +  %   + + +    +    +     + + +   +  +         +   +         +       +  +    +    !    $! +   +  +          +" +! +       + ++           +  + +      + + +  +   +  +  +  + +    +     + +   +       + +  +   +  + 7"     + +#    +      + +    +    +          + +     +           +        +   +       +   + +          +        +  +             +   +   +     +  + + +       +     +  + +   + +          +     + +  +     +     +  + + + + +    + +            +       + +   + +    + * !   +"    +   % + + + +      +         +     + +           + + +      +  +                 + + +             #$   +  +              +      +  +        +     +   + +     + + +    +     +   + + + + + +          +     + + + +    +     +      +                +    + +""    + +  + # + +  + + +    +   + +   +                 +  +           +    +  + +   +  + +       +!  + +   +  +    + +    +    % +    +  +0 +   +        + +   +  +      + +  + +  +        +    + +  +  +    +  + +        +         +  +   +  +  +      # $   +   +   + +     +& + +    +  + +      +          +    +         +  +  + +  +       +          +    +     + !      + + +  +  +     +(                 +   +   +  +  +   + +      +   + +   +   + +         +   +  +      + +    +  +       + ! *        +  #     +  + +  +  + +   +       +  +     +   + + + +  +    + +     +  +       % +     +     !   +   +  +  + )  + +      )   + + +  +  +  +  + + *   + +      + +      + +   +  +   + + + +         +   + +  + +    +    + + +  +  + +  + + +   +  +  + +  + +   + +           +  + +    + +    +   +  +   +            + +  +  +  +   +        + +     +  + +    +   + + +    +     +    + + +    +      +  + +  + +  + +       + +#!   $          + +   +  +   +     +   +   + +              +    +    +    +  +  + + +     +                    + &   + +  +   + +        +          + +  +       +   + +  +  +     + + +    +   +     +    +   +  +     + +   +  +  +   +   +  +     +     + +      +   +        +      '    +  + +   +     +  + +       + + +    +  +   +  + +   +   +  +    +   $  +  " + + +    +     +   + +" + +    + + + +       +   +   )   + +  +  + +  +           +      +  +      +     +     +              +    +     *  + +  % +   +  +  +   +     !  +       +    +       + +          + +       + +   +      +  +         +   +   +       +      $    + +  +   +   +        +  +       +      + +   + +  +  +      + + +  + +  + +  +    +     +  + +      "   +%    + + +      +      +     +     +   +      +  +      + +          +       +    +     +     + +    +          + -         +  + +  +   + +      +      * + +  +     +   !    + + + +   + +       +  + +        + +                 +   + +      +       +    + + +  + +     +    !       +      +         +  +     +  + +      + + + +   +    + + +   +    +      +  +       +         +  +  +       ,!     + +       + #    +   +  +    7    +   +  + + + +   +  + +   + +   +     +      +  +   +      + +   +           + #   +  + + +    #                   +  +         +           + +   +  +         +   + +   + +   +      + +      +          +           +  +     +       +      +   +  + +  + + +  + + +  +    +      +   +     +        +  + + +   + +   ! + +     +  +  +  ;   +      - +  + + +   +  + +1%     + +  +   +    +   +  + +    +  + + + +  +      + +       +     +   =    +   %           +! +          #  +  +    !    + +              +   + +       + + + +   +  + +    +  +  +  +   +  +  + +n&      + + +    + + +    +   + +      "  +     +   +               +   +  +   +  + +  +    +           +   +    + +    + + +           + +    +          +   + +   +  +  +    + + + +     +   "    + + + +    +   + +          + +  +      +     + +  +     +         + +     + +  +     +   +     +   +    +    +      + +    +   + +      + + +           +           + +  +         +  + +       +       +          +   +   +  +  +    +  + + !        +       + +    +  +         +  +    +      + +  +    + $ +   +  +  +  + + +         +   +     +     +  +  + +   +        +      +            +     +    +    +  +         +       +  +         +         + +  + +      +       +  + +   +      +     +    +        +  +    +   +   +  +  +   + +     +  +           +   +     +   + + +       +        "@ +  +     !       +%     +    + +    +  + +      + +  +  + +    +      +    + +     +   +       + +    +   +  + +          +      +    + +      +             + +     +   + +          +  +  + + + +   +  +  +     + +        + +     +   +         +    +    +  +   +    +   +        + +  +  +    +      +  +    +  + +     + +  + + !      +# +     +      +  + +  +        +    +  +  +      + + + +       +   +  + +                + +  +  + +       + +   +  + +         #!   +      + + + +           &   +  + + +    +    +  +  +   +    +      +            +  +     +    +  +     +  + +       +     +    + - +    +   +            9;   + + +   +   +      +  +    +   +      +    + +      +  +  +  +        +         +            +   +  +       +         +      +    +  +      +    + +       +     + + + + +   +  +       +  + + + + +   + + +   +           +        + +   +      +        +          + #   +   +     + +   +   +   + + +        +        +          + + + +   + + +  + +         +     +  +     +     +   + +   + +  +     +     # %  +   + +   +  +         +     + + +    + +                           +    +         + + +    + +   + +     +     + +      + + + + +  +  +  +    +   + +   +  +           +           +   +  $         +  + +   +       +           +        + +  +  + +  + +   +         +    +   +    + + +  +   +  5;'      + + + +  +    +  +    +     +   + + + +   + +    + +         +  + + +        + +       !         +   + + +     + +  + + + + +   &1    +  +   + +     + +         +      +    +        +    + +    +   + +   +    +        ) +  +     +    +   + +  +        + + +  +       *{À8 +       +       + + + + + + + +  +  + +     +        +    + +   +      +  +   + + +   +  +  +      -\;    +  + +       + +   '^̀o,  + + +    + +    + +      +        + +     + +    + +   +            +        +              +     + +  + + +    +;~X%   +      +    +   +>, +        +      +   +            +      +    + +  +   +       +  +      + + + +     +    + +B5      + +   + + +        +      +  +  + +   +  +        +      +  +   +   , + +      +         +   +      + + +       +          + +  +    +  + +  + +     +  + +   +   +  +    +    + +  +    +      +  +   +      +  + + + + +   +  +  +     + + +    +   +     +  +  +       +  + +   +      +  + +     +  + +  +    + + +     +  + +  +  +   +    + + +  ̀  +     + +               +   +  +       +                   +     +  + +  !  +   +   + +  +    + +    +  + +     +     +     + # +  +           + +  +               +  +     +  +       +   +       +     +      + +    +  +  +         +  +    +    +   + + +    + +  +        +  +  +     +      +    +   +  + + + +   +  +        +  +   +  + + + +  +     +  +   + + +       +     + +  +  +    +    +   + +  + + +    *    +   +!  +  ++    +   +                +     +  +       + +      + +    +   +  + + + + +      +   +    +   +            + + +      + + +            + +      + +  + +  +  +            + +            +  +  + +   +        +          +  +  !   +   +  + +              !    +        # +  +    +   + +     + +  + +          +   +            + +   + +  +   +     + +    + + %        +  +    + +  + 32  +     + +      +     + + + + +  +       +  +        +  +    +     +   +    +  +         +      + +      +    + +  +    +     +5        + $   +             +        +    + +      +  +  + + +                +     +     +   +    +     +         +$     +  +    + 0GK<* +   +         +  +  +   +  + +   +  +      + +   +      +  +  +     +         +     +           +     +         +     2 "   + +   +  + +  + +   +  + +  + +    +    + + +       +  + +   + + +  +   +     + +       +     + + + +   + + +           +         +     7XC      +   + +   +    +  + + +         +    + +         +  +                 + + +      + + +      + + +           946 +    +        +     +  +   + +   + +   + +  + +  + +  +    +  +        +       +             +     +        +      +     +     -;??  + +    +  +   +    +         + +  +        +      +   +     + +            + +  +   + + +        + + +  +      +    + +   +   +    + +           +       +                 +       +  +  $ + + +  +   +   +  + +   + + + +     + +  + + + +   +    +  +  + + +    +    + +     +     + +     + + +    +        +  +  +    +  + + +   +  +         +  +   +        +  +   + +  +   +  + +    + + + +     +   +    +  +   +      +  +  + + +  +  + +   +   +   +    + + + + + +   +                + + +   +      +    + +         +      +  + +        +          +       + +      +     +   +     +            + +      +   +   +%  +              +  +  +      +       +   +                + +  + +         +  +    +  +   +     +  +   +        + +            + + +  +   +  +  + +        +   +  +     + +  + ! +         +    + + +  +  +   + + +   +   +    +   +   + +     +  +       +   + + +   +  +  + + +      + + + +          +             +               + + +    % +  +                +      + +   +     +  +   +    +   +       +  +   +5    +   +     + %&%0&#)         +  +    +  +    +  +    +$ +  +  +           +   +    + +     +  +  + + +    + + +     +         +  -/,!&,*%        +  +   +      + + +    + +               +  +  +    +    +  + + +              + +    +  +   +  +  +   +      ""!).34?C@:!%!       +      "   + + +  + +   +                   + +                  +      + +  +         + +       +          + +   + %/-9VX\\XQA8  +         +   + +  +# +  +      +        +       +   +     +      +  + +  +      +    +   + +  + +    +   +  +     +  +  +  $@KG^rH:"$(       +      +    + !               + +   +    +     +  +  + +   +      + +   +   + + +       +    + + $4U<gA-!# +        +         + +     +  +  +  +       !   + + + +    +  + + + + +    +      +           +         +    + +     +  +      + ))5:WEɆFU.       +   + +   + +  +        +   + +   ! +  +   +        +   +     + + +   +   + +         +  + + + + +  +   + +  +   +!!-@wŁ•؇r_=$  +         +   +      +  t0 +    +        +         + + +    + + +      +        + +   +   + + +      +   +   +   +@mvigY."   +   + +     +    +   +  +   + +    +  + +  + +       +        +    + +  +   +     +       +  + + +    + +  +    + /! /5K)3hzK.%               +  +      +  +  + + +  +  +    +                +  +  +   +        +    +  + + +     +  + + + +  +#/6:i܁MQc?,             +       +      +  %  + +         +       + + +   +        +            +    + + +   +             7Nex~Y96" +   +  +     +   + +      +   +  +  +  +   + + +      +  + + +  +     +  +  + +  + +   +    + +   + +  + + +  " +  + + +   +   +  #!$-@XRNI>.%$ + + + + +   +    +  +      + +            +    +      + + +     +  +    + +  + +  +  +             +      $-3+-&'.      +     +    +        +   +  +       + + + + +           + + +   + +      +    + + + +  +           +      +        !# +   +     + +     +   +    + +            + +        +   + +     +   + +    + +        +       + + + +  + +   +     !  + +  +        +"       +   +             +           +   + + + + +  +  +  +   +     +            + +  + +          + +  +  +    +  + +          +     +             + + +   +  +   +  +    +  + + +   +      +     +  +    +   +        +      +  +  +   + +       + +     +        +  +   +   + +   + +       +  +   +  +    +   +   +   +     +   +   +  +        +      + +  ,    +       + +           + +  +     +   +  +  +             +      +    + +        +  + + + +    + +  +    +  +    +    +  +    +          + + +  + +         + +      +    + +            +             + + +  +  + +         +      +     + +     +   + +   +  +     + +     +  +  +    +        + + +   +      +    +    +   +         +    +  + +   + +    + +     +        +   +  +   +%     $  +       +    + +  +   +            +    +     +     + +    +   +     + +    +                 +   +     +  +  +    + +   +  +      + ; +    +     +  +   +    +         +       +     )     +  + +     +     +  +    +   +   +      +         +   ^i    +  + + +  +  +     + +       +  +   + + + + + +        +               +  +   +      +   + +  + +  +        +    +     +   + +     + +     +     +       +   +      +    $ +  + +   +        +   +  +    +       + +! +    +  +    +    +   + + + "    +       +  +       + + +  +     +    + +  +   +    + + + +   + +   + +  + +  +        +     + +     6 +  1          +   + +   + +  +   + +  + +   +  +  +    +   +    %     + + +   +       +    +    +    + + +        v      + + !    +        +    +  +      +  + +     +    +   +        +     +  +  +    +    +  +    +   +      + +            +  +    +  +     +   +      +  +              +     +    +     +  +     +   +   + +     +$ " + #     +      +   +    +   +  +  +    +      +    + +  +   + +  +  +  + +   + +        +   +        + + +   +  + +    +             +  +   +     +         + +  +               +     +     +           +    +   +  +   +    +           +    +  +      + +  + + +     +  + +   + +   + + J  +  +    +  + +   + +  +!      + +     +     + +  + + +     +    +   +      +  + +  + +  + +   +    +   +@     +  + +  +     +  +  +          +       +   +  +     +  + +   +  +   +   + +  +   +    +            +  +  +     +         +   + +      +     +   + +  +    +  +            +    +  +   +         + +  +  +  + + +      +  + + +    +    +     + +     +     +  +       + +     +    +        +  + +  +        + + + +     +   +          + + +         +  +  + + +   +         +   +   +  +   + +     + + +   +   +     + +  +     +  +  +   + +  + +    +     + +        + +             +  +    +  +  !       +   +   + + +   +   + +       +       + +     + +  $ +   +        + +            +    +   +              +  +  + + + +  +        + + +  +    +             +   +    + +      + +  +   +      + +   + +   +"      +  +   &          +  +    + +     + +       +    + +  +    + +    + +     +   +  +    +  +     #     +   +    +   +            +     + + +  +     + +    + +         + +    +  + +    +   + +   +        +   +   +    +    +  +     +      + +    +     + +   + + +#   +    +     +   +        +  + +    +      +       + + + + +  + + +  +    +    + +   +     +  +    +             +  + +  +  +  +     + +  +  +   +    +  +  +   +  + + + +  + +  +  + +      +            + +    + +        +  +   + +   + +   +!     + +  + +      +   +    + +    + +   + +     + +          +      +          +  +  + +   +    +  +   +      +     +    + +            +  +   +    +       +           +  + +   + +   +       + +    +         + +     +  + $ +   +    + +                  +  +   + + +  +      + +   + +   + + +   + + +   + +   +  +   + +  + +  +  +  + +  +  +  2  +  +       +   +      +  + + + +  + + + + +       +     +   + +  +  +   +     +   +  + +  + + +          +  + +  +  + + +  +      +  +   +    + +  +  +  +     +        + +    + +    +   + +  + +          + +  +  + + + +   + +    + +          +          +   +     +  +          +  +  +  + +       + + +  +  +   +  + + +            +        +       + +  + +    +    + +       + + +       +  +     +   +   + + + + +   +     +   + + + + +  +        +             +   +  + +      +   +   +     +  + +  +  + +   +  +                   +    + +   +    +  + +  + +             +  +     +   +  +    + +   +       +               + +  + + +    +   +    +  + + +  + +  + +   +   +    + + $  +  +   +  +  +      +  +  +    + +              +   +    + +    +  +  +  +  +  +  +    +   +       +  +      +    + + + +   + + +  +  +     +         +    +    +   + + +    + +  +  + +     +   + +  + +   + +    +  +  +   + +       +   +   +  + + + +   + + +     + +   +    + +  +0 +     + + + +  +   +   + +  +  +  +  +    +  +      +   +  + +            +     + +  +    + +    +     + +         +     + +     +  + +   +            +    +   +    +   +  + +    +       +        + +   +              %         + +            +   +   +  +  +  +     + "     +  +     +  +  + +         + +  +   +  + +           +     +   +           + +  + +  + +      +  +  + HJ#  +   + +      + +           +   + +     +           +           + !' +       +    +  +   +     +   +  +   @K$        + + + + +         + + +   + +        +      +  +    +  +               +   +        +  + +     +    +   +#"     +  +       + + +  +     + +     +  +  +           +  +  + +   +  +      + +      +   +    +   +  +    +  +     +        +   + +   +   +    +    + +     + + +      + +  +  +       +  +    +    +   +  + +     + + +   +  +     +  + + +          +   +   + +         + +    + +     +     + +  +    +   +    +     +    +      + + +     +   +      + +                   +     + +  +  + +     + + +  +    +  +             + +   +          +   + +   + +  +  +  +     + + + + +         +      + +  + +   +%   +  +  + +    + +   +           +   + +       +        + +  +    + + +    + +    +   +   +      +   +     +  +   +  + +'  +   +              +       +  +     + +   +      + + +     + +       +  + +   +  +        +   +       %  +      +         + +  +  + +   +   +    +   +  +   +  +        +  + +  +   +   +    +  +   +    +  +    +  +              +  +      + + + + +    +      + + + +   + +      +  +        +        +  +     +  +       +  +     +         + +     +   +  +    +      +  +   +    + +   +      + +    + + # +  + + +    +  +   + +    +        +      + +  +   +    +  +    +   + +      + +   +   +            +    +   +  + + #       +  + +   + + +  +     + +  +   + +      +  &   +   +   +     +  +   +   +      +    +  + +        +          +  +   +    +    +   +     + + + + +         +  +  +          + +  +  +    +      + + +   +              +  + +                 +  +   + +  + + +    + +          +    +     +     +   +       +     + + +  +  +    + +     +  +   +    +    + +  +   +   +  +      + + +     + +  +     +  +   +    +   +  +      + + +  +  +  +   +  +        +   +  +   +   +  + +!   !   + +   +  +  +      + +  +  +           +  +      + + +    + +              + + + +  +  +    +    +    +   +  +    +      +  +   +    +  +  +  +   + +   +  +  +    +         +  +  +  + +  +   +      +  +  +  +   + + + +  +  +     + +  +  + +  + + +               +   + + +  +  +           +  +      + + +      +  + + +  + +     +  + +            +    + +   + +    +   + +  +     +     ! +    +         +    + +          +       + +   +      +      +  + +     +  + +  +  +  +  + + +      +       +  + + +  + + +    + +  + + +          +   +  +       + +                 +   %   + +   +    +   +    +   + +   + + +   + +  +  +    +  +  +  +   +           +   + + + +   +           + +     +       +       + +  +  +  + +       +      +            + + +   + +       +         +      +       + + +  +      +    + + + +   + +   +   + +      +  +        +       +  +            + +  +    " "      +  +    +     +     + +     + +   + +    + + + +      + + +       +  + + . +   +     + +      +''!  +  +          + +    +  '  + + +   +    +   +    +     +     + +  + +  +  +  +    +  + + + + +      +    3BA-        +     +     $         + +        +     +    +    + + +    +    +    +   +  +      +    $>QyE"    + + + + +  +   +     + + +  +       +     +   +     + + +  +    + +  +    +       +  +   +       + + + +  +    +  +   + +  ]e,1%!         +          + +   +   +    +  +  + +  + +       +     +            +  + +   +  + +    +    +2dRU      +            +   +   + +     +  + +   +    + + +  +   +   + +  +    + +      +        + 'H6     +  +    +  +  +    +     ++Fāǀ@  +   +  +   +   +  +      +     +    +    +   +    +   +     + +         /wc&    +   +     + +  +  +     (7VlvU% +    +  +     +  # +   +   +     +  +   +   + +        + +        +  +         +   +  0)     + +  +   + +  +      +-/'%  +        + +  +       +   +   +  +   + +   +    +  + + + +    +    +  + "  +   +       +  + +  +     [6    + +   + +     " +  +   "   + + + +      +  +  +   + + + +  +    + +  +     +  +  + +  + + +  +   +              + + +        +  +  +  +   + !     + +   # +!     +   +  +                +      +  +     +   +  +          +    +     +  +  + !  +       "+   +     + + +     +    + + +     +     +    +    +     +  + +  +  +     +   + +  + +   +  +   +       +   +    +    +   + + +    +         +    +          + +            +  + +   +    +     +  +     +        +    +   +   + +   +     +   + + +  +         + + +     +   + +   + + +    + + +    + +         +   + + +    +!  + +         +     + +  +  +  + +  +  +   + + + + + +  +  + " +      +     + +  +     +  + +  + + +       +  +              +   + +  + + + +   +  + +    +    +       + + +   +  +    +   + +         + + +   +  +  +   + +       +    +  +  +     +  +   +   +  +   + +  +  + +   +  +  + + +     +  +   + +        +  +  +     +   + +      +      +  +  +  +   +   +   + +        +   + + + d    +         +   +  + + + +   +   +  + + +           +    +  + + +   +        +      +    +       +  +  +    + +   + ΀ +   +  +   +    +     +     +    +  +   +    +   +    + +  +   +      +     +   + +                 +   + +      +     +      +  + +           +*  + +  +   +   +   + +       +   + +   +  + +      +    +   +     +    +  +   +  +           +  +               + +     + +   +     +  + +   +      +    +    +   +  +    +    + +  + +     + +       +     + +    +  +   +      +  |ހ   +     + +   +  +  +  +  +    +     +   + + +         + +     +      + +   + + +  +  +    + +  +  +           +    +  + + +         +   +*  + + +    + +   +  +  + +           +   + + +        +  + +  +         +    +  + +        +    +    +  + +        +  + +           +    +    + +      + +      +  + +  +   +  +  +    +  +  +    +         +   +    +     + + +        +    +   + +    +   +   +  +   +  + +  +  +     +    + +   +   +      + + +  +    +  + +   +  +   +     +   +     + + +  +  + + +    + + +       +  +  +            +   + + + +       +         +    + +     + + + + +    +   +  +       +    +   + +                +  +  +    +  + +    +     +  +  +         +   +  + +  +    + +  +    +      + + +                    +    + +   +  + +   +   +  +        +  +     +  +      +  + +       + +    +           +      + +   + +  +       + + +      +     +    +  +     +  + +         +  +   +      + +       +      +     +       + +        +   +     +   +        +       +   + +      +  ! +    + +  +   +  +   + + +   +  + +    +    +        +     +     +  +  +   +        +       +     +   + + + +    +   +  +  +     +          +  +  + +             + +  '        +  +  瀡       +       +      +  +  + +          +            +   +    + +   +     +    +       +   + +  +  +V5 +  + +  +   +  +    + + + + +    +   +     +     +   +      +    +     +     + +          +    + + + +  + + + +   +  +             +   + +  +    + +    + + + +     + +  +  + +   + +    + +            + +     +   +   +  + + +   + +         + +   +    +   +     +   +  +  + +    +   + +  + +      +   +              +   +  +   +    + + +  +    +      +     +  +    +   +  + +  +      +   +     + +    + +    +        +   + + +      + + +   + +   +  + + +     +   +  +   + +  +  +         +               +    + +  +  +       +    + + +   + + +     +     +  +     + +  +   +     +    + + + + + +       + + +    +   + +                     +          + +    + +   +    +  + +  !  +       +  +    +     +     +             +  + + +             +    + +        + + +          # %!"  +    +      +   + + +      +      +       + +    + + +  +      +  +  +  +   +              + +     + + $$,')25)   +         +     +  +      + +      +   +     +  + +    +  +       + + +   +  +    +  +  +       +  "'*-E=??3+  +  +  +  +  +     + +        +    +     +  +   + +     +  +      +       +   +     +  + +    +     + +     +   /A^|T,%* +         + + + +  +  + +      + + + + + + + +                   + +      +    + + +     +   +  + +     + + +  + + .Afπm='(  +   +  + +    + +      +   +   + +      +           +   + +  +   +  + +   +   + +    +   + + + +   +  +  +  .Ẑ`J_04$    +        +      +  +      +  +         +   + +     +  + + +    +  +         +       + *"6[51c/(#       + +        +   + + +  +     + +    +            + + +    +  +  +          +     +  +(6kʁЇ=0Jj/     +   + +   + +  +   +  + +  +        + +  +    +    + + +     +     + +& + +               ++>gn#ȂӀR, +   +     +       +  + + +    +    +         +    + +   +  +   +     +  + +      +   +  +         +  9PցIl<0  +   +    + +    + +   + +  +  + +  +  + +  +    + +    + +   +  + + +         +     +   !    + +  + +   +  +     +    +  *;RihG:      +!  +      +         +    +  +  + +  +  +  +     +      +   + +    +  +  +  +   +       +   +    -BNQRP@6'  +   + + + + +     +   + + +           +  +   + +  +    + + + + +    +        +   +     +  +   +   +      %2/2)!&        +  +  +  +  +  + + + +       +     +   +     + + +    + +   + +     +    + +   + #   +       ")    +     +   + +     +  +    + +      +  +       +     + +        + + +   + +           + +   + +   + +       +      +  + +  + +  +     +     +   +         +       + +       + +   +  +      +     &   +   + +    + *            +      +          + + + +  +  + +      + +  + +     +             +   + + + +  +  +         +          +   +      +   + + +  +        +   + +  + +   + + +     +       +  +          + +      +    + +    +       +   + +      +   +   +  + + +    + +       +     + + +    + +   +   + +     +    +  +   + +           +   +         + +  + +  +   +    +   +   +  +  +  +   +          +       +       + +    +   +   +  + +      +    + + +    +   +   +   + +    +  +    + + +    +  +    +  +    + +      + + +   +    + +        +  +   +   +  +         + + +    +  +          + +   +  + +     + +    +     + +   + +   +               +               +    +      + + +   +  +      + +    + +  + +  + + + + + +    +    +        +    + +     +   +  + +   +   + +      +   +             +    +      + +    +         +     +  + +    +  +  +    + +  +   +     +   + + +  +      + +  +  + + + + +  +    +  +    +    +     +   + +     +           + +  +   +   +   +         +  +  +   +   + " +    )"           + +    +       + +    +           + +    + + +                +       +    + +         +       +  +   +     + + +  +        +  + +     +    +  + + +   +       +    +  +    + +  +     +  +   +  +  + +    +       +   +  +  + eR     + +     +  + +    + + +      +  +        +     +      +    + +     +  +  +  +   + +      +     ." +   +    +   +        + + +      +       +      +  + + + +     +   +        + + +        +   +  +      + +   +   +   + + +  +  + +    +   +       + +  +  + +   +   + +     +   +  +  +  + +             +    +       +       + +  +       +          +  +  + + + +   +   +    +    +    +  +    + +       +    +       +    +  +   + +     +   + + + +  +       + +      + +         +      + +       +       + +    +     +        +     +    +  + +          +    +    +     + + +     + +     +  +               + + +  +         +    +      + + +      +    +               + +       +        +             +  +    +  +   +  +     +      + +    +      + +  +   +  +       +       +    +     +     + +        +   +           + +       +  + +  +  +      +    +   + + + +   +       + +   + +    +   +    +    +        +         +       +  +  +       + +      + + +     +      + +      +      + +     +   +   +   +   +   +  +     +      + +  +        + +   + + + +    + +  + +          +       +   + +  +    +    +   +         +   +  +  +   + +  +    +   +    +   + + +       +       +  + +  +  + +        +   +   +      +    + +   +  +      +   +          + +  +           + +   +   +     +  +   +      +  +  + + +  +     + + +   + +              +    + +  +  +    +    +  + +   +  +   + + +      + + +  + + +   +         +      + + + +     + +  +          +            + +  +    +      +     +  +              +        + +     +       +  +  +     + +        +        +   +   + + + +  +  +   + +   +      +     +    +  +      +   +     + +            +       !     +        + +  +    + +  +  +    + +  %#    +   + + +  + + +    + +   +     + +     +   +  +      +        + +   +  + + +  + +      +   +    +   + +    +    + + +  +   +  +          +    +        +    +    +      +       +  +   +  + + + +  + +   + +       + +  + +    + + +            +   +    +  +    +          +     +             +      +  +  +    +    + + +    +  +    +    .%  +   +    +     + + +   -! +     + +  +      +     + + +   +     + + + "  + +  +   +       +  +    +   +   +    +  + *#   +  +  + !   +  + +  + + +       + +  + +        !15&$./            + +     +    +        +            +   +    + +            + $(5;B>6:0%+% +   + +            + + + +  +    + +        +    + +  +           + + +      +      +  $0  +  +  +  +   + +    +     +       +    + + +  +   +! +   +   + +            +   +        +   + +    %13H6YJuI8'     +      + +  +  +          +    !       + +    +    +  + + +   +      +     + + +       +  #9ZV-Fŀp=&      +  +    +   + +   +  +          +      + +  +       + +      + +    + + +  +  +      +    + + ->\Ҁ߀U.    +      +   + +   + +     + +  +  +  + + +   +  +                + +   +      +   +      +        +  +(1>OampjR6! +  +   +  + + +  + +      +       + +  +   +      +         + +      +     + +  + + +      +  +    +    +" +3>C6-*'      +   +        +   + +   + + + +     + +            +  +       + +  + +              + '" # + +    +    + +     +   + + +           + +     +   +     +   + + +   +   + +  +          + + +  Ӏ    +           + +    +      + +   +   + +       +  + +       +  +  + + # +    +    +    + +    + +  +    + +  + +  + +  +          + +  +  +  +          +   +  +    +     +,)       + +  q  +  +  + +  +  +    +  +      + +      +    +  +   +      +  +       +  +    +   +      +  + +    + +        +   + +  + +  +  + +        +    +       +         + + + + +  +      +      +    +   +    /d  +   +      +     + + +  +  + + + + +        +   +      +"  + +     +   +       +  +    +         +   j       +            +  +   + +  + + +  + + + +     +   + +  +      + +               +   +           +        +  +   +  + +  +     +     +     +     +    +     +  +$    +    +   +     +  + + +     +   +  +    + + +  +      +   +    + +   +     +    +  +  +  +   + +   +  +           + + +      + +   +     + +         + +  +         + +    +   +    +      +  +   + +  +  +   +  +    +     + +   + +  +  +  +    +  +  +       +   +  + + +   + + +  +      +  + +     +   +    +    + +     +      + +   +     +  +      + + +   + +   +    + +  +         +  +     + +      + +   +    +    +  +   +     +      + +     +   + + +          +      +       + +      +   +  +  +         +  + + +   + +  + +      +   +  +  +       +    +  +    + +        +   +  +  +  +     +   +    +    +    +          +    +     + +     + + +       +  +  12 +    +   +   + +  + + +    +  +      +     + +  +    +   +   +      +   + +         +      +                 +  +  + +    +  +  +     +  +  +  +         +      +    + +  + +  + +      +   !   +   + +          + + +      +  +  +  +        +        +  +      +      +          +    + +      +   +      +  +   +    +  +  +   +  + + +  +   +   +  +   +  +   + +   +    +       + + +     + + +     + +          +    + + + +  + +     +            +    +   + +       + +    + +    +    +    +         + +     +    +  +   +    +    +    +    +      + +  +    +    + + +            +  + +          +          +   +  +    +  +  +  +   +    +  +  +   +     +     + +      +   +               +    \ No newline at end of file diff --git a/test/test_fitsimage.py b/test/test_fitsimage.py index cbaddd45..b724b45e 100644 --- a/test/test_fitsimage.py +++ b/test/test_fitsimage.py @@ -18,12 +18,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import absl.testing.parameterized as parameterized import datetime import calendar import numpy.random import os import pyfits import random +import requests_mock import stat import tempfile import warnings @@ -53,7 +55,7 @@ def __exit__(self, *args): os.unlink(self.path) -class FITSImageTest(unittest.TestCase): +class FITSImageTest(parameterized.TestCase): MIN_PIXEL_VALUE = 0 MAX_PIXEL_VALUE = 65535 @@ -99,6 +101,11 @@ def random_data(cls, **keywords): """ + # Ignore keywords mapping to None. + for k, v in keywords.items(): + if v is None: + keywords.pop(k) + x_size = random.randint(cls.MIN_SIZE, cls.MAX_SIZE) y_size = random.randint(cls.MIN_SIZE, cls.MAX_SIZE) path = cls.mkfits(x_size, y_size, **keywords) @@ -343,307 +350,397 @@ def test_delete_keyword(self): with self.assertRaises(KeyError): img.read_keyword('HIERARCH ' + keyword) - def test_date_and_year(self): - - def strptime_utc(date_string): - """ Parse a string representing a UTC time according to strptime's - format '%Y-%m-%d %H:%M:%S.%f' and return it in seconds since the - Unix epoch. Note that '%s' is not a documented option to strftime() - as it is OS dependent, but it should work on any decent system.""" - - format_ = "%Y-%m-%d %H:%M:%S.%f" - dt = datetime.datetime.strptime(date_string, format_) - struct_time = dt.utctimetuple() - # strftime('.%f') because struct_time does not store fractions - return calendar.timegm(struct_time) + float(dt.strftime('.%f')) - - def unstrip(str_, max_whitespaces = 5): - """ Return a copy of 'str' with leading and trailing whitespaces. - The number of whitespaces on each side is a random number in the - range [1, max_whitespaces] """ - - leading = ' ' * random.randint(1, max_whitespaces) - trailing = ' ' * random.randint(1, max_whitespaces) - return '%s%s%s' % (leading, str_, trailing) - - # (1) The ideal case: date format 'yyyy-mm-ddTHH:MM:SS.sss' - # Start of observation = 2009-06-12 21:12:47.238, EXPTIME = 1505 - # 2009-06-12 21:12:47.238 + (00:25:05 / 2) = - # 2009-06-12 21:12:47.238 + 00:12:32.5 = - # 2009-06-12 21:25:19.738 UTC ~= - # 2009.44628104 - - keywords = {'DATE-OBS' : '2009-06-12T21:12:47.238', - 'EXPTIME' : 1505} - with self.random(**keywords) as img: - expected_date = strptime_utc("2009-06-12 21:25:19.738") - expected_year = 2009.44628104 - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # (2) Format 'yyyy-mm-ddTHH:MM:SS', without fractions of a second - # Start of observation = 1998-11-29 02:53:21, EXPTIME = 1834 - # 1998-11-29 02:53:21 + (0:30:34 / 2) = - # 1998-11-29 02:53:21 + 0:15:17 = - # 1998-11-29 03:08:38 UTC ~= - # 1998.90994793 - - keywords = {'DATE-OBS' : '1998-11-29T02:53:21', - 'EXPTIME' : 1834} - with self.random(**keywords) as img: - expected_date = strptime_utc("1998-11-29 03:08:38.0") - expected_year = 1998.90994793 - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # Repeat (2) with leading and trailing whitespaces - keywords['DATE-OBS'] = unstrip(keywords['DATE-OBS']) - with self.random(**keywords) as img: - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # (3) Another one with fractions of a second, turn to a new year - # Start of observation = 1999-12-31 23:53:12.565, EXPTIME = 4312.56 - # 1999-12-31 23:53:12.565 + (1:11:52.56 / 2) = - # 1999-12-31 23:53:12.565 + 0:35:56.28 = - # 2000-01-01 00:29:08.845 UTC =~ - # 2000.00005528 - - keywords = {'DATE-OBS' : '1999-12-31T23:53:12.565', - 'EXPTIME' : 4312.56} - with self.random(**keywords) as img: - expected_date = strptime_utc("2000-01-01 00:29:08.845") - expected_year = 2000.00005528 - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # (4) Format 'yyyy-mm-dd', HH:MM:SS.sss read from TIME-OBS - # Start of observation = 2003-03-28 04:23:17.87, EXPTIME = 1357.25 - # 2003-03-28 04:23:17.87 + (0:22:37.25 / 2) = - # 2003-03-28 04:23:17.87 + 0:11:18.625 = - # 2003-03-28 04:34:36.495 UTC ~= - # 2003.23613889 - - keywords = {'DATE-OBS' : '2003-03-28', - 'TIME-OBS' : '04:23:17.87', - 'EXPTIME' : 1357.25} - with self.random(**keywords) as img: - expected_date = strptime_utc("2003-03-28 04:34:36.495") - expected_year = 2003.23613889 - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # Repeat (4) with leading and trailing whitespaces - keywords['DATE-OBS'] = unstrip(keywords['DATE-OBS']) - keywords['TIME-OBS'] = unstrip(keywords['TIME-OBS']) - with self.random(**keywords) as img: - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # (5) Another 'yyyy-mm-dd', HH:MM:SS (no fractions) read from TIME-OBS - # Start of observation = 2011-06-13 19:04:28, EXPTIME = 2341 - # 2011-06-13 19:04:28 + (0:39:01 / 2) = - # 2011-06-13 19:04:28 + 0:19:30.5 = - # 2011-06-13 19:23:58.5 UTC ~= - # 2011.44878989 - - keywords = {'DATE-OBS' : '2011-06-13', - 'TIME-OBS' : '19:04:28', - 'EXPTIME' : 2341} - with self.random(**keywords) as img: - expected_date = strptime_utc("2011-06-13 19:23:58.5") - expected_year = 2011.44878989 - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # (6) Repeat (5), but using different, non-standard keywords - keywords['DATE'] = keywords.pop('DATE-OBS') - keywords['TIME'] = keywords.pop('TIME-OBS') - keywords['EXPOSURE'] = keywords.pop('EXPTIME') - with self.random(**keywords) as img: - kwargs = dict(date_keyword = 'DATE', - time_keyword = 'TIME', - exp_keyword = 'EXPOSURE') - self.assertAlmostEqual(expected_date, img.date(**kwargs)) - self.assertAlmostEqual(expected_year, img.year(**kwargs)) - - # (7) Format 'yy/mm/dd' (only for dates from 1900 through 1999) - # The year 13, when this format is used, is interpreted as 1913 - # Start of observation = 1913-04-20 22:58:12.1, EXPTIME = 1328 - # 1913-04-20 22:58:12.1 + (0:22:08 / 2) = - # 1913-04-20 22:58:12.1 + 0:11:04 = - # 1913-04-20 23:09:16.1 UTC ~= - # 1913.30127334 + @requests_mock.Mocker() + def test_read_barycentric_date(self, mock): keywords = { - 'DATE-OBS' : '13/04/20', - 'TIME-OBS' : '22:58:12.1', - 'EXPTIME' : 1328} - with self.random(**keywords) as img: - expected_date = strptime_utc("1913-04-20 23:09:16.1") - expected_year = 1913.30127334 - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - # (8) Another 'yy/mm/dd' format: year 89 means here 1989 - # Start of observation = 1989-08-30 01:32:22.14, EXPTIME = 83.55 - # 1989-08-30 01:32:22.14 + (0:01:23.55 / 2) = - # 1989-08-30 01:32:22.14 + 0:00:41.775 = - # 1989-08-30 01:33:03.915 ~= - # 1989.66045101 - - keywords = { - 'DATE-OBS' : '89/08/30', - 'TIME-OBS' : '01:32:22.14', - 'EXPTIME' : 83.55} + 'BJD_TDB': 2458902.321777873, + 'RA': '03:47:24.00', + 'DEC': '+24:15:19.0', + } + # From http://astroutils.astronomy.ohio-state.edu/time/bjd2utc.html, + # we see that for these coordinates, the input BJD_TDB corresponds to + # JD UTC = 2458902.321287484, which we convert to a UTC timestamp. + mock.get( + url='http://astroutils.astronomy.ohio-state.edu/time/convert.php?DEC=24.2552777778&FUNCTION=bjd2utc&JDS=2458902.321777873&RA=56.85&RAUNITS=degrees', + text='2458902.321287484') + with self.random(**keywords) as img: - expected_date = strptime_utc("1989-08-30 01:33:03.915") - expected_year = 1989.66045101 - self.assertAlmostEqual(expected_date, img.date()) - self.assertAlmostEqual(expected_year, img.year()) - - def assertRaised(exception, keywords): - """ Assert that a random FITS image with the 'keywords' FITS - keywords raises 'exception' when both its date() and year() - methods are called.""" - with self.random(**keywords) as img: - with self.assertRaises(exception): - img.date() - with self.assertRaises(exception): - img.year() - - # Keyword DATE-OBS not found - keywords = {'EXPTIME' : 1500} - assertRaised(KeyError, keywords) - - # Keyword EXPTIME not found - keywords = {'DATE-OBS' : '1988-09-13T21:45:19'} - assertRaised(KeyError, keywords) - - # DATE-OBS in the 'yyyy-mm-dd' format, so the time at the start of - # the observation must be read from TIME-OBS (which is not found) - keywords = {'DATE-OBS' : '1993-04-29', 'EXPTIME' : 1200} - assertRaised(KeyError, keywords) - - # Both DATE-OBS and EXPTIME exist, but the latter does not contain a - # floating-point number giving the exposure time in units of seconds. - keywords = {'DATE-OBS' : '1988-09-13T21:45:19', 'EXPTIME' : 'unknown'} - assertRaised(fitsimage.NonStandardFITS, keywords) - - # Several non-standard DATE-OBS formats - nonstandard_dates = [ - '1993/04/29T12:42:23', # slashes, not dashes - '1993-04-29 T 12:42:23', # 'T' surrounded by whitespaces - '1993-04-29 12:42:23', # no 'T' between date and time - '1993-04-29T12 42 23', # whitespaces, not colons - '1993-04-29T', # nothing after the 'T' - '04-29T12:42:23', # year missing - '12:42:23', # time, but not date - 'Thu Apr 29 12:42:23 1993'] # ctime() format - - for wrong_date in nonstandard_dates: - keywords['DATE-OBS'] = wrong_date - assertRaised(fitsimage.NonStandardFITS, keywords) - - # Several non-standard TIME-OBS formats - nonstandard_times = [ - '12/42/23', # slashes, not colons - '12 42 23', # whitespaces, not colons - '12:42', # seconds missing - '12h42m23s', # 'h', 'm' and 's' instead of colons - ''] # empty - - keywords = {'DATE-OBS' : '1993-04-29', 'EXPTIME' : 1200} - for wrong_time in nonstandard_times: - keywords['TIME-OBS'] = wrong_time - assertRaised(fitsimage.NonStandardFITS, keywords) - - def test_ra(self): - - ra_kwd = 'RA' - - keywords = {ra_kwd : 344.412916667} + self.assertAlmostEqual(img.date(barycentric=True), 1582400559.23860979) + + @parameterized.named_parameters( + { + 'testcase_name': 'yyyy-mm-ddTHH:MM:SS.sss', + 'date': '2009-06-12T21:12:47.238', + 'time': None, + 'exptime': 1505, + 'want_date': 1244841919.738, # 2009-06-12 21:25:19.738 + 'want_year': 2009.44628104, + },{ + 'testcase_name': 'yyyy-mm-ddTHH:MM:SS', + 'date': '1998-11-29T02:53:21', + 'time': None, + 'exptime': 1834, + 'want_date': 912308918.0, # 1998-11-29 03:08:38.0 + 'want_year': 1998.90994793, + },{ + 'testcase_name': 'yyyy-mm-ddTHH:MM:SS (leading and trailing whitespaces)', + 'date': ' 1998-11-29T02:53:21 ', + 'time': None, + 'exptime': 1834, + 'want_date': 912308918.0, # 1998-11-29 03:08:38.0 + 'want_year': 1998.90994793, + },{ + 'testcase_name': 'yyyy-mm-ddTHH:MM:SS.sss (midpoint falls in the following year)', + 'date': '1999-12-31T23:53:12.565', + 'time': None, + 'exptime': 4312.56, + 'want_date': 946686548.845, # 2000-01-01 00:29:08.845 + 'want_year': 2000.00005528, + },{ + 'testcase_name': 'yyyy-mm-dd and HH:MM:SS.sss', + 'date': '2003-03-28', + 'time': '04:23:17.87', + 'exptime': 1357.25, + 'want_date': 1048826076.495, # 2003-03-28 04:34:36.495 + 'want_year': 2003.23613889, + },{ + 'testcase_name': 'yyyy-mm-dd and HH:MM:SS.sss (leading and trailing whitespaces)', + 'date': ' 2003-03-28 ', + 'time': ' 04:23:17.87 ', + 'exptime': 1357.25, + 'want_date': 1048826076.495, # 2003-03-28 04:34:36.495 + 'want_year': 2003.23613889, + },{ + 'testcase_name': 'yyyy-mm-dd_and_HH:MM:SS', + 'date': '2011-06-13', + 'time': '19:04:28', + 'exptime': 2341, + 'want_date': 1307993038.5, # 2011-06-13 19:23:58.5 + 'want_year': 2011.44878989, + },{ + 'testcase_name': 'yy/mm/dd', + 'date': '89/08/30', # interpreted as 1989 + 'time': '01:32:22.14', + 'exptime': 83.55, + 'want_date': 620443983.915, # 1989-08-30 01:33:03.915 + 'want_year': 1989.66045101, + },{ + 'testcase_name': 'yy/mm/dd (another example)', + 'date': '13/04/20', # interpreted as 1913 + 'time': '22:58:12.1', + 'exptime': 1328, + 'want_date': -1789260643.9, # 1913-04-20 23:09:16.1 + 'want_year': 1913.30127334, + }, + ) + def test_date_and_year(self, date, time, exptime, want_date, want_year): + keywords = { + 'DATE-OBS': date, + 'TIME-OBS': time, + 'EXPTIME': exptime, + } with self.random(**keywords) as img: - self.assertAlmostEqual(keywords[ra_kwd], img.ra(ra_kwd)) + self.assertAlmostEqual(img.date(), want_date) + self.assertAlmostEqual(img.year(), want_year) - keywords = {ra_kwd.lower() : '19:43:56.01'} + def test_date_and_year_non_standard_keywords(self): + # The FITS image does not use standard keywords, but date() and year() + # can be pointed to read the date, time and exposure duration from the + # right keywords. + keywords = { + 'DATE': '2011-06-13', + 'TIME': '19:04:28', + 'EXPOSURE': 2341, + } with self.random(**keywords) as img: - self.assertAlmostEqual(295.983375, img.ra(ra_kwd)) - - keywords = {ra_kwd : '17:58:17 '} + got_date = img.date( + date_keyword='DATE', + time_keyword='TIME', + exp_keyword='EXPOSURE', + ) + got_year = img.year( + date_keyword='DATE', + time_keyword='TIME', + exp_keyword='EXPOSURE', + ) + self.assertAlmostEqual(got_date, 1307993038.5) # 2011-06-13 19:23:58.5 + self.assertAlmostEqual(got_year, 2011.44878989) + + @parameterized.named_parameters( + { + 'testcase_name': 'Missing DATE-OBS', + 'date': None, + 'exptime': 1500, + 'want': KeyError, + },{ + 'testcase_name': 'Missing EXPTIME', + 'date': '1988-09-13T21:45:19', + 'exptime': None, + 'want': KeyError, + },{ + # DATE-OBS in the 'yyyy-mm-dd' format, so the time at the start of + # the observation must be read from TIME-OBS (which is not found). + 'testcase_name': 'Missing TIME-OBS', + 'date': '1993-04-29', + 'exptime': 1200, + 'want': KeyError, + }, + ) + def test_date_and_year_missing_keyword(self, date, exptime, want): + keywords = { + 'DATE-OBS': date, + 'EXPTIME': exptime, + } with self.random(**keywords) as img: - self.assertAlmostEqual(269.570833333, img.ra(ra_kwd)) - - keywords = {ra_kwd.lower() : ' 00:42:30.997 '} + with self.assertRaises(want): + img.date() + with self.assertRaises(want): + img.year() + + @parameterized.named_parameters( + { + 'testcase_name': 'Slashes instead of dashes', + 'date': '1993/04/29T12:42:23', + },{ + 'testcase_name': "'T' surrounded by whitespaces", + 'date': '1993-04-29 T 12:42:23', + },{ + 'testcase_name': "No 'T' between date and time", + 'date': '1993-04-29 12:42:23', + },{ + 'testcase_name': 'Whitespaces instead of colons', + 'date': '1993-04-29T12 42 23', + },{ + 'testcase_name': "Nothing after the 'T'", + 'date': '1993-04-29T', + },{ + 'testcase_name': "Year missing", + 'date': '04-29T12:42:23', + },{ + 'testcase_name': 'Time present but date missing', + 'date': '12:42:23', + },{ + 'testcase_name': 'ctime() format', + 'date': 'Thu Apr 29 12:42:23 1993', + }, + ) + def test_date_and_year_nonstandard_DATE_OBS(self, date): + keywords = { + 'DATE-OBS': date, + 'EXPTIME': 1800, + } with self.random(**keywords) as img: - self.assertAlmostEqual(10.6291541667, img.ra(ra_kwd)) - - keywords = {ra_kwd : '13:00:01.'} + with self.assertRaisesRegexp(fitsimage.NonStandardFITS, 'DATE-OBS'): + img.date() + with self.assertRaisesRegexp(fitsimage.NonStandardFITS, 'DATE-OBS'): + img.year() + + @parameterized.named_parameters( + { + 'testcase_name': 'Slashes instead of colons', + 'time': '12/42/23', + },{ + 'testcase_name': 'Whitespaces instead of colons', + 'time': '12 42 23', + },{ + 'testcase_name': 'Seconds missing', + 'time': '12:42', + },{ + 'testcase_name': "'h', 'm' and 's' instead of colons", + 'time': '12h42m23s', + },{ + 'testcase_name': 'Empty', + 'time': '', + }, + ) + def test_date_and_year_nonstandard_TIME_OBS(self, time): + keywords = { + 'DATE-OBS': '1998-11-29', + 'TIME-OBS': time, + 'EXPTIME': 1800, + } with self.random(**keywords) as img: - self.assertAlmostEqual(195.004166667, img.ra(ra_kwd)) - - def assertValueErrorRaised(ra_value): - """ Assert that a random FITS image whose right ascension is - 'ra_value' raises ValueError when its ra() method is called. """ - - keywords = {ra_kwd : ra_value} - with self.random(**keywords) as img: - regexp = "not in decimal degrees or 'HH:MM:SS.sss' format" - with self.assertRaisesRegexp(ValueError, regexp): - img.ra(ra_kwd) - - # Not in decimal or dd:mm:ss[.sss] format - assertValueErrorRaised('00h42m30s') - assertValueErrorRaised('00:42:30.9997') - assertValueErrorRaised('3:24:57.12') - assertValueErrorRaised('N/A') - - # 'RA' keyword not in FITS header - with self.assertRaises(KeyError): - with self.random() as img: - img.ra(ra_kwd) - - def test_dec(self): - - dec_kwd = 'DEC' - - keywords = {dec_kwd : -52.6956605556} + with self.assertRaisesRegexp(fitsimage.NonStandardFITS, 'TIME-OBS'): + img.date() + with self.assertRaisesRegexp(fitsimage.NonStandardFITS, 'TIME-OBS'): + img.year() + + @parameterized.named_parameters( + { + 'testcase_name': 'Not a number', + 'exptime': 'unknown', + },{ + 'testcase_name': 'Empty', + 'exptime': '', + }, + ) + def test_date_and_year_nonstandard_EXPTIME(self, exptime): + keywords = { + 'DATE-OBS': '2003-03-28', + 'TIME-OBS': '04:23:17.87', + 'EXPTIME': exptime, + } with self.random(**keywords) as img: - self.assertAlmostEqual(keywords[dec_kwd], img.dec(dec_kwd)) - - keywords = {dec_kwd.lower() : '45:59:52.768'} + with self.assertRaisesRegexp(fitsimage.NonStandardFITS, 'EXPTIME'): + img.date() + with self.assertRaisesRegexp(fitsimage.NonStandardFITS, 'EXPTIME'): + img.year() + + @parameterized.named_parameters( + { + 'testcase_name': 'Decimal degrees', + 'keyword': 'RA', + 'ra': 344.412916667, + 'want': 344.412916667, + },{ + 'testcase_name': 'Sexagesimal', + 'keyword': 'RA', + 'ra': '19:43:56.01', + 'want': 295.983375, + },{ + 'testcase_name': 'Trailing whitespace', + 'keyword': 'RA', + 'ra': '17:58:17 ', + 'want': 269.570833333, + },{ + 'testcase_name': 'Leading and trailing whitespace', + 'keyword': 'RA', + 'ra': ' 00:42:30.997 ', + 'want': 10.6291541667, + },{ + 'testcase_name': 'Trailing decimal separator', + 'keyword': 'RA', + 'ra': '13:00:01.', + 'want': 195.004166667, + }, + { + 'testcase_name': 'Case-insensitive lookup', + 'keyword': 'ra', + 'ra': '00:42:30.997', + 'want': 10.6291541667, + }, + { + 'testcase_name': 'HH MM SS.ss', + 'keyword': 'RA', + 'ra': '03 47 24.00', + 'want': 56.85, + }, + ) + def test_ra(self, keyword, ra, want): + keywords = {keyword: ra} with self.random(**keywords) as img: - self.assertAlmostEqual(45.9979911111, img.dec(dec_kwd)) - - keywords = {dec_kwd : '+19:10:56 '} + self.assertAlmostEqual(img.ra('RA'), want) + + @parameterized.named_parameters( + { + 'testcase_name': 'Extraneous h/m/s', + 'ra': '00h42m30s', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'HH:MM:SS.sss' format", + },{ + 'testcase_name': 'Too many decimal places', + 'ra': '00:42:30.9997', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'HH:MM:SS.sss' format", + },{ + 'testcase_name': 'No leading zero', + 'ra': '3:24:57.12', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'HH:MM:SS.sss' format", + },{ + 'testcase_name': 'Not an actual right ascension', + 'ra': 'N/A', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'HH:MM:SS.sss' format", + },{ + 'testcase_name': 'Keyword not in FITS header', + 'ra': None, + 'want': KeyError, + 'regexp': "keyword 'RA' not found", + }, + ) + def test_ra_error(self, ra, want, regexp): + keywords = {'RA': ra} with self.random(**keywords) as img: - self.assertAlmostEqual(19.1822222222, img.dec(dec_kwd)) - - keywords = {dec_kwd.lower() : ' -08:12:05.8 '} + with self.assertRaisesRegexp(want, regexp): + img.ra('RA') + + @parameterized.named_parameters( + { + 'testcase_name': 'Decimal degrees', + 'keyword': 'DEC', + 'dec': -52.6956605556, + 'want': -52.6956605556, + },{ + 'testcase_name': 'Sexagesimal', + 'keyword': 'DEC', + 'dec': '45:59:52.768', + 'want': 45.9979911111, + },{ + 'testcase_name': 'Trailing whitespace', + 'keyword': 'DEC', + 'dec': '+19:10:56 ', + 'want': 19.1822222222, + },{ + 'testcase_name': 'Leading and trailing whitespace', + 'keyword': 'DEC', + 'dec': ' -08:12:05.8 ', + 'want': -8.20161111111, + },{ + 'testcase_name': 'Trailing decimal separator', + 'keyword': 'DEC', + 'dec': '26:25:08.', + 'want': 26.4188888889, + }, + { + 'testcase_name': 'Case-insensitive lookup', + 'keyword': 'dec', + 'dec': '-08:12:05.8', + 'want': -8.20161111111, + }, + { + 'testcase_name': 'DD MM SS.s', + 'keyword': 'DEC', + 'dec': '+24 15 19.0', + 'want': 24.25527778, + }, + ) + def test_dec(self, keyword, dec, want): + keywords = {keyword: dec} with self.random(**keywords) as img: - self.assertAlmostEqual(-8.20161111111, img.dec(dec_kwd)) - - keywords = {dec_kwd : '26:25:08.'} + self.assertAlmostEqual(img.dec('DEC'), want) + + @parameterized.named_parameters( + { + 'testcase_name': 'Extraneous +/d/m/s', + 'dec': '+41d16m9s', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'DD:MM:SS.sss' format", + },{ + 'testcase_name': 'Too many decimal places', + 'dec': '45:59:52.7685', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'DD:MM:SS.sss' format", + },{ + 'testcase_name': 'No leading zero', + 'dec': '-8:12:05.8', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'DD:MM:SS.sss' format", + },{ + 'testcase_name': 'Not an actual declination', + 'dec': 'N/A', + 'want': ValueError, + 'regexp': "not in decimal degrees or 'DD:MM:SS.sss' format", + },{ + 'testcase_name': 'Keyword not in FITS header', + 'dec': None, + 'want': KeyError, + 'regexp': "keyword 'DEC' not found", + }, + ) + def test_dec_error(self, dec, want, regexp): + keywords = {'DEC': dec} with self.random(**keywords) as img: - self.assertAlmostEqual(26.4188888889, img.dec(dec_kwd)) - - def assertValueErrorRaised(dec_value): - """ Assert that a random FITS image whose declination is - 'dec_value' raises ValueError when its dec() method is called.""" - - keywords = {dec_kwd : dec_value} - with self.random(**keywords) as img: - regexp = "not in decimal degrees or 'DD:MM:SS.sss' format" - with self.assertRaisesRegexp(ValueError, regexp): - img.dec(dec_kwd) - - # Not in decimal or dd:mm:ss[.sss] format - assertValueErrorRaised('+41d16m9s') - assertValueErrorRaised('45:59:52.7685') - assertValueErrorRaised('-8:12:05.8') - assertValueErrorRaised('N/A') - - # 'DEC' keyword not in FITS header - with self.assertRaises(KeyError): - with self.random() as img: - img.dec(dec_kwd) + with self.assertRaisesRegexp(want, regexp): + img.dec('DEC')