package com.isti.xmax.common;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.log4j.Logger;
import com.isti.traceview.TraceViewException;
import com.isti.traceview.common.AbstractEvent;
import com.isti.traceview.common.IEvent;
import com.isti.traceview.common.Station;
import com.isti.traceview.common.TimeInterval;
import com.isti.traceview.common.Wildcard;
import com.isti.traceview.data.PlotDataProvider;
import com.isti.xmax.XMAX;
import com.isti.xmax.XMAXconfiguration;
import edu.sc.seis.TauP.TauModelException;
import edu.sc.seis.TauP.TauP_Time;
import edu.sc.seis.fissuresUtil.bag.DistAz;
/**
* Class holds information about particular earthquake. Also contain
* initialization logic from "ndk" files and can compute arrivals for this
* earthquake.
*
* @author Max Kokoulin
*/
public class Earthquake extends AbstractEvent implements IEvent {
private static final Logger logger = Logger.getLogger(Earthquake.class);
private static SimpleDateFormat df = new SimpleDateFormat(
"yyyy/MM/dd HH:mm:ss.SSS");
/**
* Time lag to load earthquakes to see phase in time interval, in
* milliseconds
*/
private static long maxPhaseDelay = 7200000; // Two hours
public static String[] phases = { "p", "s", "P", "S", "Pn", "Sn", "PcP",
"ScS", "Pdiff", "Sdiff", "PKP", "SKS", "PKiKP", "SKiKS", "PKIKP",
"SKIKS" };
static {
df.setTimeZone(XMAX.timeZone);
}
/**
* @param time
* earthquake time
* @param code
* directory code
* @param latitude
* latitude
* @param longitude
* longitude
* @param depth
* depth
* @param magnitude_mb
* magnitude
* @param magnitude_MS
* magnitude
* @param location
* region description
*/
public Earthquake(Date time, String code, Double latitude,
Double longitude, Double depth, Double magnitude_mb,
Double magnitude_MS, String location) {
super(time, 0);
setParameter("SOURCECODE", code);
setParameter("LATITUDE", latitude);
setParameter("LONGITUDE", longitude);
setParameter("DEPTH", depth);
setParameter("MAGNITUDE_MB", magnitude_mb);
setParameter("MAGNITUDE_MS", magnitude_MS);
setParameter("LOCATION", location);
logger.debug("Created " + this);
}
public String getType() {
return "EARTHQUAKE";
}
public String getSourceCode() {
return (String) getParameterValue("SOURCECODE");
}
public Double getLatitude() {
return (Double) getParameterValue("LATITUDE");
}
public Double getLongitude() {
return (Double) getParameterValue("LONGITUDE");
}
public Double getDepth() {
return (Double) getParameterValue("DEPTH");
}
public Double getMagnitude_mb() {
return (Double) getParameterValue("MAGNITUDE_MB");
}
public Double getMagnitude_MS() {
return (Double) getParameterValue("MAGNITUDE_MS");
}
public String getLocation() {
return (String) getParameterValue("LOCATION");
}
public String toString() {
return "Earthquake: SourceCode " + getSourceCode() + ", latitude "
+ getLatitude() + ", longitude " + getLongitude() + ", depth "
+ getDepth() + ", magnitude mb " + getMagnitude_mb()
+ ", magnitude MS " + getMagnitude_MS() + ", location "
+ getLocation() + ", time " + getStartTime();
}
/**
* Reads earthquakes list from Global Centroid-Moment-Tensor (CMT) catalog
* NDK file format
*/
public static List<IEvent> getEarthquakes(TimeInterval ti)
throws TraceViewException {
List<IEvent> ret = new ArrayList<IEvent>();
List<File> files = new Wildcard().getFilesByMask(XMAXconfiguration.
getInstance().getEarthquakeFileMask());
for (File file: files) {
logger.debug("Processing event file: " + file.getName());
try {
LineNumberReader r = new LineNumberReader(new FileReader(file));
String[] rawData = null;
while ((rawData = readRawData(r))[0] != null) {
try {
// First line: Hypocenter line
// [1-4] Hypocenter reference catalog (e.g., PDE for
// USGS location, ISC for
// ISC catalog, SWE for surface-wave location, [Ekstrom,
// BSSA, 2006])
//String catalog = rawData[0].substring(0, 4).trim();
// [6-15] Date of reference event
// [17-26] Time of reference event
Date date = df
.parse(rawData[0].substring(5, 26).trim());
// [28-33] Latitude
Double latitude = new Double(rawData[0].substring(27,
33).trim());
// [35-41] Longitude
Double longitude = new Double(rawData[0].substring(34,
41).trim());
// [43-47] Depth
Double depth = new Double(rawData[0].substring(42, 47)
.trim());
// [49-55] Reported magnitudes, usually mb and MS
Double magnitude_mb = new Double(rawData[0].substring(
48, 51).trim());
Double magnitude_MS = new Double(rawData[0].substring(
52, 55).trim());
// [57-80] Geographical location (24 characters)
String location = rawData[0].substring(56, 80).trim();
// Second line: CMT info (1)
// [1-16] CMT event name. This string is a unique
// CMT-event identifier.
// Older
// events have 8-character names, current ones have
// 14-character names.
String name = rawData[1].substring(0, 16).trim();
if ((date.getTime() > ti.getStart() - maxPhaseDelay)
&& (date.getTime() < ti.getEnd())) {
Earthquake earthquake = new Earthquake(date, name,
latitude, longitude, depth, magnitude_mb,
magnitude_MS, location);
ret.add(earthquake);
}
} catch (NumberFormatException e) {
logger.error("Can't parse earthquake, line "
+ (r.getLineNumber() - rawData.length) + ": ", e);
} catch (ParseException e) {
logger.error("Can't parse earthquake, line "
+ (r.getLineNumber() - rawData.length) + ": ", e);
}
}
} catch (FileNotFoundException e) {
logger.error("Can't open earthquake file " + ": ", e);
}
}
Collections.sort(ret);
return ret;
}
/**
* Reads data for one earthquake from .NDK file. Return String[5] array contains five lines of
* earquake's data, or null if exception occured
*/
private static String[] readRawData(LineNumberReader r) {
String[] data = new String[5];
try {
for (int i = 0; i < data.length; i++) {
data[i] = r.readLine();
}
} catch (IOException e) {
logger.error("IOException:", e);
return null;
}
return data;
}
/**
* Compute arrivals for this earthquake
*
* @param channel
* channel describes station and time range of interested
* arrivals
* @return set of arrivals
*/
public SortedSet<IEvent> computeArrivals(PlotDataProvider channel) {
TreeSet<IEvent> ret = new TreeSet<IEvent>();
Station station = channel.getStation();
try {
TauP_Time timeTool = new TauP_Time("iasp91");
timeTool.setPhaseNames(phases);
for (IEvent earthquake : XMAX.getDataModule().getEarthquakes()) {
timeTool.depthCorrect((Double) earthquake
.getParameterValue("DEPTH"));
DistAz da = new DistAz(
(Double) earthquake.getParameterValue("LATITUDE"),
(Double) earthquake.getParameterValue("LONGITUDE"),
station.getLatitude(), station.getLongitude());
double angle = da.getDelta();
timeTool.calculate(angle);
edu.sc.seis.TauP.Arrival[] arrivals = timeTool.getArrivals();
for (int i = 0; i < arrivals.length; i++) {
ret.add(new Arrival(new Date(earthquake.getStartTime()
.getTime()
+ new Double(arrivals[i].getTime() * 1000)
.longValue()), (Earthquake) earthquake,
arrivals[i].getName(), angle, da.getAz(), da
.getBaz(), DistAz
.degreesToKilometers(angle)));
}
}
} catch (TauModelException e) {
logger.error("Can't load TauP earth model: ", e);
}
return ret;
}
}