/**
* ChannelGrouper.java
*
* @author Jagadeesh Danala
* @version
*/
package edu.sc.seis.sod;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import edu.iris.Fissures.IfNetwork.ChannelId;
import edu.iris.Fissures.model.MicroSecondDate;
import edu.iris.Fissures.model.QuantityImpl;
import edu.iris.Fissures.model.SamplingImpl;
import edu.iris.Fissures.model.UnitImpl;
import edu.iris.Fissures.network.ChannelIdUtil;
import edu.iris.Fissures.network.ChannelImpl;
import edu.sc.seis.fissuresUtil.bag.OrientationUtil;
import edu.sc.seis.fissuresUtil.hibernate.ChannelGroup;
import edu.sc.seis.sod.channelGroup.Rule;
import edu.sc.seis.sod.validator.Validator;
public class ChannelGrouper {
public ChannelGrouper() throws ConfigurationException {
this(null);
}
public ChannelGrouper(String configFileLoc) throws ConfigurationException {
try {
defaultRules = loadRules(defaultConfigFileLoc);
additionalRules = loadRules(configFileLoc);
} catch(IOException e) {
throw new ConfigurationException("Unable to configure three component rules", e);
} catch(SAXException e) {
throw new ConfigurationException("Unable to configure three component rules", e);
} catch(ParserConfigurationException e) {
throw new ConfigurationException("Unable to configure three component rules", e);
}
}
/** group channels into three components of motion. It is assumed that all the channels
* in the list are from the same network.station.
* @param channels
* @param failures
* @return
*/
public List<ChannelGroup> group(List<ChannelImpl> channels, List<ChannelImpl> failures) {
return applyRules(channels, defaultRules, additionalRules, failures);
}
private List<ChannelGroup> applyRules(List<ChannelImpl> channels,
List<Rule> defaultRules,
List<Rule> additionalRules,
List<ChannelImpl> failures) {
List<ChannelGroup> groupableChannels = new LinkedList<ChannelGroup>();
HashMap<String, List<ChannelImpl>> bandGain = groupByNetStaBandGain(channels);
Iterator<String> iter = bandGain.keySet().iterator();
while(iter.hasNext()) {
String key = iter.next();
List<ChannelImpl> toTest = new ArrayList<ChannelImpl>();
toTest.addAll(bandGain.get(key));
for (Rule rule : additionalRules) {
List<ChannelImpl> stillToTest = new ArrayList<ChannelImpl>();
List<ChannelGroup> groups = rule.acceptable(toTest, stillToTest);
groupableChannels.addAll(groups);
toTest = stillToTest;
}
for (Rule rule : defaultRules) {
List<ChannelImpl> stillToTest = new ArrayList<ChannelImpl>();
List<ChannelGroup> groups = rule.acceptable(toTest, stillToTest);
groupableChannels.addAll(groups);
toTest = stillToTest;
}
failures.addAll(toTest);
}
return groupableChannels;
}
public static boolean sanityCheck(ChannelGroup channelGroup) {
return haveSameSamplingRate(channelGroup)
&& areOrthogonal(channelGroup);
}
private static boolean areOrthogonal(ChannelGroup channelGroup) {
ChannelImpl[] chans = channelGroup.getChannels();
for(int i = 0; i < chans.length; i++) {
for(int j = i + 1; j < chans.length; j++) {
if(!OrientationUtil.areOrthogonal(chans[i].getOrientation(),
chans[j].getOrientation())) {
logger.info("Fail areOrthogonal ("+i+","+j+"): "+ChannelIdUtil.toString(chans[i].get_id())+" "+OrientationUtil.toString(chans[i].getOrientation())+" "+ChannelIdUtil.toString(chans[j].get_id())+" "+OrientationUtil.toString(chans[j].getOrientation()));
return false;
}
}
}
return true;
}
private static boolean haveSameSamplingRate(ChannelGroup cg) {
ChannelImpl[] chans = cg.getChannels();
SamplingImpl sampl = (SamplingImpl)chans[0].getSamplingInfo();
QuantityImpl freq = sampl.getFrequency();
UnitImpl baseUnit = freq.getUnit();
double samplingRate0 = (freq.getValue()) * sampl.getNumPoints();
for(int i = 1; i < chans.length; i++) {
SamplingImpl sample = (SamplingImpl)chans[i].getSamplingInfo();
double sampleRate = (sample.getFrequency().convertTo(baseUnit).getValue())
* sample.getNumPoints();
if(sampleRate != samplingRate0) {
logger.info("Fail haveSameSamplingRate ("+i+"): "+ChannelIdUtil.toString(chans[i].get_id())+" "+chans[i].getSamplingInfo()+" "+ChannelIdUtil.toString(chans[0].get_id())+" "+chans[0].getSamplingInfo());
return false;
}
}
return true;
}
HashMap<String, List<ChannelImpl>> groupByNetStaBandGain(List<ChannelImpl> channels) {
HashMap<String, List<ChannelImpl>> bandGain = new HashMap<String, List<ChannelImpl>>();
for(ChannelImpl c : channels) {
MicroSecondDate msd = new MicroSecondDate(c.get_id().begin_time);
ChannelId cId = c.getId();
String key = cId.network_id.network_code+"."+cId.station_code+"."+cId.channel_code;
key = key.substring(0, key.length() - 1);
key = msd + key;
List<ChannelImpl> chans = bandGain.get(key);
if(chans == null) {
chans = new LinkedList<ChannelImpl>();
bandGain.put(key, chans);
}
chans.add(c);
}
return bandGain;
}
// If the config file in invalid the validator throws a SAXException
private List<Rule> loadRules(String configFileLoc) throws IOException, SAXException, ParserConfigurationException, ConfigurationException {
List<Rule> out = new ArrayList<Rule>();
if(configFileLoc != null && configFileLoc.length() != 0 ) {
Validator validator = new Validator(grouperSchemaLoc);
if(!validator.validate(getRules(configFileLoc))) {
throw new ConfigurationException("Invalid config file! "+configFileLoc+" "+validator.getErrorMessage());
} else {
Document doc = Start.createDoc(getRules(configFileLoc),
configFileLoc);
NodeList ruleList = doc.getElementsByTagName("rule");
for(int i = 0; i < ruleList.getLength(); i++) {
out.add(new Rule((Element)ruleList.item(i), configFileLoc+" "+i));
}
}
}
return out;
}
private InputSource getRules(String configFileLoc) throws IOException {
ClassLoader loader = ChannelGrouper.class.getClassLoader();
return Start.createInputSource(loader, configFileLoc);
}
private static Logger logger = LoggerFactory.getLogger(ChannelGrouper.class);
private List<Rule> defaultRules;
private List<Rule> additionalRules;
List<Rule> ruleList = new ArrayList<Rule>();
private static String defaultConfigFileLoc = "jar:edu/sc/seis/sod/data/grouper.xml";
private static final String grouperSchemaLoc = "edu/sc/seis/sod/data/grouper.rng";
}