package edu.sc.seis.sod.subsetter.eventStation; import java.util.ArrayList; import java.util.List; import org.w3c.dom.Element; import edu.iris.Fissures.BoxArea; import edu.iris.Fissures.GlobalArea; import edu.iris.Fissures.event.OriginImpl; import edu.iris.Fissures.model.QuantityImpl; import edu.iris.Fissures.model.UnitImpl; import edu.iris.Fissures.network.StationImpl; import edu.sc.seis.TauP.Arrival; import edu.sc.seis.TauP.SphericalCoords; import edu.sc.seis.TauP.TauModelException; import edu.sc.seis.TauP.TauP_Path; import edu.sc.seis.TauP.TauP_Pierce; import edu.sc.seis.TauP.TimeDist; import edu.sc.seis.fissuresUtil.cache.CacheEvent; import edu.sc.seis.sod.ConfigurationException; import edu.sc.seis.sod.CookieJar; import edu.sc.seis.sod.SodUtil; import edu.sc.seis.sod.status.StringTree; import edu.sc.seis.sod.status.StringTreeLeaf; public class PhaseInteraction implements EventStationSubsetter { public PhaseInteraction(Element config) throws ConfigurationException { Element element = SodUtil.getElement(config, "modelName"); if(element != null) modelName = SodUtil.getNestedText(element); element = SodUtil.getElement(config, "phaseName"); if(element != null) phaseName = SodUtil.getNestedText(element); element = SodUtil.getElement(config, "interactionStyle"); if(element != null) interactionStyle = SodUtil.getNestedText(element); element = SodUtil.getElement(config, "interactionNumber"); if(element != null) interactionNumber = Integer.parseInt(SodUtil.getNestedText(element)); element = SodUtil.getElement(config, "relative"); if(element != null) phaseInteractionType = (PhaseInteractionType)SodUtil.load(element, "eventStation"); element = SodUtil.getElement(config, "absolute"); if(element != null) phaseInteractionType = (PhaseInteractionType)SodUtil.load(element, "eventStation"); try { tauPPierce = new TauP_Pierce(modelName); tauPPierce.clearPhaseNames(); tauPPierce.parsePhaseList(phaseName); tauPPath = new TauP_Path(tauPPierce.getTauModel()); tauPPath.clearPhaseNames(); tauPPath.parsePhaseList(phaseName); } catch(TauModelException e) { throw new ConfigurationException("Can't load TauP_Pierce", e); } } public StringTree accept(CacheEvent event, StationImpl station, CookieJar cookieJar) throws Exception { if(interactionStyle.equals("PATH")) { return new StringTreeLeaf(this, acceptPathInteraction(event, station)); } else { return new StringTreeLeaf(this, acceptPierceInteraction(event, station)); } } public boolean acceptPathInteraction(CacheEvent event, StationImpl station) throws Exception { OriginImpl origin = event.getOrigin(); double originDepth; double eventStationDistance; originDepth = ((QuantityImpl)origin.getLocation().depth).convertTo(UnitImpl.KILOMETER).value; tauPPath.setSourceDepth(originDepth); eventStationDistance = SphericalCoords.distance(origin.getLocation().latitude, origin.getLocation().longitude, station.getLocation().latitude, station.getLocation().longitude); double azimuth = SphericalCoords.azimuth(origin.getLocation().latitude, origin.getLocation().longitude, station.getLocation().latitude, station.getLocation().longitude); tauPPath.calculate(eventStationDistance); List<Arrival> arrivals = tauPPath.getArrivals(); List<Arrival> requiredArrivals = getRequiredArrival(arrivals); if(requiredArrivals.size() == 0) return false; if(phaseInteractionType instanceof Relative) { return handleRelativePathInteraction(requiredArrivals, eventStationDistance); } else { return handleAbsolutePhaseInteraction(requiredArrivals, azimuth, origin, "PATH"); } } public boolean acceptPierceInteraction(CacheEvent event, StationImpl station) throws Exception { double originDepth; double eventStationDistance; OriginImpl origin = event.getOrigin(); originDepth = ((QuantityImpl)origin.getLocation().depth).convertTo(UnitImpl.KILOMETER).value; tauPPierce.setSourceDepth(originDepth); eventStationDistance = SphericalCoords.distance(origin.getLocation().latitude, origin.getLocation().longitude, station.getLocation().latitude, station.getLocation().longitude); double azimuth = SphericalCoords.azimuth(origin.getLocation().latitude, origin.getLocation().longitude, station.getLocation().latitude, station.getLocation().longitude); tauPPierce.calculate(eventStationDistance); List<Arrival> arrivals = tauPPierce.getArrivals(); List<Arrival> requiredArrivals = getRequiredArrival(arrivals); if(requiredArrivals.size() != 0) { if(phaseInteractionType instanceof Relative) { return handlePierceRelativePhaseInteraction(requiredArrivals, eventStationDistance); } else { //throw new ConfigurationException("Absolute Area for // PhaseInteraction is Not Implemented"); return handleAbsolutePhaseInteraction(requiredArrivals, azimuth, origin, "PIERCE"); } } else return false; } public boolean handlePierceRelativePhaseInteraction(List<Arrival> requiredArrivals, double eventStationDistance) throws Exception { for(int counter = 0; counter < requiredArrivals.size(); counter++) { TimeDist[] timeDistArray = requiredArrivals.get(counter).getPierce(); TimeDist timeDist = getRequiredTimeDist(timeDistArray); QuantityImpl timeDistDepth = new QuantityImpl(timeDist.getDepth(), UnitImpl.KILOMETER); ; QuantityImpl minDepth; QuantityImpl maxDepth; QuantityImpl timeDistDistance = new QuantityImpl(timeDist.getDistDeg(), UnitImpl.DEGREE); QuantityImpl minDistance; QuantityImpl maxDistance; if(((Relative)phaseInteractionType).getDepthRange() != null) { minDepth = ((Relative)phaseInteractionType).getDepthRange() .getMinDepth(); maxDepth = ((Relative)phaseInteractionType).getDepthRange() .getMaxDepth(); } else { minDepth = timeDistDepth; maxDepth = timeDistDepth; } if(((Relative)phaseInteractionType).getDistanceRange() != null) { if(((Relative)phaseInteractionType).getReference() .equals("STATION")) { timeDistDistance = new QuantityImpl(eventStationDistance - timeDist.getDistDeg(), UnitImpl.DEGREE); } minDistance = ((Relative)phaseInteractionType).getDistanceRange() .getMin(); maxDistance = ((Relative)phaseInteractionType).getDistanceRange() .getMax(); } else { minDistance = timeDistDistance; maxDistance = timeDistDistance; } if(minDepth.lessThanEqual(timeDistDepth) && maxDepth.greaterThanEqual(timeDistDepth)) { if(minDistance.lessThanEqual(timeDistDistance) && maxDistance.greaterThanEqual(timeDistDistance)) { return true; } }//end of if checking for depth. }//end of for(int counter = 0; ........) return false; } public boolean handleRelativePathInteraction(List<Arrival> requiredArrivals, double eventStationDistance) throws Exception { for(int counter = 0; counter < requiredArrivals.size(); counter++) { TimeDist[] timeDistArray = requiredArrivals.get(counter).getPath(); if(checkForRelativePathInteraction(timeDistArray, 0, timeDistArray.length, eventStationDistance, requiredArrivals.get(counter).getDistDeg())) { return true; } } return false; } public boolean checkForRelativePathInteraction(TimeDist[] timeDistArray, int start, int end, double eventStationDistance, double totalDistance) throws Exception { //for(int i = 0; i < timeDistArray.length; i++) { int counter = 0; if(end < start) return false; int mid = (start + end) / 2; TimeDist timeDist = timeDistArray[mid]; QuantityImpl minDistance = null; QuantityImpl maxDistance = null; QuantityImpl timeDistDistance = new QuantityImpl(timeDist.getDistDeg(), UnitImpl.DEGREE); while(counter < totalDistance) { QuantityImpl timeDistDepth = new QuantityImpl(timeDist.getDepth(), UnitImpl.KILOMETER); QuantityImpl minDepth; QuantityImpl maxDepth; if(((Relative)phaseInteractionType).getDepthRange() != null) { minDepth = ((Relative)phaseInteractionType).getDepthRange() .getMinDepth(); maxDepth = ((Relative)phaseInteractionType).getDepthRange() .getMaxDepth(); } else { minDepth = timeDistDepth; maxDepth = timeDistDepth; } if(((Relative)phaseInteractionType).getDistanceRange() != null) { if(((Relative)phaseInteractionType).getReference() .equals("STATION")) { timeDistDistance = new QuantityImpl(eventStationDistance - timeDist.getDistDeg(), UnitImpl.DEGREE); } minDistance = ((Relative)phaseInteractionType).getDistanceRange() .getMin(); maxDistance = ((Relative)phaseInteractionType).getDistanceRange() .getMax(); } else { minDistance = timeDistDistance; maxDistance = timeDistDistance; } if(minDepth.lessThanEqual(timeDistDepth) && maxDepth.greaterThanEqual(timeDistDepth)) { minDistance = new QuantityImpl(minDistance.value + counter, UnitImpl.DEGREE); maxDistance = new QuantityImpl((360 + counter) - minDistance.value, UnitImpl.DEGREE); QuantityImpl tempDistance = new QuantityImpl(counter - timeDistDistance.value, UnitImpl.DEGREE); if((minDistance.lessThanEqual(timeDistDistance) && maxDistance.greaterThanEqual(timeDistDistance)) || (minDistance.lessThanEqual(tempDistance) && maxDistance.greaterThanEqual(tempDistance))) { return true; } } counter += 360; } if(end < start) { return false; } else if(minDistance.greaterThan(timeDistDistance)) { return checkForRelativePathInteraction(timeDistArray, mid, end, eventStationDistance, totalDistance); } else if(maxDistance.lessThan(timeDistDistance)) { return checkForRelativePathInteraction(timeDistArray, start, mid, eventStationDistance, totalDistance); } else return false; //} } public boolean handleAbsolutePhaseInteraction(List<Arrival> requiredArrivals, double azimuth, OriginImpl origin, String type) throws Exception { edu.iris.Fissures.Area area = ((Absolute)phaseInteractionType).getArea(); for(int i = 0; i < requiredArrivals.size(); i++) { TimeDist[] timeDist; if(type.equals("PIERCE")) { timeDist = requiredArrivals.get(i).getPierce(); } else { timeDist = requiredArrivals.get(i).getPath(); } azimuth = checkForLongway(requiredArrivals.get(i).getDistDeg(), azimuth); for(int counter = 0; counter < timeDist.length; counter++) { QuantityImpl timeDistDepth = new QuantityImpl(timeDist[0].getDepth(), UnitImpl.KILOMETER); ; QuantityImpl minDepth; QuantityImpl maxDepth; if(((Absolute)phaseInteractionType).getDepthRange() != null) { minDepth = ((Absolute)phaseInteractionType).getDepthRange() .getMinDepth(); maxDepth = ((Absolute)phaseInteractionType).getDepthRange() .getMaxDepth(); } else { minDepth = timeDistDepth; maxDepth = timeDistDepth; } if(minDepth.lessThanEqual(timeDistDepth) && maxDepth.greaterThanEqual(timeDistDepth)) { if(area == null || area instanceof GlobalArea) return true; double tLat = SphericalCoords.latFor(origin.getLocation().latitude, origin.getLocation().longitude, timeDist[counter].getDepth(), azimuth); double tLon = SphericalCoords.lonFor(origin.getLocation().latitude, origin.getLocation().longitude, timeDist[counter].getDepth(), azimuth); if(area instanceof BoxArea) { BoxArea boxArea = (BoxArea)area; if(tLat >= boxArea.min_latitude && tLat <= boxArea.max_latitude && tLon >= boxArea.min_longitude && tLon <= boxArea.max_longitude) { return true; } }//end of if area instanceof BoxArea. } //end of if checking for depth. }//end of for(int counter = 0......... }//end of for(int i= 0; i < requiredArrivals.length; i++) return false; } public TimeDist getRequiredTimeDist(TimeDist[] timeDist) { if(timeDist.length == 0) return null; double past = timeDist[0].getDepth(); double current; double next; for(int counter = 1; counter < timeDist.length - 1; counter++) { current = timeDist[counter].getDepth(); next = timeDist[counter + 1].getDepth(); if(interactionStyle.equals("TOPSIDE REFLECTION")) { //("dist = "+distance+" depth = "+depth+" past = "+past+" // current = "+current+" next = "+next); } if(interactionStyle.equals("TOPSIDE REFLECTION") && past < current && current > next) { return timeDist[counter]; } else if(interactionStyle.equals("BOTTOMSIDE REFLECTION") && past > current && current < next) { return timeDist[counter]; } past = current; } return null; } public List<Arrival> getRequiredArrival(List<Arrival> arrivals) { ArrayList<Arrival> arrayList = new ArrayList<Arrival>(); for(int counter = 0; counter < arrivals.size(); counter++) { String arrivalName = arrivals.get(counter).getName(); if(phaseName.startsWith("tt")) { if(phaseName.equals("tts") && arrivalName.toUpperCase().startsWith("S")) { arrayList.add(arrivals.get(counter)); } else if(phaseName.equals("ttp") && arrivalName.toUpperCase().startsWith("P")) { arrayList.add(arrivals.get(counter)); } } else if(phaseName.equals(arrivalName)) { arrayList.add(arrivals.get(counter)); } } return arrayList; } public double checkForLongway(double distance, double azimuth) { while(distance > 360) distance = distance - 360; if(distance > 180) { azimuth = azimuth + 180; } return azimuth; } private String modelName = "prem"; private String phaseName = null; private String interactionStyle = null; private int interactionNumber = 1; private PhaseInteractionType phaseInteractionType = null; private TauP_Pierce tauPPierce; private TauP_Path tauPPath; }// PhaseInteraction