MTIndexerModule.java

/**
 * MTIndexerModule
 */

package gov.usgs.earthquake.momenttensor;

import java.math.BigDecimal;

import gov.usgs.earthquake.indexer.DefaultIndexerModule;
import gov.usgs.earthquake.indexer.IndexerModule;
import gov.usgs.earthquake.indexer.ProductSummary;
import gov.usgs.earthquake.product.Product;

/**
 * Moment Tensor Indexer Module.
 *
 * Implements ANSS business logic for preferred moment tensors.
 *
 * Intended order is:
 * <ol>
 * <li>Mww (W-phase)</li>
 * <li>Mwc from GCMT</li>
 * <li>Mwc</li>
 * <li>Mwb</li>
 * <li>Other</li>
 * <li>Mwb outside magnitude range [5.5, 7.0]</li>
 * </ol>
 *
 * <hr>
 *
 * Uses {@link DefaultIndexerModule#getProductSummary(Product)} defaults,
 * with the following additional weights:
 *
 * <ul>
 * <li>
 *   <code>Event Source</code> comes from the product property
 *   <code>eventsource</code>
 * </li>
 * <li>
 *   <code>Magnitude</code> comes from the product property
 *   <code>derived-magnitude</code>
 * </li>
 * <li>
 *   <code>Type</code> comes from the product property
 *   <code>derived-magnitude-type</code>, or (if not found)
 *   from the product property <code>beachball-type</code>
 * </li>
 * </ul>
 *
 * <dl>
 * <dt>Type is <code>Mww</code></dt>
 * <dd><code>+60</code></dd>
 *
 * <dt>Type is <code>Mwc</code></dt>
 * <dd><code>+2</code></dd>
 *
 * <dt>Type is <code>Mwb</code>
 * <dd><code>+1</code></dd>
 *
 * <dt>Type is <code>Mwb</code>, and Magnitude outside the
 * 	 range <code>[5.5, 7.0]</code></dt>
 * <dd><code>-100</code></dd>
 *
 * <dt>Event Source is <code>GCMT</code></dt>
 * <dd><code>+56</code></dd>
 * </dl>
 */
public class MTIndexerModule extends DefaultIndexerModule {

	private static final String TYPE_MWW = "Mww";
	private static final long TYPE_MWW_BONUS = 60L;

	private static final String TYPE_MWC = "Mwc";
	private static final long TYPE_MWC_BONUS = 2L;

	private static final String TYPE_MWB = "Mwb";
	private static final long TYPE_MWB_BONUS = 1L;

	private static final long TYPE_OTHER_BONUS = 0L;

	private static final String EVENT_SOURCE_GCMT = "gcmt";
	private static final long EVENT_SOURCE_GCMT_BONUS = 56L;

	private static final long MAG_OUTSIDE_RANGE_PENALTY = -100L;
	private static final BigDecimal MAG_RANGE_MIN = new BigDecimal("5.5");
	private static final BigDecimal MAG_RANGE_MAX = new BigDecimal("7.0");

	/**
	 * Override IndexerModule api method.
	 *
	 * @return
	 * 		IndexerModule.LEVEL_SUPPORTED when type is <code>moment-tensor</code>;
	 * 		otherwise, IndexerModule.LEVEL_UNSUPPORTED.
	 */
	@Override
	public int getSupportLevel(Product product) {
		int supportLevel = IndexerModule.LEVEL_UNSUPPORTED;
		String type = getBaseProductType(product.getId().getType());
		// Support only moment tensor products
		if ("moment-tensor".equals(type)) {
			supportLevel = IndexerModule.LEVEL_SUPPORTED;
		}

		return supportLevel;
	}

	/**
	 * Calculate preferred weight for <code>moment-tensor</code> type product.
	 *
	 * @param summary "moment-tensor" type product summary.
	 * @return
	 *      when type is <code>moment-tensor</code>, {@link IndexerModule#LEVEL_SUPPORTED};
	 * 		otherwise, {@link IndexerModule#LEVEL_UNSUPPORTED}
	 */
	@Override
	protected long getPreferredWeight(ProductSummary summary)
			throws Exception {
		// Get the default preferred weight value from the parent class
		long weight = super.getPreferredWeight(summary);

		// points by type
		String tensorType = summary.getProperties().get("derived-magnitude-type");
		String eventSource = summary.getEventSource();
		String derivedMagnitude = summary.getProperties().get("derived-magnitude");
		BigDecimal magRange = derivedMagnitude == null ? null : new BigDecimal(derivedMagnitude);

		if (tensorType == null) {
			tensorType = summary.getProperties().get("beachball-type");
		}

		if (tensorType != null) {
			// Add bonus
			if (tensorType.equalsIgnoreCase(TYPE_MWW)) {
				weight += TYPE_MWW_BONUS;
			} else if (tensorType.equalsIgnoreCase(TYPE_MWC)) {
				weight += TYPE_MWC_BONUS;
			} else if (tensorType.equalsIgnoreCase(TYPE_MWB)) {
				weight += TYPE_MWB_BONUS;
			} else {
				weight += TYPE_OTHER_BONUS;
			}

			// Subtract penalty
			if (magRange != null
					&& tensorType.equalsIgnoreCase(TYPE_MWB)
					&& (magRange.compareTo(MAG_RANGE_MIN) == -1 || magRange.compareTo(MAG_RANGE_MAX) == 1)) {
				weight += MAG_OUTSIDE_RANGE_PENALTY;
			}
		}

		// Add gcmt bonus if required
		if (eventSource != null && eventSource.equalsIgnoreCase(EVENT_SOURCE_GCMT)) {
			weight += EVENT_SOURCE_GCMT_BONUS;
		}

		return weight;
	}
}