def get_datetime(from_value): """ Ensure datetime values are in MJD. This is meant to handle any odd formats that telescopes have for datetime values. Relies on astropy, until astropy fails. :param from_value: :return: datetime instance """ if from_value is not None: try: result = Time(from_value) result.format = 'mjd' return result except ValueError: try: # VLASS has a format astropy fails to understand # from datetime import datetime result = Time( dt_datetime.strptime(from_value, '%H:%M:%S')) result.format = 'mjd' return result except ValueError: logging.error('Cannot parse datetime {}'.format(from_value)) return None else: return None
def time_chunk(self, nameFile): self.logger.info("\t ... Observing time Info ... \n") t = tables.table(nameFile) self.time = t.getcol('TIME') t.close() starttime = self.time[0] endtime = self.time[-1] startdate = Time(starttime / 3600. / 24., format='mjd', scale='utc') startdate.format = 'iso' startdate.subformat = 'date_hm' enddate = Time(endtime / 3600. / 24., format='mjd', scale='utc') enddate.format = 'iso' enddate.subformat = 'date_hm' self.logger.info('\t Start date: {0:%y}{0:%b}{0:%d}:{0:%X}'.format( startdate.datetime)) self.logger.info( '\t End date : {0:%y}{0:%b}{0:%d}:{0:%X} \n\n'.format( enddate.datetime)) return startdate, enddate
def __getitem__(self, i): """ Supports indexing of the TimeScale, e.g. ts[0:10:2] """ if isinstance(i, slice): skip = 1 if i.step is None else i.step start = 0 if i.start is None else i.start stop = self.n_step if i.stop is None else i.stop new_n_step = (stop - start) // skip new_time_unix = self.val_start + start * self.val_step new_time_obj = Time(new_time_unix, format='unix') new_time_obj.format = self.time_format new_delta_sec = self.val_step * skip new_delta_obj = TimeDelta(new_delta_sec, format='sec') new_delta_obj.format = self.time_delta_format #return self.val_start + self.val_step * np.arange(start, stop, step) return TimeScale(self.name, new_time_obj.value, new_delta_obj.value, new_n_step, time_format=new_time_obj.format, time_delta_format=new_delta_obj.format) else: if i < 0 or i > self.n_step: raise IndexError( f"Index ({i}) is out of axis bound ({self.n_step})") t = Time(i * self.val_step + self.val_start, format='unix') t.format = self.time_format return t
def time_chunk(self, cfg_par): self.logger.info("\t ... Observing time Info ... \n") self.msfile = cfg_par['general']['msfullpath'] t = tables.table(self.msfile) self.time = t.getcol('TIME') t.close() starttime = self.time[0] endtime = self.time[-1] time_chunk = float(cfg_par['rfi']['chunks']['time_step']) * 60. times = np.arange(starttime, endtime + time_chunk * 1., time_chunk) cfg_par['rfi']['times'] = times startdate = Time(starttime / 3600. / 24., format='mjd', scale='utc') cfg_par['rfi']['startdate'] = startdate startdate.format = 'iso' startdate.subformat = 'date_hm' enddate = Time(endtime / 3600. / 24., format='mjd', scale='utc') cfg_par['rfi']['enddate'] = enddate enddate.format = 'iso' enddate.subformat = 'date_hm' self.logger.info('\t Start date: {0:%y}{0:%b}{0:%d}:{0:%X}'.format( startdate.datetime)) self.logger.info( '\t End date : {0:%y}{0:%b}{0:%d}:{0:%X} \n\n'.format( enddate.datetime)) return times, startdate, enddate
def get_datetime(filename): # Reading binary data with open(filename, "rb") as f: bin_data = f.read() # Searching datetime start byte date_key = r'\xe0.\x00\x00\x0b' matches = [] for match in finditer(date_key, bin_data): matches.append(match.span()) date_offset = matches[-1][0] - 8 # Unpacking datetime time_values = {} hours, days = unpack_from("<II", bin_data, date_offset) secs = days * 45.0 * 60.0 + hours / (4294967295.0 / 45.0) * 60.0 time_values["UNIX"] = secs - 2938117104000.0 # Convert to ISO and MJD time formats t = Time(time_values["UNIX"], format="unix") t.format = "iso" t.out_subfmt = "date_hm" time_values["ISO"] = t.value t.format = "mjd" time_values["MJD"] = str(int(np.floor(t.value))) return time_values
def rv(obj_name, v_sun_star, obstime_range=['2020-01-01','2020-12-31'], obsloc='Las Campanas Observatory'): '''Calculate the relative velocity between an exoplanet and the Earth Inputs --- obj_name: string The name of the object (e.g. star) that you want the coordinates of v_sun_star: integer or float in m/s The relative velocity between the Sun and the exoplanet system obstime_range: list of strings, optional A list containing the beginning and end date for the range of time that you're interested in calculating the RV between the Earth and the exoplanet of interest for. Defaults to ['2020-01-01','2020-12-31']. obsloc: string, optional Name of relevant observatory. Defaults to 'Las Campanas Observatory'. Not sure how much this affects the results. Returns --- rv_df: pandas dataframe columns: date (jd), rv (in km/s) ''' # Give v_sun_star units v_sun_star = v_sun_star*m_per_s # Find the location of the observatory loc = coord.EarthLocation.of_site(obsloc) # Find the coordinates of the object (e.g. host star) sc = SkyCoord.from_name(obj_name) # Create an astropy time object with the specified range of times t1 = Time(obstime_range[0]) t1.format = 'jd' # 'jd' could be a function input t2 = Time(obstime_range[-1]) t2.format = 'jd' # 'jd' could be a function input # I'm not sure what the length of these steps is - Victoria 10/29/20 times = Time(np.arange(t1.value, t2.value), format='jd') with coord.solar_system_ephemeris.set('jpl'): # 'jpl' could be a function input rv_corrs = sc.radial_velocity_correction(obstime=times, location=loc) # Calculate Earth-centric RVs in km/s v_star = (v_sun_star - rv_corrs).to(km_per_s) # Get rid of time's unit times = times.value rv_df = pd.DataFrame({"date":times,'rv':v_star}) return(rv_df)
def change_times_thread(logger, prfs_d, fits_image): """ @param logger: @param prfs_d: @param fits_image: @return True: """ fits_dir = '{}/{}/CCDs'.format(prfs_d['fits_dir'], mag) data, header = fits.getdata('{}/{}'.format(fits_dir, fits_image), header=True) dither = fits_image[-6:-5] if dither == '1': header['DATE-OBS'] = prfs_d['time_1'] # Change format t = Time(prfs_d['time_1']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) elif dither == '2': header['DATE-OBS'] = prfs_d['time_2'] t = Time(prfs_d['time_2']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) elif dither == '3': header['DATE-OBS'] = prfs_d['time_3'] t = Time(prfs_d['time_3']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) elif dither == '4': header['DATE-OBS'] = prfs_d['time_4'] t = Time(prfs_d['time_4']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) else: header['DATE-OBS'] = prfs_d['time_1'] # Change format t = Time(prfs_d['time_1']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) print('opens {} date-obs {} mjd-obs {} d {}'.format( fits_image, header['DATE-OBS'], header['MJD-OBS'], dither)) fits.writeto('{}/{}_copy'.format(fits_dir, fits_image), data, header, clobber=True) return True
def change_times_thread(prfs_d, fits_image): """ @param prfs_d: @param fits_image: @return True: """ data, header = fits.getdata('{}/{}'.format(prfs_d['fits_dir'], fits_image), header=True) dither = fits_image[-6:-5] print('dither {}'.format(dither)) if dither == '1': header['DATE-OBS'] = prfs_d['time_1'] # Change format t = Time(prfs_d['time_1']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) elif dither == '2': header['DATE-OBS'] = prfs_d['time_2'] t = Time(prfs_d['time_2']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) elif dither == '3': header['DATE-OBS'] = prfs_d['time_3'] t = Time(prfs_d['time_3']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) elif dither == '4': header['DATE-OBS'] = prfs_d['time_4'] t = Time(prfs_d['time_4']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) else: header['DATE-OBS'] = prfs_d['time_1'] # Change format t = Time(prfs_d['time_1']) t.format = 'mjd' header['MJD-OBS'] = float(str(t)) print('opens {} date-obs {} mjd-obs {} d {}'.format( fits_image, header['DATE-OBS'], header['MJD-OBS'], dither)) print('fits_image {}'.format(fits_image)) fits.writeto('{}/{}_t.fits'.format(prfs_d['fits_dir'], fits_image[:-5]), data, header) return True
def get_pyephem_instance_for_type(target): """ Constructs a pyephem body corresponding to the proper object type in order to perform positional calculations for the target :returns: FixedBody or EllipticalBody :raises Exception: When a target type other than sidereal or non-sidereal is supplied """ if target.type == target.SIDEREAL: body = ephem.FixedBody() body._ra = Angle(str(target.ra) + 'd').to_string(unit=units.hourangle, sep=':') body._dec = Angle(str(target.dec) + 'd').to_string(unit=units.degree, sep=':') body._epoch = target.epoch if target.epoch else ephem.Date(DEFAULT_VALUES['epoch']) return body elif target.type == target.NON_SIDEREAL: body = ephem.EllipticalBody() body._inc = ephem.degrees(target.inclination) if target.inclination else 0 body._Om = target.lng_asc_node if target.lng_asc_node else 0 body._om = target.arg_of_perihelion if target.arg_of_perihelion else 0 body._a = target.semimajor_axis if target.semimajor_axis else 0 body._M = target.mean_anomaly if target.mean_anomaly else 0 if target.ephemeris_epoch: epoch_M = Time(target.ephemeris_epoch, format='jd') epoch_M.format = 'datetime' body._epoch_M = ephem.Date(epoch_M.value) else: body._epoch_M = ephem.Date(DEFAULT_VALUES['epoch']) body._epoch = target.epoch if target.epoch else ephem.Date(DEFAULT_VALUES['epoch']) body._e = target.eccentricity if target.eccentricity else 0 return body else: raise Exception("Object type is unsupported for visibility calculations")
def eq_to_alt_az(ra, dec, lat, long): ra = ra * 15 time = datetime.utcnow() time_hrs = time.hour + time.minute / 60 + time.second / 3600 time_julian = Time(time) time_julian.format = 'jd' time_j2000 = time_julian.value - 2451545 # Get J2000 time from substracting julian time of 1.1.2000 12:00 from current julian time. local_sid_time = (100.46 + 0.98547 * time_j2000 + long + 15 * time_hrs) % 360 hour_angle = local_sid_time - ra alt = math.degrees( math.asin( math.sin(math.radians(dec)) * math.sin(math.radians(lat)) + math.cos(math.radians(dec)) * math.cos(math.radians(lat)) * math.cos(math.radians(hour_angle)))) a = math.acos((math.sin(math.radians(dec)) - math.sin(math.radians(alt)) * math.sin(math.radians(lat))) / (math.cos(math.radians(alt)) * math.cos(math.radians(lat)))) a = math.degrees(a) az = 0 if math.degrees(math.sin(math.radians(hour_angle))) < 0: az = a else: az = 360 - a return alt, az
def _process_photometry_from_plaintext(self, data_product): """ Processes the photometric data from a plaintext file into a dict, which can then be stored as a ReducedDatum for further processing or display. File is read using astropy as specified in the below documentation. The file is expected to be a multi-column delimited file, with headers for time, magnitude, filter, and error. # http://docs.astropy.org/en/stable/io/ascii/read.html :param data_product: Photometric DataProduct which will be processed into a dict :type data_product: DataProduct :returns: python dict containing the data from the DataProduct :rtype: dict """ photometry = {} data = ascii.read(data_product.data.path) if len(data) < 1: raise InvalidFileFormatException( 'Empty table or invalid file type') for datum in data: time = Time(float(datum['time']), format='mjd') utc = TimezoneInfo(utc_offset=0 * units.hour) time.format = 'datetime' value = { 'magnitude': datum['magnitude'], 'filter': datum['filter'], 'error': datum['error'] } photometry.setdefault(time.to_datetime(timezone=utc), []).append(value) return photometry
def get_leap_seconds(gps): """Find the number of leap seconds at a given gps time using astropy's time module (by comparing UTC to TAI and subtracting 19, the base difference between TAI and GPS scales).""" t = Time(gps, format='gps') t.format = 'iso' return (t.tai.to_datetime() - t.utc.to_datetime()).seconds - 19
def write_fits(img, metadata, fitsobj): imgtime = Time(metadata[0][0] + config.inttime*0.5, scale='utc', format='unix', location=(LOFAR_CS002_LONG, LOFAR_CS002_LAT)) imgtime.format='isot' imgtime.out_subfmt = 'date_hms' filename = '%s_S%0.1f_I%ix%i_W%i_A%0.1f.fits' % (imgtime.datetime.strftime("%Y%m%d%H%M%SUTC"), np.mean(subbands), len(subbands), config.inttime, config.window, config.alpha) filename = os.path.join(config.output, filename) if os.path.exists(filename): logger.info("'%s' exists - skipping", filename) return # CRVAL1 should hold RA in degrees. sidereal_time returns hour angle in # hours. fitsobj.header['CRVAL1'] = imgtime.sidereal_time(kind='apparent').value * 15 fitsobj.header['DATE-OBS'] = str(imgtime) imgtime_end = imgtime + TimeDelta(config.inttime, format='sec') fitsobj.header['END_UTC'] = str(imgtime_end) t = Time.now(); t.format = 'isot' fitsobj.header['DATE'] = str(t) fitsobj.data[0, 0, :, :] = img data = img[np.logical_not(np.isnan(img))] quality = rms.rms(rms.clip(data)) high = data.max() low = data.min() fitsobj.header['DATAMAX'] = high fitsobj.header['DATAMIN'] = low fitsobj.header['HISTORY'][0] = 'AARTFAAC 6 stations superterp' fitsobj.header['HISTORY'][1] = 'RMS {}'.format(quality) fitsobj.header['HISTORY'][2] = 'DYNAMIC RANGE {}:{}'.format(int(round(high)), int(round(quality))) fitsobj.writeto(filename) logger.info("%s %0.3f %i:%i", filename, quality, int(round(high)), int(round(quality)))
def on_save(self, path=None): """ This is a hook that is called just before saving the file. It can be used, for example, to update values in the metadata that are based on the content of the data. Override it in the subclass to make it do something, but don't forget to "chain up" to the base class, since it does things there, too. Parameters ---------- path : str The path to the file that we're about to save to. """ if isinstance(path, str): self.meta.filename = os.path.basename(path) current_date = Time(datetime.datetime.now()) current_date.format = 'isot' self.meta.date = current_date.value if not hasattr(self.meta, 'model_type'): klass = self.__class__.__name__ if klass != 'DataModel': self.meta.model_type = klass
def miriademoon(self, epoch, location): """ Returns the table of RA, DEC and markers with Miriade calulator Attributes: target (string) : target epoch (Time) : epoch epoch_step (string) : Miriade definition epoch_nsteps (int) : Iteration Number coordtype (int) : Miriade definition location (string) : Miriade definition """ epoch_iso = Time(epoch, format='fits') epoch_iso.format = 'iso' eph = Miriade.get_ephemerides('p:moon', epoch=epoch_iso.value, epoch_step='1m', epoch_nsteps=1, coordtype=1, location=location) ra = [] dec = [] marker = [] for line in eph: ra.append(line['RA']) dec.append(line['DEC']) if line['V'] < -1: marker.append(-int(line['V'])) else: marker.append(1) return Table([ra, dec, marker], names=['RA', 'DEC', 'MARKER'])
def on_save(self, path=None): """ This is a hook that is called just before saving the file. It can be used, for example, to update values in the metadata that are based on the content of the data. Override it in the subclass to make it do something, but don't forget to "chain up" to the base class, since it does things there, too. Parameters ---------- path : str The path to the file that we're about to save to. """ if isinstance(path, str): self.meta.filename = os.path.basename(path) current_date = Time(datetime.datetime.now()) current_date.format = 'isot' self.meta.date = current_date.value # Enforce model_type to be the actual type of model being saved. self.meta.model_type = self._model_type # Remove None nodes from the tree: def _remove_none(node): if node is None: return RemoveNode else: return node self._instance = treeutil.walk_and_modify(self._instance, _remove_none)
def test_strftime_array(): tstrings = ['2010-09-03 00:00:00', '2005-09-03 06:00:00', '1995-12-31 23:59:60'] t = Time(tstrings) for format in t.FORMATS: t.format = format assert t.strftime('%Y-%m-%d %H:%M:%S').tolist() == tstrings
def test_trajectory_export(): """Tests the interpolation accuracy for ISS.""" # Init TLE line1 = "1 25544U 98067A 19343.69339541 .00001764 00000-0 38792-4 0 9991" line2 = "2 25544 51.6439 211.2001 0007417 17.6667 85.6398 15.50103472202482" # test init time init_time = Time(2458826.3, format="jd", scale="utc") init_time.format = "isot" duration = TimeDelta(3.0, format="jd") steps = 4000 # number of steps within the propagation duration dt, time_list = generate_timelist(init_time, duration, steps) prop_output = propagation_engine(line1, line2, time_list) ts = prop_output["traj"].to_timeseries() pvt = prop_output["traj"].coord_list[10] # print(ts) # print(ts["time", "v_X"]) assert (ts.time[10] - pvt.obstime) < 17 * u.us assert (ts[10]["r_X"] - pvt.cartesian.x) < 1 * u.um
def local_time_to_julian_day(self, date): microseconds, _ = modf(zero_if_none(date.second) * 1000000) local_datetime = pytz.timezone(self.timezone_id).localize( datetime.datetime(date.year, date.month, date.day, zero_if_none(date.hour), zero_if_none(date.minute), int(zero_if_none(date.second)), int(microseconds))) tm = Time(local_datetime, format="datetime") tm.format = "jd" return tm.value
def convert_time(analysis): #analysis is the fits file in the photometry function t = Time(analysis[0].header['DATE-OBS']) t.format = 'mjd' result = t.value return result
def carrington_rotation_time(crot, longitude: u.deg = None): """ Return the time of a given Carrington rotation. Fractional Carrington rotation numbers can be provided in two ways: * Fractional numbers to ``crot`` * Integer numbers to ``crot`` and a Carrington longitude to ``longitude`` Inputs can be arrays. If both ``crot`` and ``longitude`` are provided, the output shape will be the broadcasted combination. The round-trip from this method to `carrington_rotation_number` has absolute errors of < 0.11 seconds. Parameters ---------- crot : `int`, `float`, `~astropy.units.Quantity` Carrington rotation number(s). Can be a fractional rotation number. longitude : `~astropy.units.Quantity` Carrington longitude(s), which must be > 0 degrees and <= 360 degrees. If provided, ``crot`` must be strictly integral. Returns ------- `astropy.time.Time` Examples -------- >>> from sunpy.coordinates.sun import carrington_rotation_time >>> import astropy.units as u >>> carrington_rotation_time(2242) <Time object: scale='utc' format='iso' value=2021-03-17 22:31:37.030> >>> carrington_rotation_time(2000.25) <Time object: scale='utc' format='iso' value=2003-02-27 02:52:57.315> >>> carrington_rotation_time(2000, 270*u.deg) <Time object: scale='utc' format='iso' value=2003-02-27 02:52:57.315> """ crot = crot << u.one if longitude is not None: if not u.allclose(crot % 1, 0): raise ValueError("Carrington rotation number(s) must be integral if `longitude` is provided.") if (longitude <= 0*u.deg).any() or (longitude > 360*u.deg).any(): raise ValueError("Carrington longitude(s) must be > 0 degrees and <= 360 degrees.") crot = crot + (1 - longitude/(360*u.deg)) estimate = (constants.mean_synodic_period * (crot - 1)) + constants.first_carrington_rotation # The above estimate is inaccurate (see comments below in carrington_rotation_number), # so put the estimate into carrington_rotation_number to determine a correction amount def refine(estimate): crot_estimate = carrington_rotation_number(estimate) dcrot = crot - crot_estimate # Correct the estimate using a linear fraction of the Carrington rotation period return estimate + (dcrot * constants.mean_synodic_period) # Perform two iterations of the correction to achieve sub-second accuracy estimate = refine(estimate) estimate = refine(estimate) t = Time(estimate, scale='tt', format='jd').utc t.format = 'iso' return t
def _process_photometry_from_plaintext(self, data_product, extras): photometry = [] data_aws = default_storage.open(data_product.data.name, 'r') data = ascii.read(data_aws.read(), names=['time', 'filter', 'magnitude', 'error']) if len(data) < 1: raise InvalidFileFormatException('Empty table or invalid file type') for datum in data: time = Time(float(datum['time']), format='mjd') utc = TimezoneInfo(utc_offset=0*units.hour) time.format = 'datetime' value = { 'timestamp': time.to_datetime(timezone=utc), 'magnitude': datum['magnitude'], 'filter': datum['filter'], 'error': datum['error'] } value.update(extras) photometry.append(value) return photometry
def test_strftime_leapsecond(): time_string = '1995-12-31 23:59:60' t = Time(time_string) for format in t.FORMATS: t.format = format assert t.strftime('%Y-%m-%d %H:%M:%S') == time_string
def carrington_rotation_time(crot): """ Return the time of a given Carrington rotation. The round-trip from this method to `carrington_rotation_number` has absolute errors of < 0.11 seconds. Parameters ---------- crot : float Carrington rotation number. Can be a fractional cycle number. Returns ------- astropy.time.Time """ estimate = (constants.mean_synodic_period.to_value('day') * (crot - 1)) + constants.first_carrington_rotation # The above estimate is inaccurate (see comments below in carrington_rotation_number), # so put the estimate into carrington_rotation_number to determine a correction amount def refine(estimate): crot_estimate = carrington_rotation_number(estimate) dcrot = crot - crot_estimate # Correct the estimate using a linear fraction of the Carrington rotation period return estimate + (dcrot * constants.mean_synodic_period) # Perform two iterations of the correction to achieve sub-second accuracy estimate = refine(estimate) estimate = refine(estimate) t = Time(estimate, scale='tt', format='jd').utc t.format = 'iso' return t
def main(input_file, exp_code): exp_code = str(exp_code) # Load data from CSV file data = ascii.read(input_file, format='csv', comment='#', header_start=0) # Convert data into desired form az_deg = data['un_az']*180*(1/np.pi) el_deg = data['el']*180*(1/np.pi) rang = data['range'] jd = data['jd'] # Generate master schedule file print('Creating master schedule file.') with open(exp_code+'_master.out', 'w') as f: for i in range(0, len(data)): print("JD : " + format(jd[i], '.8f') + " ; Az : " + format(az_deg[i], '.3f') + " ; El : " + format(el_deg[i], '.3f') + " ; Rn : 0.0 ", file=f) print('Done!') # Now generate block schedules print('Generating schedule blocks.') interval = 0.00347 # 5 minutes in fraction of day start_time = jd[0] end_time = max(jd) num_scans = math.ceil((end_time - start_time)/interval) # calculate how many 5 min chunks are needed rounded up scantime_array = np.arange(start_time, start_time + (num_scans+0.1)*interval, interval) # the 0.1 makes sure we have a final value > the end time with open(exp_code+'_master.out', 'r') as file_read: if not os.path.exists(cwd + '/' + exp_code+'_blocks'): # check if subdir exists os.mkdir(cwd + '/' + exp_code+'_blocks') # create if it does not for line in file_read: # iterate through each line of master schedule file jd_time = float(line[5:21]) # extract JD time value scan_index = max(np.where((round(jd_time,8)/np.around(scantime_array, 8)) >= 1.0)[0]) # determine the scan that the given time will fall on - rounding required because of floating point rounding errors block_file_name = exp_code + '_b' + str(scan_index+1).zfill(3) + '.out' # determine the name of that scan's file with open(cwd + '/' + exp_code+'_blocks/' + block_file_name , 'a') as file_write: # write the data to the relevant file print(str.rstrip(line), file=file_write) # strip \n before printing print('Done!') # create shell script wrapper print('Creating shell script wrapper.') if os.path.exists(cwd + '/'+exp_code+ '_wrapper.sh'): os.remove(cwd + '/'+exp_code+ '_wrapper.sh') scan_times = Time(scantime_array, format='jd', scale='utc') scan_times.format = 'iso' with open(cwd + '/'+exp_code+ '_wrapper.sh', 'w') as f: print('#!/bin/bash\n', file=f) # append shebang to shell scripts print('currenttime=$(date +%s)\n', file=f) block_list = sorted(os.listdir(cwd + '/'+exp_code+'_blocks')) # read block schedule subdirectory for i in range(0, len(block_list)): if (i % 2) == 0: # if even track normally print("if [ $currenttime -le $(date --date='" + str(scan_times[i]+ timedelta(seconds=30)) + " UTC' +%s) ]",file=f) # extra 30s is to account for the few seconds it takes for previous sattrk scan to finish print("then\n sattrk -b -d 1/xs -i " + block_list[i] + " sys26m\nfi\n", file=f) else: # if odd track with offset print("if [ $currenttime -le $(date --date='" + str(scan_times[i]+ timedelta(seconds=30)) + " UTC' +%s) ]",file=f) # extra 30s is to account for the few seconds it takes for previous sattrk scan to finish print("then\n sattrk -b -d 1/xs -x 5 -i " + block_list[i] + " sys26m\nfi\n", file=f) print('Done!') # Write out the scan information of each 5 min block - for use with spectrum analyser recording and data reduction avg_el_list, avg_range_list = scanAvgElRange(data, scantime_array) print('Writing out schedule block start times.') if os.path.exists(cwd + '/'+exp_code+ '_scaninfo.out'): os.remove(cwd + '/'+exp_code+ '_scaninfo.out') with open(cwd + '/'+exp_code+ '_scaninfo.out','w') as f: for i in range(0, len(scantime_array)): print(scantime_array[i], avg_el_list[i], avg_range_list[i], file=f) print('Done!')
def time(self): """ The timestamps of the data. """ t = Time(self._data.index) # Set time format to enable plotting with astropy.visualisation.time_support() t.format = 'iso' return t
def utc_gregorian_to_jd(date): if date.hour is None: date.set_time_to_day_start() tm = Time( {"year": date.year, "month": date.month, "day": date.day, "hour": zero_if_none(date.hour), "minute": zero_if_none(date.minute), "second": zero_if_none(date.second)}, format='ymdhms') tm.format = "jd" return tm.value
def validate(self, obj, value): """ try to parse and return an ISO time string """ try: the_time = Time(value) the_time.format = "iso" return the_time except ValueError: return self.error(obj, value)
def utc2mjd(dt): """ Converts UTC values to MJD datetime objects """ t = Time(dt, format='datetime') t.format = 'mjd' return t.value
def mjd2utc(mjd): """ Converts MJD values to UTC datetime objects """ t = Time(mjd, format='mjd') t.format = 'datetime' return t.value
def convertMJD(mjd): ''' Converts MJD to weekday ,date, month, year ''' mydate=Time(mjd,format='mjd') mydate.format='fits' tdate= date(int(mydate.value[0:4]),int(mydate.value[5:7]),int(mydate.value[8:10])) month = calendar.month_name[tdate.month] weekday = calendar.day_name[tdate.weekday()] ret_string = '{0} {1}-{2}-{3} '.format(weekday,int(mydate.value[8:10]),month,int(mydate.value[0:4])) return ret_string
def test_strftime_scalar(): """Test of Time.strftime """ time_string = '2010-09-03 06:00:00' t = Time(time_string) for format in t.FORMATS: t.format = format assert t.strftime('%Y-%m-%d %H:%M:%S') == time_string
def get_member_info(object_name, filtertype='r', imagetype='p'): """ Query the ssois ephemeris for images of a given object. Then parse through for desired image type, filter, exposure time, and telescope instrument """ # From the given input, identify the desired filter and rename appropriately Replace this? if filtertype.lower().__contains__('r'): filtertype = 'r.MP9601' # this is the old (standard) r filter for MegaCam if filtertype.lower().__contains__('u'): filtertype = 'u.MP9301' # Define time period of image search, basically while MegaCam in operation search_start_date = Time('2013-01-01', scale='utc') # epoch1=2013+01+01 search_end_date = Time('2017-01-01', scale='utc') # epoch2=2017+1+1 print "----- Searching for images of object {}".format(object_name) query = Query(object_name, search_start_date=search_start_date, search_end_date=search_end_date) try: objects = parse_ssois_return(query.get(), object_name, imagetype, camera_filter=filtertype) except IOError: print "Sleeping 30 seconds" time.sleep(30) objects = parse_ssois_return(query.get(), object_name, imagetype, camera_filter=filtertype) # Setup output, label columns if len(objects)>0: output = '{}/{}_object_images.txt'.format(_OUTPUT_DIR, object_name) with open(output, 'w') as outfile: outfile.write("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n".format( "Object", "Image", "Exp_time", "RA (deg)", "Dec (deg)", "time", "filter", "RA rate (\"/hr)", "Dec rate (\"/hr)")) mjds = [] for line in objects: mjds.append(float(line['MJD'])) #Have to convert elements to floats start_time = Time(min(mjds), format='mjd') - 1.0*units.minute stop_time = Time(max(mjds), format='mjd') + 1.0*units.minute #Query Horizons once to establish position values over given time period, then give it a current time which it interpolates withl body = horizons.Body(object_name, start_time=start_time, stop_time=stop_time, step_size=10 * units.minute) for line in objects: with open(output, 'a') as outfile: time = Time(line['MJD'], format='mjd', scale='utc') time.format = 'iso' body.current_time = time p_ra = body.coordinate.ra.degree p_dec = body.coordinate.dec.degree ra_dot = body.ra_rate.to(units.arcsecond/units.hour).value dec_dot = body.dec_rate.to(units.arcsecond/units.hour).value try: outfile.write("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n".format( object_name, line['Image'], line['Exptime'], p_ra, p_dec, Time(line['MJD'], format='mjd', scale='utc'), line['Filter'], ra_dot, dec_dot)) except Exception, e: print "Error writing to outfile: {}".format(e)
def test_strftime_array_2(): tstrings = [['1998-01-01 00:00:01', '1998-01-01 00:00:02'], ['1998-01-01 00:00:03', '1995-12-31 23:59:60']] tstrings = np.array(tstrings) t = Time(tstrings) for format in t.FORMATS: t.format = format assert np.all(t.strftime('%Y-%m-%d %H:%M:%S') == tstrings) assert t.strftime('%Y-%m-%d %H:%M:%S').shape == tstrings.shape
def plot_magnitudes(mags=None, errors=None, times=None, source=None, night=None, ref_mag=0, alpha=0.25, y_range=None): """ Plot one night of magnitude data for one source, overlaying a rolling mean and indication of mean/deviation. """ mean = np.nanmean(mags) std = np.nanstd(mags) working_times = times # - night plt.errorbar(working_times, mags, yerr=errors, fmt='o', alpha=alpha, label='night: {}'.format(night)) plt.xlim(working_times.min(), working_times.max()) plt.plot(plt.xlim(), [mean, mean], 'k--', ) plt.plot(plt.xlim(), [mean + std, mean + std], 'k:') plt.plot(plt.xlim(), [mean - std, mean - std], 'k:') plt.plot(pd.rolling_mean(working_times, 20, center=True), pd.rolling_mean(mags, 20, center=True), color='gray', linewidth=3) if y_range: plt.ylim(y_range) else: # Make sure plot range is at least 0.1 mag... min_range = 0.1 ylim = plt.ylim() if ylim[1] - ylim[0] < min_range: plt.ylim(mean - min_range/2, mean + min_range/2) ylim = plt.ylim() # Reverse vertical axis so brighter is higher plt.ylim((ylim[1], ylim[0])) # # Add marker indicating brightness of star. # size = 1000./(mean - ref_mag + 0.1)**2 # plt.scatter([0.8*(plt.xlim()[1]-plt.xlim()[0]) + plt.xlim()[0]], # [0.8*(plt.ylim()[1] - plt.ylim()[0]) + plt.ylim()[0]], # c='red', marker='o', s=size) # plt.legend() calendar_date = Time(night, format='jd', out_subfmt='date') calendar_date.format = 'iso' plt.title('night {}'.format(calendar_date)) plt.xlabel('time (days)') return mean, std
def convert_time(mytime2): """ This Function is convert the date we have into MJD units .. exp: 131009= 2013 October 9 >>> 2012-10-09 (this is the format that Time function in astopry accepts. >>> 50987.00 is the final time """ word2='20' for i in range(0,len(mytime2),2): word2+=str(mytime2[i]+mytime2[i+1])+'-' word2=word2[:-1] t=Time(word2) t.format='mjd' result=t.value return result
def on_save(self, path=None): """ This is a hook that is called just before saving the file. It can be used, for example, to update values in the metadata that are based on the content of the data. Override it in the subclass to make it do something, but don't forget to "chain up" to the base class, since it does things there, too. Parameters ---------- path : str The path to the file that we're about to save to. """ if isinstance(path, str): self.meta.filename = os.path.basename(path) current_date = Time(datetime.datetime.now()) current_date.format = 'isot' self.meta.date = current_date.value
def convert_time(start_time, exposure): """Convert a start time and exposure length into an mjd_start and mjd_end time.""" logging.debug('Begin convert_time.') if start_time is not None and exposure is not None: logging.debug( 'Use date {} and exposure {} to convert time.'.format(start_time, exposure)) if type(start_time) is float: t_start = Time(start_time, format='mjd') else: t_start = Time(start_time) dt = TimeDelta(exposure, format='sec') t_end = t_start + dt t_start.format = 'mjd' t_end.format = 'mjd' mjd_start = t_start.value mjd_end = t_end.value logging.debug('End convert_time mjd start {} mjd end {} .'.format( mjd_start, mjd_end)) return mjd_start, mjd_end return None, None
def __init__(self, init=None, schema=None, pass_invalid_values=False, strict_validation=False, **kwargs): """ Parameters ---------- init : shape tuple, file path, file object, astropy.io.fits.HDUList, numpy array, None - None: A default data model with no shape - shape tuple: Initialize with empty data of the given shape - file path: Initialize from the given file (FITS or ASDF) - readable file object: Initialize from the given file object - ``astropy.io.fits.HDUList``: Initialize from the given `~astropy.io.fits.HDUList`. - A numpy array: Used to initialize the data array - dict: The object model tree for the data model schema : tree of objects representing a JSON schema, or string naming a schema, optional The schema to use to understand the elements on the model. If not provided, the schema associated with this class will be used. pass_invalid_values: If true, values that do not validate the schema will be added to the metadata. If false, they will be set to None strict_validation: if true, an schema validation errors will generate an excption. If false, they will generate a warning. kwargs: Aadditional arguments passed to lower level functions """ # Override value of validation parameters # if environment value set self._pass_invalid_values = self.get_envar("PASS_INVALID_VALUES", pass_invalid_values) self._strict_validation = self.get_envar("STRICT_VALIDATION", strict_validation) # Load the schema files if schema is None: schema_path = os.path.join(URL_PREFIX, self.schema_url) # Create an AsdfFile so we can use its resolver for loading schemas asdf_file = AsdfFile() schema = asdf_schema.load_schema(schema_path, resolver=asdf_file.resolver, resolve_references=True) self._schema = mschema.merge_property_trees(schema) # Provide the object as context to other classes and functions self._ctx = self # Determine what kind of input we have (init) and execute the # proper code to intiailize the model self._files_to_close = [] self._iscopy = False is_array = False is_shape = False shape = None if init is None: asdffile = self.open_asdf(init=None, **kwargs) elif isinstance(init, dict): asdffile = self.open_asdf(init=init, **kwargs) elif isinstance(init, np.ndarray): asdffile = self.open_asdf(init=None, **kwargs) shape = init.shape is_array = True elif isinstance(init, tuple): for item in init: if not isinstance(item, int): raise ValueError("shape must be a tuple of ints") shape = init is_shape = True asdffile = self.open_asdf(init=None, **kwargs) elif isinstance(init, DataModel): asdffile = None self.clone(self, init) if not isinstance(init, self.__class__): self.validate() return elif isinstance(init, AsdfFile): asdffile = init elif isinstance(init, fits.HDUList): asdffile = fits_support.from_fits(init, self._schema, self._ctx) elif isinstance(init, (str, bytes)): if isinstance(init, bytes): init = init.decode(sys.getfilesystemencoding()) file_type = filetype.check(init) if file_type == "fits": hdulist = fits.open(init) asdffile = fits_support.from_fits(hdulist, self._schema, self._ctx, **kwargs) self._files_to_close.append(hdulist) elif file_type == "asdf": asdffile = self.open_asdf(init=init, **kwargs) else: # TODO handle json files as well raise IOError( "File does not appear to be a FITS or ASDF file.") else: raise ValueError( "Can't initialize datamodel using {0}".format(str(type(init)))) # Initialize object fields as determined from the code above self._shape = shape self._instance = asdffile.tree self._asdf = asdffile # Initalize class dependent hidden fields self._no_asdf_extension = False # Instantiate the primary array of the image if is_array: primary_array_name = self.get_primary_array_name() if not primary_array_name: raise TypeError( "Array passed to DataModel.__init__, but model has " "no primary array in its schema") setattr(self, primary_array_name, init) if is_shape: if not self.get_primary_array_name(): raise TypeError( "Shape passed to DataModel.__init__, but model has " "no primary array in its schema") # if the input is from a file, set the filename attribute if isinstance(init, str): self.meta.filename = os.path.basename(init) elif isinstance(init, fits.HDUList): info = init.fileinfo(0) if info is not None: filename = info.get('filename') if filename is not None: self.meta.filename = os.path.basename(filename) # if the input model doesn't have a date set, use the current date/time if not self.meta.hasattr('date'): current_date = Time(datetime.datetime.now()) current_date.format = 'isot' self.meta.date = current_date.value # store the data model type, if not already set klass = self.__class__.__name__ if klass != 'DataModel': if not self.meta.hasattr('model_type'): self.meta.model_type = klass # initialize arrays from keyword arguments when they are present for attr, value in kwargs.items(): if value is not None: subschema = properties._get_schema_for_property(self._schema, attr) if 'datatype' in subschema: setattr(self, attr, value)
parser.add_argument('--norb',type=int,help='Number of orbits in sky plot',default=100) parser.add_argument('--Qmax',type=float,help='Max apocenter to plot',default=1000.0) parser.add_argument('--interactive','-i',action='store_true',help='Interactive plot') parser.add_argument('--zvzfile',type=str,help='zvz file name',default='zvz.png') parser.add_argument('--elemfile',type=str,help='elem file name',default='elem_noerr.png') parser.add_argument('--skyfile',type=str,help='sky orbits file name',default='sky.png') parser.add_argument('--pickle_zvz',action='store_true',help='pickle z/vz data') parser.add_argument('--pickle_zvz_file',type=str,help='pickle file name',default='zvz.pkl') args = parser.parse_args() # dt using astropy Time d = Time(args.date2)-Time(args.date1) d.format = 'jd' dt = d.value/365.25 # compute the basic parameters if args.sep1 != None: R,V,B,phi,pa0,zsgn = seppa2rvbphi(args.sep1,args.pa1,args.sep2,args.pa2,args.mass,dt,args.distance) titlestr = 'Input parameters\n$S_1:'+str(args.sep1)+'$" $PA_1:'+str(args.pa1)+'^\circ$ $D_1$:'+str(args.date1)+' $S_2:'+str(args.sep2)+'$" $PA_2:'+str(args.pa2)+'^\circ$ $D_2$:'+str(args.date2)+' $M_\star:'+str(args.mass)+'M_\odot$ $d:'+str(args.distance)+'pc$\n\n\n' else: R,V,B,phi,pa0,zsgn = cart2rvbphi(args.N1,args.E1,args.N2,args.E2,args,mass,dt,args.distance) titlestr = 'Input parameters\n$N_1:'+str(args.N1)+'$" $E_1:'+str(args.E1)+'$" $D_1$:'+str(args.date1)+' $N_2:'+str(args.N2)+'$" $E_2:'+str(args.E2)+'$" $D_2$:'+str(args.date2)+' $M_\star:'+str(args.mass)+'M_\odot$ $d:'+str(args.distance)+'pc$\n\n\n' print('') print('R =', R, 'au') print('V =', V, 'au / yr') print('B =', B) print('phi =', phi/np.pi*180, 'deg')
def match_wcs(fiss_file,smooth=False,**kwargs): """ Match the wcs information of FISS files with the SDO/HMI file. Parameters ---------- fiss_file : str or list A single of fiss file or the list of fts file. sdo_file : (optional) str A SDO/HMI data to use for matching the wcs. If False, then download the HMI data on the VSO site. dirname : (optional) str The directory name for saving the npz data. If False, the dirname is the present working directory. filename : (optional) str The file name for saving the npz data. There are no need to add the extension. If False, the filename is the date of FISS data. sil : (optional) bool If False, it print the ongoing time index. Default is True. sdo_path : (optional) str The directory name for saving the HMI data. method : (optioinal) bool If True, then manually match the wcs. If False, you have a no choice to this yet. kkk. wvref : (optional) float The referenced wavelength for making raster image. reflect : (optional) bool Correct the reflection of FISS data. Default is True. alpha : (optional) float The transparency of the image to missing : (optional) float The extrapolated value of interpolation. Default is -1. Returns ------- match_angle : float The angle to rotate the FISS data to match the wcs information. wcsx : float The x-axis value of image center in WCS arcesec unit. wcsy : float The y-axis value of image center in WCS arcesec unit. Example ------- >>> from glob import glob >>> from fisspy.image import coalignment >>> file=glob('*_A1_c.fts') >>> dirname='D:\\im\\so\\hot' >>> sdo_path='D:\\im\\sdo\\path' >>> coalignment.match_wcs(file,dirname=dirname,sil=False, sdo_path=sdo_path) """ ref_frame=kwargs.get('ref_frame',len(fiss_file)//2) kwargs['ref_frame']=ref_frame fiss_file0=fiss_file[ref_frame] sdo_file=kwargs.pop('sdo_file',False) sil=kwargs.get('sil',False) sdo_path=kwargs.pop('sdo_path',os.getcwd()) if not sdo_file: h=getheader(fiss_file0) tlist=h['date'] t=Time(tlist,format='isot',scale='ut1') tjd=t.jd t1=tjd-22/24/3600 t2=tjd+22/24/3600 t1=Time(t1,format='jd') t2=Time(t2,format='jd') t1.format='isot' t2.format='isot' hmi=(a.Time(t1.value,t2.value), a.Instrument('HMI'), a.vso.Physobs('intensity')) res=Fido.search(hmi) if not sil: print('Download the SDO/HMI file') sdo_file=Fido.fetch(res,path=os.path.join(sdo_path, '{file}')) sdo_file=sdo_file[0] if not sil: print('SDO/HMI file name is %s'%sdo_file) manual(fiss_file,sdo_file,**kwargs) return
def main(fname, output=False, separator=":", verbose=True): # verbose printing on flag raise v_print = print if verbose else lambda *a, **k: None ############### Observation Settings ospath = os.getcwd() + "/" path = "/".join(fname.split("/")[:-1]) #+ "/" print("Path = {}",path) nod_dates = [] nod_slits = [] nod_exptimes = [] nod_instruments = [] nod_object = [] nod_filter = [] nod_airmass = [] with open(fname, "r") as f: for line in f: #Replace ":"" in list file with "-" if separator != ":": line_parts = line.split(":") line = separator.join(line_parts) fitsname = line[:-1] + ".fits" v_print("The fits file to open is" , fitsname) try: v_print("Trying location = {}".format(path + "../Raw_files/" + fitsname)) header = fits.getheader(path + "../Raw_files/" + fitsname) except: try: v_print("Trying location = {}".format(path + "Raw_files/" + fitsname)) header = fits.getheader(path + "Raw_files/" + fitsname) except: try: header = fits.getheader(path + fitsname) except: v_print("Having issues finding files from list.") raise obsdate = header["DATE-OBS"] nod_dates.append(obsdate) nod_slits.append(header["HIERARCH ESO INS SLIT1 WID"]) nod_exptimes.append(header["EXPTIME"]) nod_instruments.append(header["INSTRUME"]) nod_object.append(header["OBJECT"]) nod_filter.append(header["ESO INS FILT1 NAME"]) # AIRMASS values airmass_start = header["HIERARCH ESO TEL AIRM START"] airmass_end = header["HIERARCH ESO TEL AIRM END"] nod_mean_airmass = round((airmass_start + airmass_end) / 2 , 4) nod_airmass.append(nod_mean_airmass) #ESO TEL AIRM END: 1.204 #ESO TEL AIRM START: 1.214 v_print("Values obtained from the list files") v_print("The nod date-obs = {} ".format(nod_dates)) v_print("The nod Slit Widths = {}".format(nod_slits)) v_print("The nod Exposure times = {} seconds".format(nod_exptimes)) v_print("The listed Instruments = {} ".format(nod_instruments)) if len(set(nod_instruments)) == 1: instrument = nod_instruments[0] else: #raise error as list intruments are not unique raise NodError("Nods in list were not taken on the same instrument") if len(set(nod_exptimes)) == 1: exptime = nod_exptimes[0] else: #raise error as list exptime are not unique raise NodError("Nods in the list do not have same exposure times") if len(set(nod_slits)) == 1: slit_width = nod_slits[0] else: #raise error as list exptime are not unique raise NodError("Nods in list do not have same slit widths") # Get average time of observation (adding exposure time) if len(set(nod_object)) == 1: Object = nod_object[0] else: #raise error as list exptime are not unique raise NodError("Nods in list are not of the Object") if len(set(nod_filter)) == 1: nod_filter = nod_filter[0] else: #raise error as list exptime are not unique raise NodError("Nods in list are not of the Object") jd_days = [] for nod_date in nod_dates: t = Time(nod_date, format="fits") + TimeDelta(exptime/2, format="sec") t.format= 'jd' jd_days.append(t.value) v_print("Nod dates converted into JD {}".format(jd_days)) if max(jd_days)-min(jd_days) > len(jd_days)*2*exptime/86400.: raise NodError("Issue with time for the nod observations took longer " \ "then twice exposure time for each exposure (maybe need to add a lower" \ " limit for quick observations) ") mean_obs_time = np.mean(jd_days) median_obs_time = np.median(jd_days) obs_begin_time = Time(nod_dates[0], format="fits") print(" obs_begin_time", obs_begin_time, "nod_dates[0]", nod_dates[0]) obs_end_time = Time(nod_dates[-1], format="fits") + TimeDelta(exptime, format="sec") mean_obs_t = Time(mean_obs_time, format="jd") mean_obs_t.format = "fits" med_obs_t = Time(median_obs_time, format="jd") med_obs_t.format = "fits" obs_begin_time2 = Time(obs_begin_time) obs_end_time2 = Time(obs_end_time) obs_begin_time2.format = "jd" obs_end_time2.format = "jd" obs_total = obs_end_time2-obs_begin_time2 obs_total_minutes = obs_total * 24*60 Middle_obs = obs_begin_time2 + TimeDelta(60*obs_total_minutes/2, format="sec") Middle_obs.format = "fits" Middle_obs2 = Time(Middle_obs) Middle_obs2.format = "jd" v_print("Mean obs time averged in JD {}".format(mean_obs_time)) v_print("Median obs time in JD {}".format(median_obs_time)) v_print("Begin obs time in JD {}".format(obs_begin_time)) v_print("End obs time in JD {}".format(obs_end_time)) target_ra = header["RA"] # of the last observation in the list target_dec = header["DEC"] obs_wl_min = header["HIERARCH ESO INS WLEN MIN"] obs_wl_max = header["HIERARCH ESO INS WLEN MAX"] # Print header values to find the ones most interested in. ##for key in header: #print(str(key) + ": " + str(header[key])) Obs_name = header["ESO OBS NAME"] Nabcycles = header["ESO SEQ NABCYCLES"] # ESO SEQ NABCYCLES: 4 NEXP = header["ESO TPL NEXP"] # ESO TPL NEXP: 8 # Observation IDs obs_pi_id= header["ESO OBS PI-COI ID"] prosal_id= header["ESO OBS PROG ID"] tpl_id = header["ESO TPL ID"] #CRIRES_spec_obs_AutoNodOnSlit ao_loop_state = header["ESO AOS RTC LOOP STATE"] #Airmass calculation mean_airmass = np.mean(nod_airmass) airmass_range = np.max(nod_airmass)-np.min(nod_airmass) ####### Observatory Settings instrument = header["INSTRUME"] telescope = header["TELESCOP"] if "VLT" in telescope: obs_name = "ESO Paranal Chile (VLT)" else: v_print("Don't have TAPAS telecope location name (Using the Obervation value)") obs_name = telescope obs_long = header["HIERARCH ESO TEL GEOLON"] obs_lat = header["HIERARCH ESO TEL GEOLAT"] obs_alt = header["HIERARCH ESO TEL GEOELEV"] ####### Target Settings ra_angle = Angle(target_ra, u.degree) ra_j2000 = str(ra_angle.to_string(unit=u.hour, sep=':', precision=0, pad=True)) # Extra str to get rid of u"string" which failed in template dec_angle = Angle(target_dec, u.deg) dec_j2000 = str(dec_angle.to_string(unit=u.degree, sep=':', precision=0, pad=True)) # Extra str to get rid of u"string" which failed in template v_print("RA degrees = {0}, RA Angle = {1}, RA for tapas = {2}".format(target_ra, ra_angle, ra_j2000)) v_print("DEC degrees = {0}, DEC Angle = {1}, DEC for tapas = {2}".format(target_dec, dec_angle, dec_j2000)) # Resolving power rule of thumb R = 100000*0.2 / slit_width resolving_power = int(R) print("Resolving Power = {}".format(resolving_power)) if output: output_file = output else: output_file = "key_observation_values.txt" try: with open(output_file, "w") as out: ############################################################ #Put the useful parameters I need to know here out.write("KEY CRIRES OBSERVATION PARAMETERS:\n------------------\n") out.write("Target Name = {}\n".format(Object)) out.write("Observation Name = {}\n".format(Obs_name)) out.write("RA = {}, {} \n".format(ra_angle, ra_j2000)) out.write("DEC = {}, {} \n".format(dec_angle, dec_j2000)) out.write("\nOBS IDs:\n------------------\n") out.write("Proposal ID = {}\n".format(prosal_id)) out.write("PI-COI ID = {}\n".format(obs_pi_id)) out.write("Obs Template ID = {}\n".format(tpl_id)) out.write("AO State(OPEN=noAo) = {}\n".format(ao_loop_state)) out.write("\nDetector Setup:\n------------------\n") out.write("Telescope = {}\n".format(telescope)) out.write("Instrument = {}\n".format(instrument)) out.write("Spec Filter = {}\n".format(nod_filter)) out.write("Min wavelength = {} nm\n".format(obs_wl_min)) out.write("Max Wavelength = {} nm\n".format(obs_wl_max)) out.write("Slit width = {} \n".format(slit_width)) out.write("Resolving Power = {}\n".format(resolving_power)) out.write("Exposure time = {}\n".format(exptime)) out.write("Number AB cycles = {}\n".format(Nabcycles)) out.write("Number of Exposures = {}\n".format(NEXP)) out.write("\nTime Calculations:\n------------------\n") # FITS Format out.write("## FITS format\n") out.write("Obs Start time = {}\n".format(obs_begin_time)) out.write("Average obs time = {}\n".format(mean_obs_t)) out.write("Median obs time = {}\n".format(med_obs_t)) #out.write("Middle of obs = {} \n".format(Middle_obs)) out.write("Obs End time = {}\n".format(obs_end_time)) obs_begin_time.format = "jd" obs_end_time.format = "jd" # JD Format out.write("## JD format\n") out.write("Obs start time (JD) = {}\n".format(obs_begin_time2)) out.write("Average obs time (JD) = {}\n".format(mean_obs_time)) out.write("Medaian obs time (JD) = {}\n".format(median_obs_time)) #out.write("Middle of obs (JD) = {}\n".format(Middle_obs2)) out.write("Obs End time (JD) = {}\n".format(obs_end_time2)) out.write("Total observation time [inc. exptime] (JD) = {} \n".format(obs_total)) out.write("Total observation time [inc. exptime] (min) = {} \n".format(obs_total_minutes)) out.write("Total intergration time [NEXP*exptime] (min) = {} \n".format(exptime*NEXP/60)) out.write("\nAirmass values:\n------------------\n") out.write("Nod airmasses = {}\n".format(nod_airmass)) out.write("Mean airmass valu = {}\n".format(mean_airmass)) out.write("Airmass range [max-min] = {}\n".format(airmass_range)) # DATE CREATED out.write("\n\nThis file was generated on {}\n".format(datetime.datetime.now())) ############################################################# print("Saved Observation information to \t {0}".format(output_file)) except: print("Failed to save Observation information to \t {0}.".format(output_file)) raise
def main(fname="/home/jneal/Phd/data/Crires/BDs-DRACS/HD30501-1/Combined_Nods/CRIRE.2012-04-07T00:08:29.976_1.nod.ms.norm.sum.wavecal.fits", listspectra=False, resolvpower=False, unit="vacuum", instrument_function="gaussian", sampling=10, berv=False, tapas_format="ASCII", constituents="all", output_file=False, request_id=10, wl_min=False, wl_max=False, request_number=None, verbose=False): # verbose printing on flag raise v_print = print if verbose else lambda *a, **k: None # Dotfile for saving requst number for iteration home = os.path.expanduser("~") dot_file = os.path.join(home, ".tapas_request_num") ############### Observation Settings ospath = os.getcwd() + "/" v_print("OS path {}".format(ospath)) path = "/".join(fname.split("/")[:-1]) + "/" v_print("Path obtained from fname = {}".format(path)) if listspectra: nod_dates = [] nod_slits = [] nod_exptimes = [] nod_instruments = [] with open(fname, "r") as f: for line in f: fitsname = line[:-1] + ".fits" v_print("The fits file to open is" ,fitsname) try: v_print("Trying location{}".format(path + "../Raw_files/" + fitsname)) header = fits.getheader(path + "../Raw_files/" + fitsname) except: try: v_print("Trying location = {}".format(path + "Raw_files/" + fitsname)) header = fits.getheader(path + "Raw_files/" + fitsname) except: try: header = fits.getheader(path + fitsname) except: v_print("Having issues finding files from list.") raise obsdate = header["DATE-OBS"] nod_dates.append(obsdate) nod_slits.append(header["HIERARCH ESO INS SLIT1 WID"]) nod_exptimes.append(header["EXPTIME"]) nod_instruments.append(header["INSTRUME"]) v_print("Values obtained from the list files") v_print("The nod date-obs = {} ".format(nod_dates)) v_print("The nod Slit Widths = {}".format( nod_slits)) v_print("The nod Exposure times = {} seconds".format(nod_exptimes)) v_print("The listed Instruments = {} ".format(nod_instruments)) if len(set(nod_instruments)) == 1: instrument = nod_instruments[0] else: #raise error as list intruments are not unique raise NodError("Nods in list were not taken on the same instrument") if len(set(nod_exptimes)) == 1: exptime = nod_exptimes[0] else: #raise error as list exptime are not unique raise NodError("Nods in the list do not have same exposure times") if len(set(nod_slits)) == 1: slit_width = nod_slits[0] else: #raise error as list exptime are not unique raise NodError("Nods in list do not have same slit widths") # Get average time of observation (adding exposure time) jd_days = [] for nod_date in nod_dates: t = Time(nod_date, format="fits") + TimeDelta(exptime/2, format="sec") t.format= 'jd' jd_days.append(t.value) v_print("Nod dates converted into JD {}".format(jd_days)) if max(jd_days)-min(jd_days) > len(jd_days)*2*exptime/86400.: raise NodError("Issue with time for the nod observations took longer then twice exposure time for each exposure (maybe need to add a lower limit for quick observations) ") mean_obs_time = np.mean(jd_days) v_print("Mean obs time averged in JD {}".format(mean_obs_time)) v_print("Median obs time in JD {}".format(np.median(jd_days))) date = Time(mean_obs_time, format="jd") date.format = "fits" # Turn back into fits format date = date.value[:-5] + "Z" # Going from Time object back to string and adding Z to end for Tapas target_ra = header["RA"] # of the last observation in the list target_dec = header["DEC"] obs_wl_min = header["HIERARCH ESO INS WLEN MIN"] obs_wl_max = header["HIERARCH ESO INS WLEN MAX"] else: header = fits.getheader(fname) date = header["DATE-OBS"][:-1]+"Z" target_ra = header["RA"] target_dec = header["DEC"] obs_wl_min = header["HIERARCH ESO INS WLEN MIN"] obs_wl_max = header["HIERARCH ESO INS WLEN MAX"] slit_width = header["HIERARCH ESO INS SLIT1 WID"] ####### Observatory Settings instrument = header["INSTRUME"] telescope = header["TELESCOP"] if "VLT" in telescope: obs_name = "ESO Paranal Chile (VLT)" else: v_print("Don't have TAPAS telecope location name (Using the Obervation value)") obs_name = telescope obs_long = header["HIERARCH ESO TEL GEOLON"] obs_lat = header["HIERARCH ESO TEL GEOLAT"] obs_alt = header["HIERARCH ESO TEL GEOELEV"] ####### Target Settings ra_angle = Angle(target_ra, u.degree) ra_j2000 = str(ra_angle.to_string(unit=u.hour, sep=':', precision=0, pad=True)) # Extra str to get rid of u"string" which failed in template dec_angle = Angle(target_dec, u.deg) dec_j2000 = str(dec_angle.to_string(unit=u.degree, sep=':', precision=0, pad=True)) # Extra str to get rid of u"string" which failed in template v_print("RA degrees = {0}, RA Angle = {1}, RA for tapas = {2}".format(target_ra, ra_angle, ra_j2000)) v_print("DEC degrees = {0}, DEC Angle = {1}, DEC for tapas = {2}".format(target_dec, dec_angle, dec_j2000)) if wl_min: spec_range_min = int(wl_min) else: spec_range_min = int(obs_wl_min - 10) if wl_max: spec_range_max = int(wl_max) else: spec_range_max = int(obs_wl_max + 10) # Check for TAPAS consistency #Tapas wavelength range is from 350 to 2500 nm in vacuum. if spec_range_min < 350: v_print("Lower wavelength bound of {} was below tapas minimum. Setting to tapas minimum of 350 nm".format(spec_range_min)) spec_range_min = 350 elif spec_range_min > 2500: v_print("Wavelength Lower bound of {} is above Tapas maximum wavelength of 2500 nm. Check your wavelength units".format(spec_range_min)) raise("Wavelength bounds Error") if spec_range_max > 2500: v_print("Upper wavelength bound of {} was above tapas maximum. Setting to tapas maximum of 2500 nm".format(spec_range_max)) spec_range_max = 2500 elif spec_range_max < 350: v_print("Wavelength Upper bound of {} is below Tapas minimum wavelength of 350 nm. Check your wavelength units".format(spec_range_max)) raise("Wavelength bounds Error") ########### Tapas Specifications if tapas_format in ["ascii","fits","vetcdf","vo"]: tapas_format = tapas_format.upper() else: v_print("TAPAS format was not correct, using default of ASCII") tapas_format = "ASCII" # open save file, find request id, add 1 # get request number from previous xml file if not given. if not request_number: # Load previous tapas request number try: with open(dot_file, "r") as req: old_number = req.readline().split("=")[1] v_print("Previous request_number = {}".format(old_number)) request_number = int(old_number) + 1 v_print("New request_number number = {}".format(request_number)) except: request_number = 0 print("Could not read request number from previous request in {0}. The default value of {1} will need to be manually changed when submitting the request.".format(dot_file, request_number)) else: # Manually given request number v_print("Manually given request number={0} will be used.\n".format(request_number)) ##### Specify Species in tapas spectra #Could possibly make this a binary AND operation if constituents == "all": species_map = [1,1,1,1,1,1,1] species_id = 10 elif constituents == "ray": species_map = [1,0,0,0,0,0,0] species_id = 11 elif constituents == "h2o": species_map = [0,1,0,0,0,0,0] species_id = 12 elif constituents == "o3": species_map = [0,0,1,0,0,0,0] species_id = 13 elif constituents == "o2": species_map = [0,0,0,1,0,0,0] species_id = 14 elif constituents == "co2": species_map = [0,0,0,0,1,0,0] species_id = 15 elif constituents == "ch4": species_map = [0,0,0,0,0,1,0] species_id = 16 elif constituents == "n2o": species_map = [0,0,0,0,0,0,1] species_id = 17 elif constituents == "not_h2o": species_map = [1,0,1,1,1,1,1] species_id = 18 else: species_id = 9999 raise SpeciesError("Choice of constituents was not in valid range.") # Request id baised on the species present unless manually specified if request_id: Request_ID = request_id else: Request_ID = species_id if species_map[0]: ray = "YES" else: ray = "NO" if species_map[1]: h20 = "YES" # alternate yes no for h20 for scaling else: h20 = "NO" # alternate yes no for h20 for scaling if species_map[2]: o2 = "YES" else: o2 = "NO" if species_map[3]: o3 = "YES" else: o3 = "NO" if species_map[4]: co2 = "YES" else: co2 = "NO" if species_map[5]: ch4 = "YES" else: ch4 = "NO" if species_map[6]: n2o = "YES" else: n2o = "NO" if "air" in unit.lower(): spectral_choice = "Standard Wavelength (nm)" if "vac" in unit.lower(): spectral_choice = "Vacuum Wavelength (nm)" if "wave" in unit.lower(): spectral_choice = "Wavenumber (cm-1)" instrument_function = instrument_function.lower() if "none" in instrument_function: ilsf_choice = -1 # -1, 0, 1 elif "gaussian" in instrument_function: ilsf_choice = 1 # -1, 0, 1 else: v_print("Instrument function not specifid correctly\n Valid choices are none or gaussian, The default is gaussian.") sampling_ratio = sampling # defualt 10 if resolvpower: resolving_power = int(resolvpower) v_print("Resolving power manually specified at {}".format(resolving_power)) else: if "CRIRES" in instrument: v_print("Resolving Power\nUsing the rule of thumb equation from the CRIRES manual. \nWarning! The use of adpative optics is not checked for!!") R = 100000*0.2 / slit_width resolving_power = int(R) v_print("Slit width was {0} inches.\nTherefore the resolving_power is set = {1}".format(slit_width, resolving_power)) #TO DO Specify other instruments in here? else: v_print("Resolving power not defined") if berv: apply_berv = "YES" else: apply_berv = "NO" ###### Atmosphere Parameters # hours(date[11:13]) only seem to work if multiple of 06 hours #assuming 00 is for 00->06 hours hour = int(date[11:13]) if hour >= 0 and hour < 6: hour_out = "00" elif hour >= 6 and hour < 12: hour_out = "06" elif hour >= 12 and hour < 18: hour_out = "12" elif hour >= 18 and hour < 24: hour_out = "18" else: raise HourError("Error with the arletty timing. The request will fail") file_date = date[0:4] + date[5:7] + date[8:10] + hour_out arletty_file = "canr_" + file_date + ".arl" ecmwf_file = "canr_" + file_date + "_qo3.txt" v_print("arletty_file", arletty_file) v_print("ecmwf_file", ecmwf_file) d = {"request_number":request_number, "Request_ID":Request_ID, "tapas_format":tapas_format, "ray":ray, "h20":h20, "o3":o3, "o2":o2, "co2":co2, "ch4":ch4, "n2o":n2o, "date":date, "obs_name":obs_name, "obs_long":obs_long, "obs_lat":obs_lat, "obs_alt":obs_alt, "ra_j2000":ra_j2000, "dec_j2000":dec_j2000, "spectral_choice":spectral_choice, "spec_range_min":spec_range_min, "spec_range_max":spec_range_max, "ilsf_choice":ilsf_choice, "resolving_power":resolving_power, "sampling_ratio":sampling_ratio, "apply_berv":apply_berv, "arletty_file":arletty_file, "ecmwf_file":ecmwf_file} template = """<?xml version="1.0" encoding="UTF-8"?> <tapas Id="Ether_TAPAS_$request_number"> <request Id="$Request_ID"> <preferences> <format valid="VO,ASCII,FITS,NETCDF">$tapas_format</format> <rayleigh_extinction valid="YES,NO">$ray</rayleigh_extinction> <h2o_extinction valid="YES,NO">$h20</h2o_extinction> <o3_extinction valid="YES,NO">$o3</o3_extinction> <o2_extinction valid="YES,NO">$o2</o2_extinction> <co2_extinction valid="YES,NO">$co2</co2_extinction> <ch4_extinction valid="YES,NO">$ch4</ch4_extinction> <n2o_extinction valid="YES,NO">$n2o</n2o_extinction> </preferences> <observation> <date>$date</date> <observatory> <name>$obs_name</name> <longitude min="-180" max="180">$obs_long</longitude> <latitude min="-90" max="90">$obs_lat</latitude> <altitude min="0" max="10000">$obs_alt</altitude> </observatory> <los> <ra_j2000>$ra_j2000</ra_j2000> <dec_j2000>$dec_j2000</dec_j2000> </los> <instrument> <spectral_choice valid="Vacuum Wavelength (nm),Standard Wavelength (nm),Wavenumber (cm-1)">$spectral_choice</spectral_choice> <spectral_range>$spec_range_min $spec_range_max</spectral_range> <ilsf_choice valid="-1,0,1">$ilsf_choice</ilsf_choice> <resolving_power min="0">$resolving_power</resolving_power> <sampling_ratio min="0">$sampling_ratio</sampling_ratio> <appli_berv valid="YES,NO">$apply_berv</appli_berv> </instrument> </observation> <atmosphere> <reference valid="0,1,2,3,4,5,6">0</reference> <arletty_file>/data/tapas///arletty/$arletty_file</arletty_file> <ecmwf_file>/data/tapas///ecmwf/$ecmwf_file</ecmwf_file> </atmosphere> </request> </tapas> """ # ECMWF = ARLETTY #[{"text":"ECMWF","value":0},{"text":"TROPICAL","value":1},{"text":"MEDIUM_LATITUDE_SUMMER","value":2},{"text":"MEDIUM_LATITUDE_WINTER","value":3},{"text":"SUBARCTIC_SUMMER","value":4},{"text":"SUBARCTIC_WINTER","value":5},{"text":"US_STANDARD_1976","value":6}] #######################TODO - Missing all in one transmission #tapasTexts["NM_STANDARD"] = "Standard Wavelength (nm)"; # tapasTexts["NM_VACUUM"] = "Vacuum Wavelength (nm)"; # tapasTexts["CM"] = "Wavenumber (cm-1)"; # # tapasTexts["NONE"] = "None"; # tapasTexts["GAUSSIAN"] = "Gaussian"; # tapasTexts["ECMWF"] = "ARLETTY"; # tapasTexts["TROPICAL"] = "Tropical"; # tapasTexts["MEDIUM_LATITUDE_SUMMER"] = "Average latitude summer"; # tapasTexts["MEDIUM_LATITUDE_WINTER"] = "Average latitude winter"; # tapasTexts["SUBARCTIC_SUMMER"] = "Subarctic summer"; # tapasTexts["SUBARCTIC_WINTER"] = "Subarctic winter"; # tapasTexts["US_STANDARD_1976"] = "Standard US 1976"; from string import Template s = Template(template) v_print("Xml Template object = {}".format(s)) sub = s.substitute(d) #print(sub) # Save xml ouptut for copying to tapas #TO TRY in future - submit straight to tapas #output_file = "/home/jneal/Phd/Codes/UsefulModules/Tapas_xml_request_file.xml" if not output_file: output_file = "tapas_request_{}.xml".format(request_number) else: # Add request number split = output_file.split(".") if len(split) == 2: output_file = split[0] + "_{}.".format(request_number) + split[1] else: print("Warning output filename may not be the expected format 'some_name.xml'") print("Split output file", split) try: with open(output_file, "w") as out: out.write(sub) print("Saved tapas xml request to \t {0}".format(output_file)) except: print("Failed to save xml request to \t {0}. \nHere is a printed version.".format(output_file)) print("\n{}\n".format(sub)) try: with open(dot_file, "w") as req: req.write("request_number = {0}".format(request_number)) v_print("Stored current request number {0} in {1} for later iteration".format(request_number, dot_file)) except: v_print("Failed to store request number {0} in {1} .".format(request_number, dot_file))