package org.opensha2.calc; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static org.opensha2.data.XySequence.emptyCopyOf; import org.opensha2.data.XySequence; import org.opensha2.eq.model.GridSourceSet; import org.opensha2.eq.model.HazardModel; import org.opensha2.eq.model.Source; import org.opensha2.eq.model.SourceSet; import org.opensha2.eq.model.SourceType; import org.opensha2.gmm.Imt; import com.google.common.base.StandardSystemProperty; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Maps; import com.google.common.collect.SetMultimap; import java.util.EnumMap; import java.util.Map; import java.util.Map.Entry; /** * The result of a hazard calculation. This container class is public for * reference by external packages but is not directly modifiable, nor its fields * accessible. The {@link HazardExport} class provides {@code Hazard} exporting * and processing utilities. * * @author Peter Powers * @see HazardExport */ public final class Hazard { final SetMultimap<SourceType, HazardCurveSet> sourceSetCurves; final Map<Imt, XySequence> totalCurves; final HazardModel model; final Site site; final CalcConfig config; private Hazard( SetMultimap<SourceType, HazardCurveSet> sourceSetCurves, Map<Imt, XySequence> totalCurves, HazardModel model, Site site, CalcConfig config) { this.sourceSetCurves = sourceSetCurves; this.totalCurves = totalCurves; this.model = model; this.site = site; this.config = config; } @Override public String toString() { String LF = StandardSystemProperty.LINE_SEPARATOR.value(); StringBuilder sb = new StringBuilder("HazardResult:"); if (sourceSetCurves.keySet().isEmpty()) { sb.append(" empty, was the site out of range?"); return sb.toString(); } sb.append(LF); for (SourceType type : sourceSetCurves.keySet()) { sb.append(type).append("SourceSet:").append(LF); for (HazardCurveSet curveSet : sourceSetCurves.get(type)) { SourceSet<? extends Source> ss = curveSet.sourceSet; sb.append(" ").append(ss); sb.append("Used: "); switch (type) { case CLUSTER: sb.append(curveSet.clusterGroundMotionsList.size()); break; case SYSTEM: sb.append(curveSet.hazardGroundMotionsList.get(0).inputs.size()); break; case GRID: sb.append(GridSourceSet.sizeString( curveSet.sourceSet, curveSet.hazardGroundMotionsList.size())); break; default: sb.append(curveSet.hazardGroundMotionsList.size()); } sb.append(LF); } } return sb.toString(); } /** * The total mean hazard curves for each calculated {@code Imt}. */ public Map<Imt, XySequence> curves() { return totalCurves; } /** * The original configuration used to generate this result. */ public CalcConfig config() { return config; } /** * Combine hazard from multiple independent models. The hazard object returned * by this method probably does not specify a parent 'model'. * * @return a combined {@code Hazard} that probably has a {@code null} parent * model. If only 1 {@code Hazard} is supplied, method returns that * supplied. */ public static Hazard merge(Hazard... hazards) { checkArgument(hazards.length > 0); if (hazards.length == 1) { return hazards[0]; } ImmutableSetMultimap.Builder<SourceType, HazardCurveSet> curveMapBuilder = ImmutableSetMultimap.builder(); Map<Imt, XySequence> totalCurves = new EnumMap<>(Imt.class); for (Entry<Imt, XySequence> entry : hazards[0].config.hazard.logModelCurves().entrySet()) { totalCurves.put(entry.getKey(), emptyCopyOf(entry.getValue())); } for (Hazard hazard : hazards) { curveMapBuilder.putAll(hazard.sourceSetCurves); for (Entry<Imt, XySequence> entry : hazard.totalCurves.entrySet()) { totalCurves.get(entry.getKey()).add(entry.getValue()); } } return new Hazard( curveMapBuilder.build(), totalCurves, null, hazards[0].site, hazards[0].config); } static Builder builder(CalcConfig config) { return new Builder(config); } static class Builder { private static final String ID = "HazardResult.Builder"; private boolean built = false; private HazardModel model; private Site site; private CalcConfig config; private ImmutableSetMultimap.Builder<SourceType, HazardCurveSet> curveMapBuilder; private Map<Imt, XySequence> totalCurves; private Builder(CalcConfig config) { this.config = checkNotNull(config); totalCurves = new EnumMap<>(Imt.class); for (Entry<Imt, XySequence> entry : config.hazard.logModelCurves().entrySet()) { totalCurves.put(entry.getKey(), emptyCopyOf(entry.getValue())); } curveMapBuilder = ImmutableSetMultimap.builder(); } Builder site(Site site) { checkState(this.site == null, "%s site already set", ID); this.site = checkNotNull(site); return this; } Builder model(HazardModel model) { checkState(this.model == null, "%s model already set", ID); this.model = checkNotNull(model); return this; } Builder addCurveSet(HazardCurveSet curveSet) { curveMapBuilder.put(curveSet.sourceSet.type(), curveSet); for (Entry<Imt, XySequence> entry : curveSet.totalCurves.entrySet()) { totalCurves.get(entry.getKey()).add(entry.getValue()); } return this; } private void validateState(String mssgID) { checkState(!built, "This %s instance has already been used", mssgID); checkState(site != null, "%s site not set", mssgID); checkState(model != null, "%s model not set", mssgID); } Hazard build() { validateState(ID); return new Hazard( curveMapBuilder.build(), Maps.immutableEnumMap(totalCurves), model, site, config); } } }