package edu.sc.seis.sod.subsetter.origin;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import edu.iris.Fissures.IfEvent.Origin;
import edu.iris.Fissures.event.EventAttrImpl;
import edu.iris.Fissures.event.OriginImpl;
import edu.iris.Fissures.model.MicroSecondDate;
import edu.iris.Fissures.model.QuantityImpl;
import edu.iris.Fissures.model.TimeInterval;
import edu.iris.Fissures.model.UnitImpl;
import edu.sc.seis.fissuresUtil.bag.DistAz;
import edu.sc.seis.fissuresUtil.cache.CacheEvent;
import edu.sc.seis.fissuresUtil.time.MicroSecondTimeRange;
import edu.sc.seis.fissuresUtil.xml.XMLUtil;
import edu.sc.seis.sod.ConfigurationException;
import edu.sc.seis.sod.SodUtil;
import edu.sc.seis.sod.Standing;
import edu.sc.seis.sod.hibernate.StatefulEvent;
import edu.sc.seis.sod.hibernate.StatefulEventDB;
import edu.sc.seis.sod.status.StringTree;
import edu.sc.seis.sod.status.StringTreeLeaf;
public class RemoveEventDuplicate implements OriginSubsetter {
public RemoveEventDuplicate(Element config) throws ConfigurationException {
Element el = XMLUtil.getElement(config, "timeVariance");
if (el != null){
setTimeVariance(SodUtil.loadQuantity(el));
}
el = XMLUtil.getElement(config, "distanceVariance");
if (el != null){
setDistanceVariance(SodUtil.loadQuantity(el));
}
el = XMLUtil.getElement(config, "depthVariance");
if (el != null){
setDepthVariance(SodUtil.loadQuantity(el));
}
}
public RemoveEventDuplicate(QuantityImpl timeVariance, QuantityImpl distanceVariance, QuantityImpl depthVariance)
throws ConfigurationException {
setTimeVariance(timeVariance);
setDistanceVariance(distanceVariance);
setDepthVariance(depthVariance);
}
public RemoveEventDuplicate() {
}
public StatefulEventDB getEventStatusTable() throws SQLException {
if (eventTable == null) {
eventTable = StatefulEventDB.getSingleton();
}
return eventTable;
}
public StringTree accept(CacheEvent eventAccess,
EventAttrImpl eventAttr,
OriginImpl preferred_origin)
throws Exception {
// first eliminate based on time and depth as these are easy and the database can do efficiently
Iterator matchingEvents = getEventsNearTimeAndDepth(preferred_origin).iterator();
while( matchingEvents.hasNext()) {
StatefulEvent e = (StatefulEvent)matchingEvents.next();
if (!e.equals(eventAccess)){
if (isDistanceClose(e, preferred_origin)){
return new StringTreeLeaf(this, false);
}
}
}
return new StringTreeLeaf(this, true);
}
public boolean isDistanceClose(CacheEvent eventA, Origin originB) {
Origin curOrig = eventA.getOrigin();
DistAz distAz = new DistAz(curOrig.getLocation(), originB.getLocation());
if (distanceVariance.getUnit().isConvertableTo(UnitImpl.DEGREE)) {
return distAz.getDelta() < distanceVariance.convertTo(UnitImpl.DEGREE).value;
} else {
// use earth radius of 6371 km
return distAz.getDelta()*6371 < distanceVariance.convertTo(UnitImpl.KILOMETER).value;
}
}
public List getEventsNearTimeAndDepth(Origin preferred_origin) throws SQLException {
MicroSecondDate originTime = new MicroSecondDate(preferred_origin.getOriginTime());
MicroSecondDate minTime = originTime.subtract(new TimeInterval(timeVariance));
MicroSecondDate maxTime = originTime.add(new TimeInterval(timeVariance));
QuantityImpl originDepth = QuantityImpl.createQuantityImpl(preferred_origin.getLocation().depth);
QuantityImpl depthRangeImpl = QuantityImpl.createQuantityImpl(depthVariance);
QuantityImpl minDepth = originDepth.subtract(depthRangeImpl);
QuantityImpl maxDepth = originDepth.add(depthRangeImpl);
List timeEvents =
getEventStatusTable().getEventInTimeRangeRegardlessOfStatus(new MicroSecondTimeRange(minTime,
maxTime));
List out = new ArrayList();
Iterator it = timeEvents.iterator();
while(it.hasNext()) {
StatefulEvent e = (StatefulEvent)it.next();
if (e.getStatus().getStanding().equals(Standing.INIT) ||
e.getStatus().getStanding().equals(Standing.IN_PROG) ||
e.getStatus().getStanding().equals(Standing.SUCCESS)) {
QuantityImpl depth = (QuantityImpl)e.getOrigin().getLocation().depth;
if (depth.greaterThanEqual(minDepth) && depth.lessThanEqual(maxDepth)) {
out.add(e);
logger.debug("Considering for RemoveEventDup: "+e);
} else {
logger.debug("Not considering (depth="+depth+") for RemoveEventDup: "+e);
}
} else {
logger.debug("Not considering (status="+e.getStatus()+") for RemoveEventDup: "+e);
}
}
return out;
}
protected void setTimeVariance(QuantityImpl timeVariance) throws ConfigurationException {
if ( ! ( timeVariance.getUnit().isConvertableTo(UnitImpl.SECOND))) {
throw new ConfigurationException("Units must be convertible to SECOND: "+timeVariance.getUnit());
}
this.timeVariance = timeVariance;
}
protected void setDistanceVariance(QuantityImpl maxDistance) throws ConfigurationException {
if ( ! ( maxDistance.getUnit().isConvertableTo(UnitImpl.DEGREE) || maxDistance.getUnit().isConvertableTo(UnitImpl.KILOMETER))) {
throw new ConfigurationException("Units must be convertible to DEGREE or KILOMETER: "+maxDistance.getUnit());
}
this.distanceVariance = maxDistance;
}
protected void setDepthVariance(QuantityImpl depthVariance) throws ConfigurationException {
if ( ! ( depthVariance.getUnit().isConvertableTo(UnitImpl.KILOMETER))) {
throw new ConfigurationException("Units must be convertible to KILOMETER: "+depthVariance.getUnit());
}
this.depthVariance = depthVariance;
}
protected QuantityImpl timeVariance = new QuantityImpl(10, UnitImpl.SECOND);
protected QuantityImpl distanceVariance = new QuantityImpl(0.5, UnitImpl.DEGREE);
protected QuantityImpl depthVariance = new QuantityImpl(100, UnitImpl.KILOMETER);
private StatefulEventDB eventTable;
private static Logger logger = LoggerFactory.getLogger(RemoveEventDuplicate.class);
}