package org.opensha2.eq.model; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.StandardSystemProperty.LINE_SEPARATOR; import static org.opensha2.eq.Earthquakes.checkInterfaceDepth; import static org.opensha2.eq.Earthquakes.checkInterfaceWidth; import static org.opensha2.eq.fault.Faults.checkTrace; import static org.opensha2.eq.model.SourceType.INTERFACE; import org.opensha2.eq.fault.surface.ApproxGriddedSurface; import org.opensha2.eq.fault.surface.DefaultGriddedSurface; import org.opensha2.eq.fault.surface.GriddedSurface; import org.opensha2.eq.fault.surface.RuptureFloating; import org.opensha2.eq.fault.surface.RuptureScaling; import org.opensha2.geo.Location; import org.opensha2.geo.LocationList; import org.opensha2.geo.Locations; import org.opensha2.mfd.IncrementalMfd; import com.google.common.collect.ImmutableList; import java.util.List; /** * Subduction source representation. This class wraps a model of a subduction * interface geometry and a list of magnitude frequency distributions that * characterize how the fault might rupture (e.g. as one, single * geometry-filling event, or as multiple smaller events) during earthquakes. * Smaller events are modeled as 'floating' ruptures; they occur in multiple * locations on the fault surface with appropriately scaled rates. * * <p>An {@code InterfaceSource} cannot be created directly; it may only be * created by a private parser. * * @author Peter Powers */ public class InterfaceSource extends FaultSource { final LocationList lowerTrace; private InterfaceSource( String name, int id, LocationList upperTrace, LocationList lowerTrace, double dip, double width, GriddedSurface surface, double rake, List<IncrementalMfd> mfds, double spacing, RuptureScaling rupScaling, RuptureFloating rupFloating, boolean rupVariability) { super(name, id, upperTrace, dip, width, surface, rake, mfds, spacing, rupScaling, rupFloating, rupVariability); this.lowerTrace = (lowerTrace == null) ? surface.getEvenlyDiscritizedLowerEdge() : lowerTrace; // TODO lowerTrace may be null and this is bad bad; lowerTrace // is referenced in InterfaceSourceSet distanceFilter and // we should populate this even if the original source only // specified an upper trace. This highlights another shortcoming // of Container2D and GriddedSurface: why is there no getRow(int) // of getBottomRow() given that there is a getUpperEdge(), // acknowledging that the latter may not be the same as the trace // due to seismogenic depth constraints. For now, we are ignoring // lower trace in distance filter, but given large width of interface // sources TODO clean up Container2D methods } @Override public SourceType type() { return INTERFACE; } /** * The closest point on the upper or lower fault trace, relative to the * supplied site {@code Location}. */ @Override public Location location(Location site) { return Locations.closestPoint(site, LocationList.builder() .addAll(trace) .addAll(lowerTrace) .build()); } @Override public String toString() { // TODO use joiner return new StringBuilder() .append("========== Interface Source ==========") .append(LINE_SEPARATOR.value()) .append(" Source name: ").append(name()) .append(LINE_SEPARATOR.value()) .append(" dip: ").append(dip) .append(LINE_SEPARATOR.value()) .append(" width: ").append(width) .append(LINE_SEPARATOR.value()) .append(" rake: ").append(rake) .append(LINE_SEPARATOR.value()) .append(" mfds: ").append(mfds.size()) .append(LINE_SEPARATOR.value()) .append(" top: ").append(trace.first().depth()) .append(LINE_SEPARATOR.value()).toString(); } /* Single use builder. */ static class Builder extends FaultSource.Builder { private static final String ID = "InterfaceSource.Builder"; // required private LocationList lowerTrace; @Override Builder depth(double depth) { this.depth = checkInterfaceDepth(depth); return this; } @Override Builder width(double width) { this.width = checkInterfaceWidth(width); return this; } Builder lowerTrace(LocationList trace) { checkNotNull(this.trace, "Upper trace must be set first"); this.lowerTrace = checkTrace(trace); return this; } InterfaceSource buildSubductionSource() { /* * Either upper and lower trace must be set, or upper trace depth, dip, * and width. If upper and lower are set, depth, dip and width (if also * set) will ultimately be ignored and computed lazily by the subduction * surface implementation; otherwise the three fields are set to NaN to * satisfy parent builder. */ mfds = mfdsBuilder.build(); GriddedSurface surface = null; if (lowerTrace != null) { // if going dual-trace route, satisfy parent builder with NaNs this.depth = Double.NaN; this.dip = Double.NaN; this.width = Double.NaN; validateState(ID); surface = new ApproxGriddedSurface(trace, lowerTrace, spacing); } else { // otherwise build a basic fault source validateState(ID); surface = DefaultGriddedSurface.builder() .trace(trace) .depth(depth) .dip(dip) .width(width) .spacing(spacing) .build(); } return new InterfaceSource(name, id, trace, lowerTrace, dip, width, surface, rake, ImmutableList.copyOf(mfds), spacing, rupScaling, rupFloating, rupVariability); } } }