📄 seedreader.java
字号:
package org.trinet.jasi.seed;
import java.io.*;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.util.*;
import java.lang.*;
import java.math.*;
import org.trinet.jasi.*;
import org.trinet.jdbc.*;
import org.trinet.util.Bits;
import org.trinet.util.DateTime;
import org.trinet.util.TimeSpan;
import org.trinet.util.EpochTime;
import org.trinet.util.BenchMark;
import org.trinet.util.WaveClient;
// Changed to use Fissure decoder to get Steim2
// see: http://www.seis.sc.edu/software/Fissures/seed.html
import edu.iris.Fissures.seed.codec.Steim1;
import edu.iris.Fissures.seed.codec.Steim2;
/**
* SeedReader. Read seed files and interpret them. All methods in the class are
* static because we want only one instance of the RemoteFileReader. The class will
* determine if Waveform files are local or remote at instantiation time.
* If remote, the class reads from the data source using DbBlobReader which gets
* timeseries using a stored procedure in the dbase. <p>
*
* This class also knows how to read the waveforms from various data sources.
* See the various getDataXxxxxx() methods.
*/
/*
1/15/02 Integrated AWW's DbBlobReader
*/
public class SeedReader {
/* double Precision problems!
0.01 * 300 = 3.0
0.01 * 301 = 3.0100000000000002
0.01 * 302 = 3.02
0.01 * 303 = 3.0300000000000002
0.01 * 304 = 3.04
0.01 * 305 = 3.0500000000000003
*/
protected static CallableStatement csStmt;
// SEED header
static SeedHeader header;
// Header fields
/*
static int sequenceNumber;
static String stationName;
static String locationName;
static String componentName;
static String networkName;
static String headerType;
static double startTime; // converted to local epoch
static int sampleCount; // count of samples in the Seed packet
static double samplesPerSecond;
static double sampleMultiplier;
static byte activityFlag;
static byte ioFlag;
static byte qualityFlag;
static int headerTimeCorrection;
static private int blockettesFollowing;
static int dataOffset; //byte offset to start of data, counting from byte 0
static int blocketteOffset; //start of 1st blockette, counting from byte 0
// Blockette 1000
static int encodingFormat; // from blockette 1000
static int wordOrder; //0=VAX/Intel, 1=SUN/Motorola
static int dataRecordLength;
*/
// Data encoding formats described in SEED v2.3, see SEED Ref. Man. pg. 106
// ONLY STEIM1 IS CURRENTLY SUPPORTED
// public static final byte STEIM1 = 10;
// public static final byte STEIM2 = 11;
// public static final byte GEOSCOPE24 = 12;
// public static final byte GEOSCOPE16_3 = 13;
// public static final byte GEOSCOPE16_4 = 14;
// public static final byte USNSN = 15;
// public static final byte CDSN = 16;
// public static final byte GRAEFENBERG = 17;
// public static final byte IGP = 18;
// Blockette 1001
static int timeQuality;
static int timeCorrection;
static int reserved;
static int framesInRecord;
// reuseable variable to reduce instantiations in methods :. speed up
static int map[] = new int[16]; // 0 - 15; // map of compression mask
// static float pt[]; // ref. to decompressed samples
static int imap = -1;
static int firstValue;
static int lastValue;
static final int FrameSize = 64; // in bytes
/** Bytes per read */
final static int READBUFFERSIZE = 16384;
/** bytes per Seed packet work area, equal to maximum Seed packet size we can handle */
final static int DEFAULTSEEDBLOCKSIZE = 8192; // bytes per Seed packet
// move this to file scope?
static byte[] buff = new byte[DEFAULTSEEDBLOCKSIZE];
static int seedBlockSize; // may be set otherwise someday
static TimeSpan fileSpan = new TimeSpan(); // earliest & latest times in file
static Waveform wf;
static WFSegment wfseg = new WFSegment();
// Make the FTP reader, make one at instantiation time so the connection
// will remain open rather then getting garbage collected.
// static RemoteFileReader remoteReader = new RemoteFileReader();
// static RemoteFileReader remoteReader = null;
static DbBlobReader dbBlobReader = null;
static boolean accessKnown = false; // is local/remote known?
/**
* JDBConn must already be established.
*/
public SeedReader ()
{
}
/** Decompresses MiniSEED packets. Returns float[] of time-series samples if
* packet header indicates a data packet, else returns null.
*
* @exception java.lang.SeedReaderException input null, input packet <512 bytes, or i/o
* error parsing packet data. */
public static float [] getDataSamples(byte [] seedPacket) throws SeedReaderException {
float [] samples = null;
try {
if (seedPacket == null)
throw new NullPointerException("SeedReader.getDataSamples(byte[]) Null input parameter");
if (seedPacket.length < 512)
throw new IllegalArgumentException("SeedReader.getDataSamples(byte[]) Input byte array length:"
+ seedPacket.length + " is too short for known packet sizes");
WFSegment wfSegment = createWFSegment(seedPacket);
header = getHeader();
if (header.isData() ) { // decompress only data messages
samples = decompress (header, seedPacket);
}
}
catch (NullPointerException ex) {
throw new SeedReaderException(ex.getMessage());
}
catch (IllegalArgumentException ex) {
throw new SeedReaderException(ex.getMessage());
}
catch (Exception ex) {
ex.printStackTrace();
throw new SeedReaderException("getDataSamples(): " + ex.getMessage());
}
return samples;
}
/** Decodes a Collection containing miniSEED time-series data packets as elements.
* Returns a Collection of jasi.WFSegments with the same number of elements.
* @exception java.lang.SeedReaderException input null, or i/o error parsing packet data.
*/
public static Collection getWFSegments(Collection packetList) {
if (packetList == null)
throw new NullPointerException("getWFSegments() Null input collection of seed packets.");
final int MAX_PACKET_SIZE = 8192; // test efficiency, instead of dynamically creating new arrays for each packet.
Collection wfSegmentCollection = new ArrayList(packetList.size());
Iterator iter = packetList.iterator();
try {
while (iter.hasNext()) {
byte [] seedPacket = (byte []) iter.next();
WFSegment wfSegment = createWFSegment(seedPacket);
header = getHeader();
if ( header.isData() ) { // decompress only data messages
wfSegment.setTimeSeries(
decompress (header, seedPacket)
);
}
wfSegmentCollection.add(wfSegment);
}
}
catch (NullPointerException ex) {
throw new SeedReaderException(ex.getMessage());
}
catch (Exception ex) {
ex.printStackTrace();
throw new SeedReaderException("getWFSegments(): " + ex.getMessage());
}
return wfSegmentCollection;
}
/**
* Read a file in Seed format as described in a waveform object. Returns
* the number of WFSegments read . The access method, local or remote,
* is determined automatically.
*/
public static int getData (Waveform wf) {
return getData(wf, wf.getStart().doubleValue(), wf.getEnd().doubleValue());
}
public static int getData (Waveform wf, double startTime, double endTime) {
if (wf.getWaveSourceType() == Waveform.LoadFromDataSource) {
// Try accessing locally first, if that fails use remote access.
if (wf.filesAreLocal()) {
return getDataLocal(wf); // try local access
}
else {
return getDataFromDataSource(wf, startTime, endTime); // try test DB access via blob - aww
}
//} else {
// return getDataRemote(wf); // try remote ftp access
//}
} else if (wf.getWaveSourceType() == Waveform.LoadFromWaveServer) {
return getDataFromWaveServer(wf);
}
return 0;
}
//** Get timeseries from a wave server */
public static int getDataFromWaveServer (Waveform waveform) {
WaveClient waveClient = (WaveClient) Waveform.getWaveSource();
// System.out.println ("SeedReader: waveClient ="+waveClient);
try {
// Get the time-series
waveClient.setTruncatetAtTimeGap(false);
// not sure this is always true
waveform.setAmpUnits(Units.COUNTS);
return waveClient.getJasiWaveformDataRaw (waveform);
}
catch (Exception ex) {
System.err.println(ex.toString());
ex.printStackTrace();
}
finally {
// if (waveClient != null) waveClient.close();
}
return 0;
}
/**
* Return a ChannelableList of Waveform objects extracted from a Local or NFS mounted file
* containing Seed format. Returns null on fatal error. */
public static ChannelableList getDataFromFile (String filename, int traceoff) {
ChannelableList wfList = new ChannelableList();
Waveform wf = null;
FileInputStream seedStream;
File file = new File(filename);
long filesize = file.length();
filesize -= traceoff;
// System.out.println ("SeedReader opening "+file+ " "+traceoff+" "+nbytes);
// open the Seed File
try {
// seedStream = new FileInputStream(filename);
seedStream = new FileInputStream(file);
} catch (FileNotFoundException exc) {
System.out.println ("File not found: " + filename);
return null;
} catch (IOException exc) {
System.err.println ("IO error: " + exc.toString());
return null;
}
BufferedInputStream inbuff =
new BufferedInputStream (seedStream, READBUFFERSIZE);
int buffOffset = 0;
int dataSize = 0;
int totalBytes = 0;
int lastChannelStart = 0;
// skip the proper byte offset in the file
if (traceoff > 0) {
try {
long bytesSkippped = inbuff.skip(traceoff);
// catch non-exception problems
if (bytesSkippped != traceoff) {
System.err.println ("IO error: could only skip "+bytesSkippped+
" wanted to skip " + traceoff);
return null;
}
} catch (IOException exc) {
System.err.println ("IO error skipping to data offset: " +
exc.toString());
return null;
}
}
// file read loop; while data is there and we haven't yet gotten all the bytes
try {
while (inbuff.available() > 0) {
// && totalBytes < nbytes) {
buffOffset = 0;
/*
* NOTE: Seed packets can be of various sizes, although the size must be a power of 2.
* You don't know what the size is until you read the header of the packet.
*/
// <1> read the header
//NOTE: DANGER HERE: THIS ASSUMES THE HEADER IS TOTALLY CONTAINED WITHIN THE
// FIRST 64-BYTE FRAME. HEADERS MAY EXTEND INTO SUBSEQUENT FRAMES IF THE
// BLOCKETTES FILL THE FIRST ONE (E.G. THE "V" HEADERS ARE > 64 BYTES)
totalBytes +=
inbuff.read(buff, buffOffset, FrameSize); // read one Seed header (64 bytes)
lastChannelStart = totalBytes - FrameSize; // beginning of a channel's data
header = SeedHeader.parseSeedHeader(buff);
if (header == null) {
System.out.println("Skipping malformed SEED header");
continue; // continue while loop to read next frame
} else if (!header.isData()) {
System.out.println("Skipping non-data header of type "+ header.headerType);
continue; // continue while loop to read next frame
}
wfseg = SeedReader.createWFSegment(header);
if (wfseg == null) return null; // bad data
// <2> read the data part now that we know how big it is (=blockSize)
dataSize = header.seedBlockSize - FrameSize;
buffOffset = FrameSize; // start storing bytes in buffer at # 64
totalBytes +=
inbuff.read(buff, buffOffset, dataSize); // append Seed data frames
if ( header.isData() ) // a data "record"
{
// decompress the data into the WFSegment
wfseg.setTimeSeries( decompress (header, buff) );
// is it a channel we already have in our list
wf = (Waveform) wfList.getByChannel(wfseg.getChannelObj());
if (wf == null) { // not in list :. a new channel/waveform
wf = Waveform.create();
// not sure this is always true
wf.setAmpUnits(Units.COUNTS);
wf.setFileOffset(lastChannelStart);
wf.setFilename(filename);
wf.setFileOffset(traceoff);
wf.setChannelObj(wfseg.getChannelObj());
wf.format.setValue(Waveform.SEED_FORMAT);
wf.setSampleRate(1.0/wfseg.getSampleInterval());
wf.encoding.setValue(header.encodingFormat);
wf.setStart(wfseg.getStart());
// wf.id = evid; // no meaningfull file!
wfList.add(wf);
}
// add segment to the Waveform
wf.getSegmentList().add(wfseg);
wf.setEnd(wfseg.getEnd()); // push back end time
} else { // skip non-data blocks
// noop
}
// progress
System.out.print ("\rRead: " +(int) (((double)totalBytes/(double)filesize) * 100.0)+"% "+
totalBytes+ " / "+ filesize);
} // end of while loop
System.out.println ("");
inbuff.close();
seedStream.close();
} catch (IOException exc) {
System.err.println ("IO error: " + exc.toString());
exc.printStackTrace();
} catch (Exception exc) {
System.err.println ("General exception: " + exc.toString());
exc.printStackTrace();
}
// collapse multiple segements into minimum possible
Waveform wfa[] = (Waveform[]) wfList.toArray(new Waveform[0]);
for (int i = 0; i < wfa.length; i++) {
if (wfa[i] != null ) {
wfa[i].collapse();
// set max, min, bias values
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -