def test_sdf(self): """Test building a SDF from a tarball.""" sdf = metabundle.get_sdf(mdbFile)
def main(args): # Set the site site = None if args.lwa1: site = 'lwa1' elif args.lwasv: site = 'lwasv' # Open the file and file good data (not raw DRX data) fh = open(args.filename, 'rb') try: for i in xrange(5): junkFrame = drx.read_frame(fh) raise RuntimeError("ERROR: '%s' appears to be a raw DRX file, not a DR spectrometer file" % args.filename) except errors.SyncError: fh.seek(0) # Interrogate the file to figure out what frames sizes to expect, now many # frames there are, and what the transform length is FRAME_SIZE = drspec.get_frame_size(fh) nFrames = os.path.getsize(args.filename) // FRAME_SIZE nChunks = nFrames LFFT = drspec.get_transform_size(fh) # Read in the first frame to figure out the DP information junkFrame = drspec.read_frame(fh) fh.seek(-FRAME_SIZE, 1) srate = junkFrame.sample_rate t0 = junkFrame.time tInt = junkFrame.header.nints*LFFT/srate # Offset in frames for beampols beam/tuning/pol. sets offset = int(round(args.skip / tInt)) fh.seek(offset*FRAME_SIZE, 1) # Iterate on the offsets until we reach the right point in the file. This # is needed to deal with files that start with only one tuning and/or a # different sample rate. while True: ## Figure out where in the file we are and what the current tuning/sample ## rate is junkFrame = drspec.read_frame(fh) srate = junkFrame.sample_rate t1 = junkFrame.time tInt = junkFrame.header.nints*LFFT/srate fh.seek(-FRAME_SIZE, 1) ## See how far off the current frame is from the target tDiff = t1 - (t0 + args.skip) ## Half that to come up with a new seek parameter tCorr = -tDiff / 2.0 cOffset = int(round(tCorr / tInt)) offset += cOffset ## If the offset is zero, we are done. Otherwise, apply the offset ## and check the location in the file again/ if cOffset is 0: break fh.seek(cOffset*FRAME_SIZE, 1) # Update the offset actually used args.skip = t1 - t0 nChunks = (os.path.getsize(args.filename) - fh.tell()) // FRAME_SIZE # Update the file contents beam = junkFrame.id central_freq1, central_freq2 = junkFrame.central_freq srate = junkFrame.sample_rate data_products = junkFrame.data_products t0 = junkFrame.time tInt = junkFrame.header.nints*LFFT/srate beginDate = junkFrame.time.datetime # Report print("Filename: %s" % args.filename) if args.metadata is not None: print("Metadata: %s" % args.metadata) elif args.sdf is not None: print("SDF: %s" % args.sdf) print("Date of First Frame: %s" % beginDate) print("Beam: %i" % beam) print("Sample Rate: %i Hz" % srate) print("Tuning Frequency: %.3f Hz (1); %.3f Hz (2)" % (central_freq1, central_freq2)) print("Data Products: %s" % ','.join(data_products)) print("Frames: %i (%.3f s)" % (nFrames, nFrames*tInt)) print("---") print("Offset: %.3f s (%i frames)" % (args.skip, offset)) print("Transform Length: %i" % LFFT) print("Integration: %.3f s" % tInt) # Setup the output file outname = os.path.split(args.filename)[1] outname = os.path.splitext(outname)[0] outname = '%s-waterfall.hdf5' % outname if os.path.exists(outname): if not args.force: yn = raw_input("WARNING: '%s' exists, overwrite? [Y/n] " % outname) else: yn = 'y' if yn not in ('n', 'N'): os.unlink(outname) else: raise RuntimeError("Output file '%s' already exists" % outname) f = hdfData.create_new_file(outname) obsList = {} if args.metadata is not None: try: project = metabundle.get_sdf(args.metadata) except Exception as e: if adpReady: project = metabundleADP.get_sdf(args.metadata) else: raise e sdfBeam = project.sessions[0].drx_beam spcSetup = project.sessions[0].spcSetup if sdfBeam != beam: raise RuntimeError("Metadata is for beam #%i, but data is from beam #%i" % (sdfBeam, beam)) for i,obs in enumerate(project.sessions[0].observations): sdfStart = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm) sdfStop = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm + obs.dur) obsChunks = int(numpy.ceil(obs.dur/1000.0 * drx.FILTER_CODES[obs.filter] / (spcSetup[0]*spcSetup[1]))) obsList[i+1] = (sdfStart, sdfStop, obsChunks) hdfData.fill_from_metabundle(f, args.metadata) elif args.sdf is not None: try: project = sdf.parse_sdf(args.sdf) except Exception as e: if adpReady: project = sdfADP.parse_sdf(args.sdf) else: raise e sdfBeam = project.sessions[0].drx_beam spcSetup = project.sessions[0].spcSetup if sdfBeam != beam: raise RuntimeError("Metadata is for beam #%i, but data is from beam #%i" % (sdfBeam, beam)) for i,obs in enumerate(project.sessions[0].observations): sdfStart = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm) sdfStop = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm + obs.dur) obsChunks = int(numpy.ceil(obs.dur/1000.0 * drx.FILTER_CODES[obs.filter] / (spcSetup[0]*spcSetup[1]))) obsList[i+1] = (sdfStart, sdfStop, obsChunks) hdfData.fill_from_sdf(f, args.sdf, station=site) else: obsList[1] = (beginDate, datetime(2222,12,31,23,59,59), nChunks) hdfData.fill_minimum(f, 1, beam, srate, station=site) data_products = junkFrame.data_products for o in sorted(obsList.keys()): for t in (1,2): hdfData.create_observation_set(f, o, t, numpy.arange(LFFT, dtype=numpy.float64), obsList[o][2], data_products) f.attrs['FileGenerator'] = 'drspec2hdf.py' f.attrs['InputData'] = os.path.basename(args.filename) # Create the various HDF group holders ds = {} for o in sorted(obsList.keys()): obs = hdfData.get_observation_set(f, o) ds['obs%i' % o] = obs ds['obs%i-time' % o] = hdfData.get_time(f, o) for t in (1,2): ds['obs%i-freq%i' % (o, t)] = hdfData.get_data_set(f, o, t, 'freq') for p in data_products: ds["obs%i-%s%i" % (o, p, t)] = hdfData.get_data_set(f, o, t, p) ds['obs%i-Saturation%i' % (o, t)] = hdfData.get_data_set(f, o, t, 'Saturation') # Loop over DR spectrometer frames to fill in the HDF5 file pbar = progress.ProgressBar(max=nChunks) o = 1 j = 0 firstPass = True for i in xrange(nChunks): frame = drspec.read_frame(fh) cTime = frame.time.datetime if cTime > obsList[o][1]: # Increment to the next observation o += 1 # If we have reached the end, exit... try: obsList[o] firstPass = True except KeyError: sys.stdout.write('%s\r' % (' '*pbar.span)) sys.stdout.flush() print("End of observing block according to SDF, exiting") break if cTime < obsList[o][0]: # Skip over data that occurs before the start of the observation continue try: if frame.time > oTime + 1.001*tInt: print('Warning: Time tag error at frame %i; %.3f > %.3f + %.3f' % (i, frame.time, oTime, tInt)) except NameError: pass oTime = frame.time if firstPass: # Otherwise, continue on... central_freq1, central_freq2 = frame.central_freq srate = frame.sample_rate tInt = frame.header.nints*LFFT/srate freq = numpy.fft.fftshift( numpy.fft.fftfreq(LFFT, d=1.0/srate) ) freq = freq.astype(numpy.float64) sys.stdout.write('%s\r' % (' '*pbar.span)) sys.stdout.flush() print("Switching to Obs. #%i" % o) print("-> Tunings: %.1f Hz, %.1f Hz" % (central_freq1, central_freq2)) print("-> Sample Rate: %.1f Hz" % srate) print("-> Integration Time: %.3f s" % tInt) sys.stdout.write(pbar.show()+'\r') sys.stdout.flush() j = 0 ds['obs%i-freq1' % o][:] = freq + central_freq1 ds['obs%i-freq2' % o][:] = freq + central_freq2 obs = ds['obs%i' % o] obs.attrs['tInt'] = tInt obs.attrs['tInt_Units'] = 's' obs.attrs['LFFT'] = LFFT obs.attrs['nChan'] = LFFT obs.attrs['RBW'] = freq[1]-freq[0] obs.attrs['RBW_Units'] = 'Hz' firstPass = False # Load the data from the spectrometer frame into the HDF5 group ds['obs%i-time' % o][j] = (frame.time[0], frame.time[1]) ds['obs%i-Saturation1' % o][j,:] = frame.payload.saturations[0:2] ds['obs%i-Saturation2' % o][j,:] = frame.payload.saturations[2:4] for t in (1,2): for p in data_products: ds['obs%i-%s%i' % (o, p, t)][j,:] = getattr(frame.payload, "%s%i" % (p, t-1), None) j += 1 # Update the progress bar pbar.inc() if i % 10 == 0: sys.stdout.write(pbar.show()+'\r') sys.stdout.flush() sys.stdout.write(pbar.show()+'\n') sys.stdout.flush() # Done fh.close() # Save the output to a HDF5 file f.close()
def main(args): # Get the site and observer site = stations.lwa1 observer = site.get_observer() # Filenames in an easier format inputTGZ = args.filename # Parse the input file and get the dates of the observations. Be default # this is for LWA1 but we switch over to LWA-SV if an error occurs. try: # LWA1 project = metabundle.get_sdf(inputTGZ) obsImpl = metabundle.get_observation_spec(inputTGZ) fileInfo = metabundle.get_session_metadata(inputTGZ) aspConfigB = metabundle.get_asp_configuration_summary( inputTGZ, which='Beginning') aspConfigE = metabundle.get_asp_configuration_summary(inputTGZ, which='End') except: # LWA-SV ## Site changes site = stations.lwasv observer = site.get_observer() ## Try again project = metabundleADP.get_sdf(inputTGZ) obsImpl = metabundleADP.get_observation_spec(inputTGZ) fileInfo = metabundleADP.get_session_metadata(inputTGZ) aspConfigB = metabundleADP.get_asp_configuration_summary( inputTGZ, which='Beginning') aspConfigE = metabundleADP.get_asp_configuration_summary(inputTGZ, which='End') nObs = len(project.sessions[0].observations) tStart = [ None, ] * nObs for i in range(nObs): tStart[i] = utcjd_to_unix(project.sessions[0].observations[i].mjd + MJD_OFFSET) tStart[i] += project.sessions[0].observations[i].mpm / 1000.0 tStart[i] = datetime.utcfromtimestamp(tStart[i]) tStart[i] = _UTC.localize(tStart[i]) # Get the LST at the start observer.date = (min(tStart)).strftime('%Y/%m/%d %H:%M:%S') lst = observer.sidereal_time() # Report on the file print("Filename: %s" % inputTGZ) print(" Project ID: %s" % project.id) print(" Session ID: %i" % project.sessions[0].id) print(" Observations appear to start at %s" % (min(tStart)).strftime(_FORMAT_STRING)) print(" -> LST at %s for this date/time is %s" % (site.name, lst)) lastDur = project.sessions[0].observations[nObs - 1].dur lastDur = timedelta(seconds=int(lastDur / 1000), microseconds=(lastDur * 1000) % 1000000) sessionDur = max(tStart) - min(tStart) + lastDur print(" ") print(" Total Session Duration: %s" % sessionDur) print(" -> First observation starts at %s" % min(tStart).strftime(_FORMAT_STRING)) print(" -> Last observation ends at %s" % (max(tStart) + lastDur).strftime(_FORMAT_STRING)) if project.sessions[0].observations[0].mode not in ('TBW', 'TBN'): drspec = 'No' if project.sessions[0].spcSetup[0] != 0 and project.sessions[ 0].spcSetup[1] != 0: drspec = 'Yes' drxBeam = project.sessions[0].drx_beam if drxBeam < 1: drxBeam = "MCS decides" else: drxBeam = "%i" % drxBeam print(" DRX Beam: %s" % drxBeam) print(" DR Spectrometer used? %s" % drspec) if drspec == 'Yes': print(" -> %i channels, %i windows/integration" % tuple(project.sessions[0].spcSetup)) else: tbnCount = 0 tbwCount = 0 for obs in project.sessions[0].observations: if obs.mode == 'TBW': tbwCount += 1 else: tbnCount += 1 if tbwCount > 0 and tbnCount == 0: print(" Transient Buffer Mode: TBW") elif tbwCount == 0 and tbnCount > 0: print(" Transient Buffer Mode: TBN") else: print(" Transient Buffer Mode: both TBW and TBN") print(" ") print("File Information:") for obsID in fileInfo.keys(): print(" Obs. #%i: %s" % (obsID, fileInfo[obsID]['tag'])) print(" ") print("ASP Configuration:") print(' Beginning') for k, v in aspConfigB.items(): print(' %s: %i' % (k, v)) print(' End') for k, v in aspConfigE.items(): print(' %s: %i' % (k, v)) print(" ") print(" Number of observations: %i" % nObs) print(" Observation Detail:") for i in range(nObs): currDur = project.sessions[0].observations[i].dur currDur = timedelta(seconds=int(currDur / 1000), microseconds=(currDur * 1000) % 1000000) print(" Observation #%i" % (i + 1, )) currObs = None for j in range(len(obsImpl)): if obsImpl[j]['obsID'] == i + 1: currObs = obsImpl[j] break ## Basic setup print(" Target: %s" % project.sessions[0].observations[i].target) print(" Mode: %s" % project.sessions[0].observations[i].mode) print(" Start:") print(" MJD: %i" % project.sessions[0].observations[i].mjd) print(" MPM: %i" % project.sessions[0].observations[i].mpm) print(" -> %s" % get_observation_start_stop( project.sessions[0].observations[i])[0].strftime(_FORMAT_STRING)) print(" Duration: %s" % currDur) ## DP setup if project.sessions[0].observations[i].mode not in ('TBW', ): print(" Tuning 1: %.3f MHz" % (project.sessions[0].observations[i].frequency1 / 1e6, )) if project.sessions[0].observations[i].mode not in ('TBW', 'TBN'): print(" Tuning 2: %.3f MHz" % (project.sessions[0].observations[i].frequency2 / 1e6, )) if project.sessions[0].observations[i].mode not in ('TBW', ): print(" Filter code: %i" % project.sessions[0].observations[i].filter) if currObs is not None: if project.sessions[0].observations[i].mode not in ('TBW', ): if project.sessions[0].observations[i].mode == 'TBN': print(" Gain setting: %i" % currObs['tbnGain']) else: print(" Gain setting: %i" % currObs['drxGain']) else: print( " WARNING: observation specification not found for this observation" ) ## Comments/notes print(" Observer Comments: %s" % project.sessions[0].observations[i].comments)
def main(args): # Parse the command line filenames = args.filename # Check if the first argument on the command line is a directory. If so, # use what is in that directory if os.path.isdir(filenames[0]): filenames = [ os.path.join(filenames[0], filename) for filename in os.listdir(filenames[0]) ] filenames.sort() # Convert the filenames to absolute paths filenames = [os.path.abspath(filename) for filename in filenames] # Open the database connection to NRAO to find the antenna locations try: db = database('params') except Exception as e: sys.stderr.write("WARNING: %s" % str(e)) sys.stderr.flush() db = None # Pass 1 - Get the LWA metadata so we know where we are pointed context = { 'observer': 'Unknown', 'project': 'Unknown', 'session': None, 'vlaref': None } setup = None sources = [] metadata = {} lwasite = {} for filename in filenames: # Figure out what to do with the file ext = os.path.splitext(filename)[1] if ext == '.tgz': ## LWA Metadata try: ## Extract the SDF if len(sources) == 0: try: sdf = metabundle.get_sdf(filename) except Exception as e: sdf = metabundleADP.get_sdf(filename) context['observer'] = sdf.observer.name context['project'] = sdf.id context['session'] = sdf.sessions[0].id comments = sdf.project_office.sessions[0] mtch = CORR_CHANNELS.search(comments) if mtch is not None: corr_channels = int(mtch.group('channels'), 10) else: corr_channels = None mtch = CORR_INTTIME.search(comments) if mtch is not None: corr_inttime = float(mtch.group('inttime')) else: corr_inttime = None mtch = CORR_BASIS.search(comments) if mtch is not None: corr_basis = mtch.group('basis') else: sys.stderr.write( "WARNING: No output correlation polarization basis defined, assuming 'linear'.\n" ) corr_basis = 'linear' if corr_channels is not None and corr_inttime is not None: setup = { 'channels': corr_channels, 'inttime': corr_inttime, 'basis': corr_basis } else: sys.stderr.write( "WARNING: No or incomplete correlation configuration defined, setting to be defined at correlation time.\n" ) for o, obs in enumerate(sdf.sessions[0].observations): if type(obs).__name__ == 'Solar': name = 'Sun' intent = 'target' ra = None dec = None elif type(obs).__name__ == 'Jovian': name = 'Jupiter' intent = 'target' ra = None dec = None else: name = obs.target intent = obs.name ra = ephem.hours(str(obs.ra)) dec = ephem.degrees(str(obs.dec)) tStart = mjdmpm_to_datetime(obs.mjd, obs.mpm) tStop = mjdmpm_to_datetime(obs.mjd, obs.mpm + obs.dur) sources.append({ 'name': name, 'intent': intent, 'ra2000': ra, 'dec2000': dec, 'start': tStart, 'stop': tStop }) ### Alternate phase centers comments = sdf.project_office.observations[0][o] alts = {} for mtch in ALT_TARGET.finditer(comments): alt_id = int(mtch.group('id'), 10) alt_name = mtch.group('target') try: alts[alt_id]['name'] = alt_name except KeyError: alts[alt_id] = { 'name': alt_name, 'intent': 'dummy', 'ra': None, 'dec': None } for mtch in ALT_INTENT.finditer(comments): alt_id = int(mtch.group('id'), 10) alt_intent = mtch.group('intent') try: alts[alt_id]['intent'] = alt_intent except KeyError: alts[alt_id] = { 'name': None, 'intent': alt_intent, 'ra': None, 'dec': None } for mtch in ALT_RA.finditer(comments): alt_id = int(mtch.group('id'), 10) alt_ra = ephem.hours(mtch.group('ra')) try: alts[alt_id]['ra'] = alt_ra except KeyError: alts[alt_id] = { 'name': None, 'intent': 'dummy', 'ra': alt_ra, 'dec': None } for mtch in ALT_DEC.finditer(comments): alt_id = int(mtch.group('id'), 10) alt_dec = ephem.degrees(mtch.group('dec')) try: alts[alt_id]['dec'] = alt_dec except KeyError: alts[alt_id] = { 'name': None, 'intent': 'dummy', 'ra': None, 'dec': alt_dec } for alt_id in sorted(alts.keys()): alt_name, alt_ra, alt_dec = alts[alt_id] if alt_name is None or alt_ra is None or alt_dec is None: sys.stderr.write( "WARNING: Incomplete alternate phase center %i, skipping.\n" % alt_id) else: sources.append({ 'name': alt_name, 'ra2000': alt_ra, 'dec2000': alt_dec, 'start': tStart, 'stop': tStop }) ## Extract the file information so that we can pair things together fileInfo = metabundle.get_session_metadata(filename) for obsID in fileInfo.keys(): metadata[fileInfo[obsID]['tag']] = filename ## Figure out LWA1 vs LWA-SV try: cs = metabundle.get_command_script(filename) for c in cs: if c['subsystem_id'] == 'DP': site = 'LWA1' break elif c['subsystem_id'] == 'ADP': site = 'LWA-SV' break except (RuntimeError, ValueError): site = 'LWA-SV' for obsID in fileInfo.keys(): lwasite[fileInfo[obsID]['tag']] = site except Exception as e: sys.stderr.write("ERROR reading metadata file: %s\n" % str(e)) sys.stderr.flush() # Setup what we need to write out a configuration file corrConfig = { 'context': context, 'setup': setup, 'source': { 'name': '', 'ra2000': '', 'dec2000': '' }, 'inputs': [] } metadata = {} for filename in filenames: #print("%s:" % os.path.basename(filename)) # Skip over empty files if os.path.getsize(filename) == 0: continue # Open the file fh = open(filename, 'rb') # Figure out what to do with the file ext = os.path.splitext(filename)[1] if ext == '': ## DRX try: ## Get the site try: sitename = lwasite[os.path.basename(filename)] except KeyError: sitename = 'LWA1' ## Get the location so that we can set site-specific parameters if sitename == 'LWA1': xyz = LWA1_ECEF off = args.lwa1_offset elif sitename == 'LWA-SV': xyz = LWASV_ECEF off = args.lwasv_offset else: raise RuntimeError("Unknown LWA site '%s'" % site) ## Move into the LWA1 coordinate system ### ECEF to LWA1 rho = xyz - LWA1_ECEF sez = numpy.dot(LWA1_ROT, rho) enz = sez[[1, 0, 2]] # pylint: disable=invalid-sequence-index enz[1] *= -1 ## Read in the first few frames to get the start time frames = [drx.read_frame(fh) for i in xrange(1024)] streams = [] freq1, freq2 = 0.0, 0.0 for frame in frames: beam, tune, pol = frame.id if tune == 1: freq1 = frame.central_freq else: freq2 = frame.central_freq if (beam, tune, pol) not in streams: streams.append((beam, tune, pol)) tStart = frames[0].time.datetime tStartAlt = (frames[-1].time - 1023 // len(streams) * 4096 / frames[-1].sample_rate).datetime tStartDiff = tStart - tStartAlt if abs(tStartDiff) > timedelta(microseconds=10000): sys.stderr.write( "WARNING: Stale data found at the start of '%s', ignoring\n" % os.path.basename(filename)) sys.stderr.flush() tStart = tStartAlt ### ^ Adjustment to the start time to deal with occasional problems ### with stale data in the DR buffers at LWA-SV ## Read in the last few frames to find the end time fh.seek(os.path.getsize(filename) - 1024 * drx.FRAME_SIZE) backed = 0 while backed < 2 * drx.FRAME_SIZE: try: drx.read_frame(fh) fh.seek(-drx.FRAME_SIZE, 1) break except errors.SyncError: backed += 1 fh.seek(-drx.FRAME_SIZE - 1, 1) for i in xrange(32): try: frame = drx.read_frame(fh) beam, tune, _ = frame.id if tune == 1: freq1 = frame.central_freq else: freq2 = frame.central_freq except errors.SyncError: continue tStop = frame.time.datetime ## Save corrConfig['inputs'].append({ 'file': filename, 'type': 'DRX', 'antenna': sitename, 'pols': 'X, Y', 'location': (enz[0], enz[1], enz[2]), 'clockoffset': (off, off), 'fileoffset': 0, 'beam': beam, 'tstart': tStart, 'tstop': tStop, 'freq': (freq1, freq2) }) except Exception as e: sys.stderr.write("ERROR reading DRX file: %s\n" % str(e)) sys.stderr.flush() elif ext == '.vdif': ## VDIF try: ## Read in the GUPPI header header = vdif.read_guppi_header(fh) ## Read in the first frame vdif.FRAME_SIZE = vdif.get_frame_size(fh) frame = vdif.read_frame(fh) antID = frame.id[0] - 12300 tStart = frame.time.datetime nThread = vdif.get_thread_count(fh) ## Read in the last frame nJump = int(os.path.getsize(filename) / vdif.FRAME_SIZE) nJump -= 30 fh.seek(nJump * vdif.FRAME_SIZE, 1) mark = fh.tell() while True: try: frame = vdif.read_frame(fh) tStop = frame.time.datetime except Exception as e: break ## Find the antenna location pad, edate = db.get_pad('EA%02i' % antID, tStart) x, y, z = db.get_xyz(pad, tStart) #print(" Pad: %s" % pad) #print(" VLA relative XYZ: %.3f, %.3f, %.3f" % (x,y,z)) ## Move into the LWA1 coordinate system ### relative to ECEF xyz = numpy.array([x, y, z]) xyz += VLA_ECEF ### ECEF to LWA1 rho = xyz - LWA1_ECEF sez = numpy.dot(LWA1_ROT, rho) enz = sez[[1, 0, 2]] # pylint: disable=invalid-sequence-index enz[1] *= -1 ## Set an apparent position if WiDAR is already applying a delay model apparent_enz = (None, None, None) if args.no_vla_delay_model: apparent_xyz = VLA_ECEF apparent_rho = apparent_xyz - LWA1_ECEF apparent_sez = numpy.dot(LWA1_ROT, apparent_rho) apparent_enz = apparent_sez[[1, 0, 2]] # pylint: disable=invalid-sequence-index apparent_enz[1] *= -1 ## VLA time offset off = args.vla_offset ## Save corrConfig['context']['observer'] = header['OBSERVER'] try: corrConfig['context']['project'] = header[ 'BASENAME'].split('_')[0] corrConfig['context']['session'] = header[ 'BASENAME'].split('_')[1].replace('sb', '') except IndexError: corrConfig['context']['project'] = header[ 'BASENAME'].split('.')[0] corrConfig['context']['session'] = header[ 'BASENAME'].split('.')[1].replace('sb', '') corrConfig['context']['vlaref'] = re.sub( '\.[0-9]+\.[0-9]+\.[AB][CD]-.*', '', header['BASENAME']) corrConfig['source']['name'] = header['SRC_NAME'] corrConfig['source']['intent'] = 'target' corrConfig['source']['ra2000'] = header['RA_STR'] corrConfig['source']['dec2000'] = header['DEC_STR'] corrConfig['inputs'].append({ 'file': filename, 'type': 'VDIF', 'antenna': 'EA%02i' % antID, 'pols': 'Y, X', 'location': (enz[0], enz[1], enz[2]), 'apparent_location': (apparent_enz[0], apparent_enz[1], apparent_enz[2]), 'clockoffset': (off, off), 'fileoffset': 0, 'pad': pad, 'tstart': tStart, 'tstop': tStop, 'freq': header['OBSFREQ'] }) except Exception as e: sys.stderr.write("ERROR reading VDIF file: %s\n" % str(e)) sys.stderr.flush() elif ext == '.tgz': ## LWA Metadata try: ## Extract the file information so that we can pair things together fileInfo = metabundle.get_session_metadata(filename) for obsID in fileInfo.keys(): metadata[fileInfo[obsID]['tag']] = filename except Exception as e: sys.stderr.write("ERROR reading metadata file: %s\n" % str(e)) sys.stderr.flush() # Done fh.close() # Close out the connection to NRAO try: db.close() except AttributeError: pass # Choose a VDIF reference file, if there is one, and mark whether or # not DRX files were found vdifRefFile = None isDRX = False for cinp in corrConfig['inputs']: if cinp['type'] == 'VDIF': if vdifRefFile is None: vdifRefFile = cinp elif cinp['type'] == 'DRX': isDRX = True # Set a state variable so that we can generate a warning about missing # DRX files drxFound = False # Purge DRX files that don't make sense toPurge = [] drxFound = False lwasvFound = False for cinp in corrConfig['inputs']: ### Sort out multiple DRX files - this only works if we have only one LWA station if cinp['type'] == 'DRX': if vdifRefFile is not None: l0, l1 = cinp['tstart'], cinp['tstop'] v0, v1 = vdifRefFile['tstart'], vdifRefFile['tstop'] ve = (v1 - v0).total_seconds() overlapWithVDIF = (v0 >= l0 and v0 < l1) or (l0 >= v0 and l0 < v1) lvo = (min([v1, l1]) - max([v0, l0])).total_seconds() if not overlapWithVDIF or lvo < 0.25 * ve: toPurge.append(cinp) drxFound = True if cinp['antenna'] == 'LWA-SV': lwasvFound = True for cinp in toPurge: del corrConfig['inputs'][corrConfig['inputs'].index(cinp)] # Sort the inputs based on the antenna name - this puts LWA1 first, # LWA-SV second, and the VLA at the end in 'EA' antenna order, i.e., # EA01, EA02, etc. corrConfig['inputs'].sort(key=lambda x: 0 if x['antenna'] == 'LWA1' else ( 1 if x['antenna'] == 'LWA-SV' else int(x['antenna'][2:], 10))) # VDIF/DRX warning check/report if vdifRefFile is not None and isDRX and not drxFound: sys.stderr.write( "WARNING: DRX files provided but none overlapped with VDIF data") # Duplicate antenna check antCounts = {} for cinp in corrConfig['inputs']: try: antCounts[cinp['antenna']] += 1 except KeyError: antCounts[cinp['antenna']] = 1 for ant in antCounts.keys(): if antCounts[ant] != 1: sys.stderr.write("WARNING: Antenna '%s' is defined %i times" % (ant, antCounts[ant])) # Update the file offsets to get things lined up better tMax = max([cinp['tstart'] for cinp in corrConfig['inputs']]) for cinp in corrConfig['inputs']: diff = tMax - cinp['tstart'] offset = diff.days * 86400 + diff.seconds + diff.microseconds / 1e6 cinp['fileoffset'] = max([0, offset]) # Reconcile the source lists for when we have eLWA data. This is needed so # that we use the source information contained in the VDIF files rather than # the stub information contained in the SDFs if len(sources) <= 1: if corrConfig['source']['name'] != '': ## Update the source information with what comes from the VLA try: sources[0] = corrConfig['source'] except IndexError: sources.append(corrConfig['source']) # Update the dwell time using the minimum on-source time for all inputs if # there is only one source, i.e., for full eLWA runs if len(sources) == 1: sources[0]['start'] = max( [cinp['tstart'] for cinp in corrConfig['inputs']]) sources[0]['stop'] = min( [cinp['tstop'] for cinp in corrConfig['inputs']]) # Render the configuration startRef = sources[0]['start'] s = 0 for source in sources: startOffset = source['start'] - startRef startOffset = startOffset.total_seconds() dur = source['stop'] - source['start'] dur = dur.total_seconds() ## Skip over dummy scans and scans that start after the files end if source['intent'] in (None, 'dummy'): continue if source['start'] > max( [cinp['tstop'] for cinp in corrConfig['inputs']]): print( "Skipping scan of %s which starts at %s, %.3f s after the data end" % (source['name'], source['start'], (source['start'] - max([cinp['tstop'] for cinp in corrConfig['inputs']])).total_seconds())) continue ## Small correction for the first scan to compensate for stale data at LWA-SV if lwasvFound and s == 0: startOffset += 10.0 dur -= 10.0 ## Skip over scans that are too short if dur < args.minimum_scan_length: continue ## Setup if args.output is None: fh = sys.stdout else: outname = args.output if len(sources) > 1: outname += str(s + 1) fh = open(outname, 'w') try: repo = git.Repo(os.path.dirname(os.path.abspath(__file__))) try: branch = repo.active_branch.name hexsha = repo.active_branch.commit.hexsha except TypeError: branch = '<detached>' hexsha = repo.head.commit.hexsha shortsha = hexsha[-7:] dirty = ' (dirty)' if repo.is_dirty() else '' except git.exc.GitError: branch = 'unknown' hexsha = 'unknown' shortsha = 'unknown' dirty = '' ## Preamble fh.write("# Created\n") fh.write("# on %s\n" % datetime.now()) fh.write("# using %s, revision %s.%s%s\n" % (os.path.basename(__file__), branch, shortsha, dirty)) fh.write("\n") ## Observation context fh.write("Context\n") fh.write(" Observer %s\n" % corrConfig['context']['observer']) fh.write(" Project %s\n" % corrConfig['context']['project']) if corrConfig['context']['session'] is not None: fh.write(" Session %s\n" % corrConfig['context']['session']) if corrConfig['context']['vlaref'] is not None: fh.write(" VLARef %s\n" % corrConfig['context']['vlaref']) fh.write("EndContext\n") fh.write("\n") ## Configuration, if present if corrConfig['setup'] is not None: fh.write("Configuration\n") fh.write(" Channels %i\n" % corrConfig['setup']['channels']) fh.write(" IntTime %.3f\n" % corrConfig['setup']['inttime']) fh.write(" PolBasis %s\n" % corrConfig['setup']['basis']) fh.write("EndConfiguration\n") fh.write("\n") ## Source fh.write("Source\n") fh.write("# Observation start is %s\n" % source['start']) fh.write("# Duration is %s\n" % (source['stop'] - source['start'], )) fh.write(" Name %s\n" % source['name']) fh.write(" Intent %s\n" % source['intent'].lower()) if source['name'] not in ('Sun', 'Jupiter'): fh.write(" RA2000 %s\n" % source['ra2000']) fh.write(" Dec2000 %s\n" % source['dec2000']) fh.write(" Duration %.3f\n" % dur) fh.write("SourceDone\n") fh.write("\n") ## Input files for cinp in corrConfig['inputs']: fh.write("Input\n") fh.write("# Start time is %s\n" % cinp['tstart']) fh.write("# Stop time is %s\n" % cinp['tstop']) try: fh.write("# Beam is %i\n" % cinp['beam']) except KeyError: pass try: fh.write("# VLA pad is %s\n" % cinp['pad']) except KeyError: pass try: fh.write("# Frequency tuning 1 is %.3f Hz\n" % cinp['freq'][0]) fh.write("# Frequency tuning 2 is %.3f Hz\n" % cinp['freq'][1]) except TypeError: fh.write("# Frequency tuning is %.3f Hz\n" % cinp['freq']) fh.write(" File %s\n" % cinp['file']) try: metaname = metadata[os.path.basename(cinp['file'])] fh.write(" MetaData %s\n" % metaname) except KeyError: if cinp['type'] == 'DRX': sys.stderr.write( "WARNING: No metadata found for '%s', source %i\n" % (os.path.basename(cinp['file']), s + 1)) sys.stderr.flush() pass fh.write(" Type %s\n" % cinp['type']) fh.write(" Antenna %s\n" % cinp['antenna']) fh.write(" Pols %s\n" % cinp['pols']) fh.write(" Location %.6f, %.6f, %.6f\n" % cinp['location']) try: if cinp['apparent_location'][0] is not None: fh.write(" ApparentLocation %.6f, %.6f, %.6f\n" % cinp['apparent_location']) except KeyError: pass fh.write(" ClockOffset %s, %s\n" % cinp['clockoffset']) fh.write(" FileOffset %.3f\n" % (startOffset + cinp['fileoffset'], )) fh.write("InputDone\n") fh.write("\n") if fh != sys.stdout: fh.close() # Increment the source/file counter s += 1
def main(args): # Length of the FFT and the window to use LFFT = args.fft_length if args.bartlett: window = numpy.bartlett elif args.blackman: window = numpy.blackman elif args.hanning: window = numpy.hanning else: window = fxc.null_window args.window = window # Open the file and find good data idf = LWA1DataFile(args.filename, ignore_timetag_errors=args.ignore_time_errors) # Metadata nFramesFile = idf.get_info('nframe') srate = idf.get_info('sample_rate') antpols = idf.get_info('nantenna') # Number of frames to integrate over nFramesAvg = int(args.average * srate / 512) * antpols nFramesAvg = int(1.0 * (nFramesAvg // antpols) * 512 / float(LFFT)) * LFFT / 512 * antpols args.average = 1.0 * (nFramesAvg // antpols) * 512 / srate maxFrames = nFramesAvg # Offset into the file, if needed offset = idf.offset(args.skip) # Number of remaining chunks (and the correction to the number of # frames to read in). if args.metadata is not None: args.duration = 0 if args.duration == 0: args.duration = 1.0 * nFramesFile / antpols * 512 / srate args.duration -= args.skip else: args.duration = int( round(args.duration * srate * antpols / 512) // antpols * 512 // srate) nChunks = int(round(args.duration / args.average)) if nChunks == 0: nChunks = 1 nFrames = nFramesAvg * nChunks # Date & Central Frequency t1 = idf.get_info('start_time') beginDate = t1.datetime central_freq1 = idf.get_info('freq1') # File summary print("Filename: %s" % args.filename) print("Date of First Frame: %s" % str(beginDate)) print("Antenna/Pols: %i" % antpols) print("Sample Rate: %i Hz" % srate) print("Tuning Frequency: %.3f Hz" % (central_freq1, )) print("Frames: %i (%.3f s)" % (nFramesFile, 1.0 * nFramesFile / antpols * 512 / srate)) print("---") print("Offset: %.3f s (%i frames)" % (args.skip, offset)) print("Integration: %.3f s (%i frames; %i frames per antenna/pol)" % (args.average, nFramesAvg, nFramesAvg // antpols)) print("Duration: %.3f s (%i frames; %i frames per antenna/pol)" % (args.average * nChunks, nFrames, nFrames // antpols)) print("Chunks: %i" % nChunks) print(" ") # Estimate clip level (if needed) if args.estimate_clip_level: estimate = idf.estimate_levels(sigma=5.0) clip1 = 1.0 * sum(estimate) / len(estimate) else: clip1 = args.clip_level # Get the antennas for Stokes calculation if args.metadata is not None: try: project = metabundle.get_sdf(args.metadata) station = stations.lwa1 except Exception as e: project = metabundleADP.get_sdf(args.metadata) station = stations.lwasv elif args.lwasv: station = stations.lwasv else: station = stations.lwa1 antennas = station.antennas # Setup the output file outname = os.path.split(args.filename)[1] outname = os.path.splitext(outname)[0] outname = '%s-tbn-waterfall.hdf5' % outname if os.path.exists(outname): if not args.force: yn = raw_input("WARNING: '%s' exists, overwrite? [Y/n] " % outname) else: yn = 'y' if yn not in ('n', 'N'): os.unlink(outname) else: raise RuntimeError("Output file '%s' already exists" % outname) f = hdfData.create_new_file(outname) # Look at the metadata and come up with a list of observations. If # there are no metadata, create a single "observation" that covers the # whole file. obsList = {} if args.metadata is not None: try: project = metabundle.get_sdf(args.metadata) except Exception as e: project = metabundleADP.get_sdf(args.metadata) sdfBeam = project.sessions[0].drx_beam if sdfBeam != 5: raise RuntimeError( "Metadata is for beam #%i, but data is from beam #%i" % (sdfBeam, 5)) for i, obs in enumerate(project.sessions[0].observations): sdfStart = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm) sdfStop = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm + obs.dur) obsDur = obs.dur / 1000.0 obsSR = tbn.FILTER_CODES[obs.filter] obsList[i + 1] = (sdfStart, sdfStop, obsDur, obsSR) print("Observations:") for i in sorted(obsList.keys()): obs = obsList[i] print(" #%i: %s to %s (%.3f s) at %.3f MHz" % (i, obs[0], obs[1], obs[2], obs[3] / 1e6)) print(" ") hdfData.fill_from_metabundle(f, args.metadata) elif args.sdf is not None: try: project = sdf.parse_sdf(args.sdf) except Exception as e: project = sdfADP.parse_sdf(args.sdf) sdfBeam = project.sessions[0].drx_beam if sdfBeam != 5: raise RuntimeError( "Metadata is for beam #%i, but data is from beam #%i" % (sdfBeam, 5)) for i, obs in enumerate(project.sessions[0].observations): sdfStart = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm) sdfStop = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm + obs.dur) obsDur = obs.dur / 1000.0 obsSR = tbn.FILTER_CODES[obs.filter] obsList[i + 1] = (sdfStart, sdfStop, obsDur, obsSR) site = 'lwa1' if args.lwasv: site = 'lwasv' hdfData.fill_from_sdf(f, args.sdf, station=site) else: obsList[1] = (datetime.utcfromtimestamp(t1), datetime(2222, 12, 31, 23, 59, 59), args.duration, srate) site = 'lwa1' if args.lwasv: site = 'lwasv' hdfData.fill_minimum(f, 1, 5, srate, station=site) if (not args.stokes): data_products = ['XX', 'YY'] else: data_products = ['I', 'Q', 'U', 'V'] for o in sorted(obsList.keys()): for t in range(len(antennas) // 2): hdfData.create_observation_set( f, o, t + 1, numpy.arange(LFFT, dtype=numpy.float64), int(round(obsList[o][2] / args.average)), data_products) f.attrs['FileGenerator'] = 'tbnWaterfall.py' f.attrs['InputData'] = os.path.basename(args.filename) # Create the various HDF group holders ds = {} for o in sorted(obsList.keys()): obs = hdfData.get_observation_set(f, o) ds['obs%i' % o] = obs ds['obs%i-time' % o] = hdfData.get_time(f, o) for t in range(len(antennas) // 2): ds['obs%i-freq%i' % (o, t + 1)] = hdfData.get_data_set( f, o, t + 1, 'freq') for p in data_products: ds["obs%i-%s%i" % (o, p, t + 1)] = hdfData.get_data_set( f, o, t + 1, p) ds['obs%i-Saturation%i' % (o, t + 1)] = hdfData.get_data_set( f, o, t + 1, 'Saturation') # Load in the correct analysis function if (not args.stokes): process_data = process_data_to_linear else: process_data = process_data_to_stokes # Go! for o in sorted(obsList.keys()): try: process_data(idf, antennas, obsList[o][0], obsList[o][2], obsList[o][3], args, ds, obsID=o, clip1=clip1) except RuntimeError as e: print("Observation #%i: %s, abandoning this observation" % (o, str(e))) # Save the output to a HDF5 file f.close() # Close out the data file idf.close()
def main(args): # Get the file names meta = args.metadata data = args.filename # Get all observations and their start times try: ## LWA-1 sdf = metabundle.get_sdf(meta) ses = metabundle.get_session_spec(meta) obs = metabundle.get_observation_spec(meta) except: ## LWA-SV ### Try again sdf = metabundleADP.get_sdf(meta) ses = metabundleADP.get_session_spec(meta) obs = metabundleADP.get_observation_spec(meta) obs.sort(_obs_comp) tStart = [] oDetails = [] for i,o in enumerate(obs): tStart.append( mjdmpm_to_datetime(o['mjd'], o['mpm']) ) oDetails.append( {'m': o['mode'], 'd': o['dur'] / 1000.0, 'f': o['bw'], 'p': o['project_id'], 's': o['session_id'], 'o': o['obs_id'], 't': sdf.sessions[0].observations[o['obs_id']-1].target} ) print("Observation #%i" % (o['obs_id'])) print(" Start: %i, %i -> %s" % (o['mjd'], o['mpm'], tStart[-1])) print(" Mode: %s" % mode_to_string(o['mode'])) print(" BW: %i" % o['bw']) print(" Target: %s" % sdf.sessions[0].observations[o['obs_id']-1].target) print(" ") # Figure out where in the file the various bits are. fh = open(data, 'rb') lf = drx.read_frame(fh) beam, j, k = lf.id if beam != obs[0]['drx_beam']: print('ERROR: Beam mis-match, metadata is for #%i, file is for #%i' % (obs[0]['drx_beam'], beam)) sys.exit() firstFrame = lf.time.datetime if abs(firstFrame - min(tStart)) > timedelta(seconds=30): print('ERROR: Time mis-match, metadata is for %s, file is for %s' % (min(tStart), firstFrame)) sys.exit() fh.seek(0) for i in range(len(tStart)): eof = False ## Get observation properties oStart = tStart[i] oMode = mode_to_string(oDetails[i]['m']) oDur = oDetails[i]['d'] oBW = oDetails[i]['f'] print("Seeking %s observation of %.3f seconds at %s" % (oMode, oDur, oStart)) ## Get the correct reader to use if oMode == 'TBW': reader = tbw bwKey = None bwMult = 520.0 / 400 fCount = 400 elif oMode == 'TBN': reader = tbn bwKey = tbn.FILTER_CODES bwMult = 520.0 / 512 fCount = 512 else: reader = drx bwKey = drx.FILTER_CODES bwMult = 4.0 / 4096 fCount = 4096 ## Jump ahead to where the next frame should be, if needed if i != 0: pDur = oDetails[i-1]['d'] pBW = oDetails[i-1]['f'] nFramesSkip = int(pDur*bwKey[pBW]*bwMult) fh.seek(nFramesSkip*reader.FRAME_SIZE, 1) if fh.tell() >= os.path.getsize(data): fh.seek(-10*reader.FRAME_SIZE, 2) ## Figure out where we are and make sure we line up on a frame ## NOTE: This should never be needed fail = True while fail: try: frame = reader.read_frame(fh) fail = False except errors.SyncError: fh.seek(1, 1) except errors.EOFError: break fh.seek(-reader.FRAME_SIZE, 1) ## Go in search of the start of the observation if frame.time.datetime < oStart: ### We aren't at the beginning yet, seek fowards print("-> At byte %i, time is %s < %s" % (fh.tell(), frame.time.datetime, oStart)) while frame.time.datetime < oStart: try: frame = reader.read_frame(fh) except errors.SyncError: fh.seek(1, 1) except errors.EOFError: break #print(frame.time.datetime, oStart) elif frame.time.datetime > oStart: ### We've gone too far, seek backwards print("-> At byte %i, time is %s > %s" % (fh.tell(), frame.time.datetime, oStart)) while frame.time.datetime > oStart: if fh.tell() == 0: break fh.seek(-2*reader.FRAME_SIZE, 1) try: frame = reader.read_frame(fh) except errors.SyncError: fh.seek(-1, 1) except errors.EOFError: break #print(frame.time.datetime, oStart) else: ### We're there already print("-> At byte %i, time is %s = %s" % (fh.tell(), frame.time.datetime, oStart)) ## Jump back exactly one frame so that the filehandle is in a position ## to read the first frame that is part of the observation try: frame = reader.read_frame(fh) print("-> At byte %i, time is %s = %s" % (fh.tell(), frame.time.datetime, oStart)) fh.seek(-reader.FRAME_SIZE, 1) except errors.EOFError: pass ## Update the bytes ranges if fh.tell() < os.path.getsize(data): oDetails[i]['b'] = fh.tell() oDetails[i]['e'] = -1 else: oDetails[i]['b'] = -1 oDetails[i]['e'] = -1 if i != 0: oDetails[i-1]['e'] = fh.tell() ## Progress report if oDetails[i]['b'] >= 0: print('-> Obs.', oDetails[i]['o'], 'starts at byte', oDetails[i]['b']) else: print('-> Obs.', oDetails[i]['o'], 'starts after the end of the file') print(" ") # Report for i in range(len(tStart)): if oDetails[i]['b'] < 0: print("%s, Session %i, Observation %i: not found" % (oDetails[i]['p'], oDetails[i]['s'], oDetails[i]['o'])) else: print("%s, Session %i, Observation %i: %i to %i (%i bytes)" % (oDetails[i]['p'], oDetails[i]['s'], oDetails[i]['o'], oDetails[i]['b'], oDetails[i]['e'], (oDetails[i]['e'] - oDetails[i]['b']))) print(" ") # Split if not args.list: for i in range(len(tStart)): if oDetails[i]['b'] < 0: continue ## Report print("Working on Observation %i" % (i+1,)) ## Create the output name if args.source: outname = '%s_%i_%s.dat' % (oDetails[i]['p'], oDetails[i]['s'], oDetails[i]['t'].replace(' ', '').replace('/','').replace('&','and')) else: outname = '%s_%i_%i.dat' % (oDetails[i]['p'], oDetails[i]['s'], oDetails[i]['o']) oMode = mode_to_string(oDetails[i]['m']) ## Get the correct reader to use if oMode == 'TBW': reader = tbw elif oMode == 'TBN': reader = tbn else: reader = drx ## Get the number of frames if oDetails[i]['e'] > 0: nFramesRead = (oDetails[i]['e'] - oDetails[i]['b']) // reader.FRAME_SIZE else: nFramesRead = (os.path.getsize(data) - oDetails[i]['b']) // reader.FRAME_SIZE ## Split if os.path.exists(outname): if not args.force: yn = input("WARNING: '%s' exists, overwrite? [Y/n] " % outname) else: yn = 'y' if yn not in ('n', 'N'): os.unlink(outname) else: print("WARNING: output file '%s' already exists, skipping" % outname) continue fh.seek(oDetails[i]['b']) t0 = time.time() oh = open(outname, 'wb') for sl in [2**i for i in range(17)[::-1]]: while nFramesRead >= sl: temp = fh.read(sl*reader.FRAME_SIZE) oh.write(temp) nFramesRead -= sl oh.close() t1 = time.time() print(" Copied %i bytes in %.3f s (%.3f MB/s)" % (os.path.getsize(outname), t1-t0, os.path.getsize(outname)/1024.0**2/(t1-t0))) print(" ")
def main(args): # Length of the FFT and the window to use LFFT = args.fft_length if args.bartlett: window = numpy.bartlett elif args.blackman: window = numpy.blackman elif args.hanning: window = numpy.hanning else: window = fxc.null_window args.window = window # Open the file and find good data (not spectrometer data) fh = open(args.filename, "rb") try: for i in xrange(5): junkFrame = drspec.read_frame(fh) raise RuntimeError( "ERROR: '%s' appears to be a DR spectrometer file, not a raw DRX file" % args.filename) except errors.SyncError: fh.seek(0) # Good, we seem to have a real DRX file, switch over to the LDP interface fh.close() idf = LWA1DataFile(args.filename, ignore_timetag_errors=args.ignore_time_errors) # Metadata nFramesFile = idf.get_info('nframe') beam = idf.get_info('beam') srate = idf.get_info('sample_rate') beampols = idf.get_info('nbeampol') beams = max([1, beampols // 4]) # Number of frames to integrate over nFramesAvg = int(args.average * srate / 4096) * beampols nFramesAvg = int(1.0 * (nFramesAvg // beampols) * 4096 / float(LFFT)) * LFFT / 4096 * beampols args.average = 1.0 * (nFramesAvg // beampols) * 4096 / srate maxFrames = nFramesAvg # Offset into the file, if needed offset = idf.offset(args.skip) # Number of remaining chunks (and the correction to the number of # frames to read in). if args.metadata is not None: args.duration = 0 if args.duration == 0: args.duration = 1.0 * nFramesFile / beampols * 4096 / srate args.duration -= args.skip else: args.duration = int( round(args.duration * srate * beampols / 4096) / beampols * 4096 / srate) nChunks = int(round(args.duration / args.average)) if nChunks == 0: nChunks = 1 nFrames = nFramesAvg * nChunks # Date & Central Frequency t1 = idf.get_info('start_time') beginDate = t1.datetime central_freq1 = idf.get_info('freq1') central_freq2 = idf.get_info('freq2') # File summary print("Filename: %s" % args.filename) print("Date of First Frame: %s" % str(beginDate)) print("Beams: %i" % beams) print("Tune/Pols: %i" % beampols) print("Sample Rate: %i Hz" % srate) print("Tuning Frequency: %.3f Hz (1); %.3f Hz (2)" % (central_freq1, central_freq2)) print("Frames: %i (%.3f s)" % (nFramesFile, 1.0 * nFramesFile / beampols * 4096 / srate)) print("---") print("Offset: %.3f s (%i frames)" % (args.skip, offset)) print("Integration: %.3f s (%i frames; %i frames per beam/tune/pol)" % (args.average, nFramesAvg, nFramesAvg / beampols)) print("Duration: %.3f s (%i frames; %i frames per beam/tune/pol)" % (args.average * nChunks, nFrames, nFrames / beampols)) print("Chunks: %i" % nChunks) print(" ") # Estimate clip level (if needed) if args.estimate_clip_level: estimate = idf.estimate_levels(fh, sigma=5.0) clip1 = (estimate[0] + estimate[1]) / 2.0 clip2 = (estimate[2] + estimate[3]) / 2.0 else: clip1 = args.clip_level clip2 = args.clip_level # Make the pseudo-antennas for Stokes calculation antennas = [] for i in xrange(4): if i // 2 == 0: newAnt = stations.Antenna(1) else: newAnt = stations.Antenna(2) if i % 2 == 0: newAnt.pol = 0 else: newAnt.pol = 1 antennas.append(newAnt) # Setup the output file outname = os.path.split(args.filename)[1] outname = os.path.splitext(outname)[0] outname = '%s-waterfall.hdf5' % outname if os.path.exists(outname): if not args.force: yn = raw_input("WARNING: '%s' exists, overwrite? [Y/n] " % outname) else: yn = 'y' if yn not in ('n', 'N'): os.unlink(outname) else: raise RuntimeError("Output file '%s' already exists" % outname) f = hdfData.create_new_file(outname) # Look at the metadata and come up with a list of observations. If # there are no metadata, create a single "observation" that covers the # whole file. obsList = {} if args.metadata is not None: try: project = metabundle.get_sdf(args.metadata) except Exception as e: project = metabundleADP.get_sdf(args.metadata) sdfBeam = project.sessions[0].drx_beam spcSetup = project.sessions[0].spcSetup if sdfBeam != beam: raise RuntimeError( "Metadata is for beam #%i, but data is from beam #%i" % (sdfBeam, beam)) for i, obs in enumerate(project.sessions[0].observations): sdfStart = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm) sdfStop = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm + obs.dur) obsDur = obs.dur / 1000.0 obsSR = drx.FILTER_CODES[obs.filter] obsList[i + 1] = (sdfStart, sdfStop, obsDur, obsSR) print("Observations:") for i in sorted(obsList.keys()): obs = obsList[i] print(" #%i: %s to %s (%.3f s) at %.3f MHz" % (i, obs[0], obs[1], obs[2], obs[3] / 1e6)) print(" ") hdfData.fill_from_metabundle(f, args.metadata) elif args.sdf is not None: try: project = sdf.parse_sdf(args.sdf) except Exception as e: project = sdfADP.parse_sdf(args.sdf) sdfBeam = project.sessions[0].drx_beam spcSetup = project.sessions[0].spcSetup if sdfBeam != beam: raise RuntimeError( "Metadata is for beam #%i, but data is from beam #%i" % (sdfBeam, beam)) for i, obs in enumerate(project.sessions[0].observations): sdfStart = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm) sdfStop = mcs.mjdmpm_to_datetime(obs.mjd, obs.mpm + obs.dur) obsDur = obs.dur / 1000.0 obsSR = drx.FILTER_CODES[obs.filter] obsList[i + 1] = (sdfStart, sdfStop, obsDur, obsSR) site = 'lwa1' if args.lwasv: site = 'lwasv' hdfData.fill_from_sdf(f, args.sdf, station=site) else: obsList[1] = (datetime.utcfromtimestamp(t1), datetime(2222, 12, 31, 23, 59, 59), args.duration, srate) site = 'lwa1' if args.lwasv: site = 'lwasv' hdfData.fill_minimum(f, 1, beam, srate, station=site) if (not args.stokes): data_products = ['XX', 'YY'] else: data_products = ['I', 'Q', 'U', 'V'] for o in sorted(obsList.keys()): for t in (1, 2): hdfData.create_observation_set( f, o, t, numpy.arange(LFFT, dtype=numpy.float64), int(round(obsList[o][2] / args.average)), data_products) f.attrs['FileGenerator'] = 'hdfWaterfall.py' f.attrs['InputData'] = os.path.basename(args.filename) # Create the various HDF group holders ds = {} for o in sorted(obsList.keys()): obs = hdfData.get_observation_set(f, o) ds['obs%i' % o] = obs ds['obs%i-time' % o] = hdfData.get_time(f, o) for t in (1, 2): ds['obs%i-freq%i' % (o, t)] = hdfData.get_data_set(f, o, t, 'freq') for p in data_products: ds["obs%i-%s%i" % (o, p, t)] = hdfData.get_data_set(f, o, t, p) ds['obs%i-Saturation%i' % (o, t)] = hdfData.get_data_set( f, o, t, 'Saturation') # Load in the correct analysis function if (not args.stokes): processDataBatch = processDataBatchLinear else: processDataBatch = processDataBatchStokes # Go! for o in sorted(obsList.keys()): try: processDataBatch(idf, antennas, obsList[o][0], obsList[o][2], obsList[o][3], args, ds, obsID=o, clip1=clip1, clip2=clip2) except RuntimeError as e: print("Observation #%i: %s, abandoning this observation" % (o, str(e))) # Save the output to a HDF5 file f.close() # Close out the data file idf.close()