package org.opensha2.calc;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static org.opensha2.internal.TextUtils.NEWLINE;
import org.opensha2.gmm.Gmm;
import org.opensha2.gmm.Imt;
import org.opensha2.gmm.ScalarGroundMotion;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Container class for scalar ground motions associated with individual
* {@code Source}s in a {@code SourceSet}.
*
* @author Peter Powers
*/
final class GroundMotions {
/*
* NOTE the inputList supplied to Builder is immutable but the
* ScalarGroundMotion map it builds is not.
*/
final InputList inputs;
final Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> gmMap;
private GroundMotions(
InputList inputs,
Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> gmMap) {
this.inputs = inputs;
this.gmMap = gmMap;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb.append(" [").append(inputs.parentName()).append("]");
sb.append(":").append(NEWLINE);
for (Entry<Imt, Map<Gmm, List<ScalarGroundMotion>>> imtEntry : gmMap.entrySet()) {
sb.append(" ");
Imt imt = imtEntry.getKey();
for (Entry<Gmm, List<ScalarGroundMotion>> gmmEntry : imtEntry.getValue().entrySet()) {
sb.append(imt.name()).append(" [ ");
Gmm gmm = gmmEntry.getKey();
sb.append(gmm.name()).append(" ");
for (ScalarGroundMotion sgm : gmmEntry.getValue()) {
sb.append(String.format("μ=%.3f", sgm.mean())).append(" ");
sb.append(String.format("σ=%.3f", sgm.sigma())).append(" ");
}
sb.append("] ");
}
sb.append(NEWLINE);
}
return sb.toString();
}
static Builder builder(InputList inputs, Set<Imt> imts, Set<Gmm> gmms) {
return new Builder(inputs, imts, gmms);
}
/*
* Combine GroundMotions resulting from InputList partitioning. The original
* InputList is required as a convenience (the supplied GroundMotions contain
* sublists of this list). The original list is also used as a size check
* against the combined result.
*/
static GroundMotions combine(InputList inputs, List<GroundMotions> groundMotions) {
Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> keyModel = groundMotions.get(0).gmMap;
Set<Imt> imtKeys = keyModel.keySet();
Set<Gmm> gmmKeys = keyModel.get(imtKeys.iterator().next()).keySet();
return builder(inputs, imtKeys, gmmKeys)
.combine(groundMotions)
.build();
}
static class Builder {
private static final String ID = "GroundMotions.Builder";
private boolean built = false;
private final int size;
private int addCount = 0;
private final InputList inputs;
private final Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> gmMap;
private Builder(InputList inputs, Set<Imt> imts, Set<Gmm> gmms) {
checkArgument(inputs.size() > 0);
checkArgument(gmms.size() > 0);
this.inputs = inputs;
gmMap = initGmMap(imts, gmms, inputs.size());
size = imts.size() * gmms.size() * inputs.size();
}
Builder add(Imt imt, Gmm gmm, ScalarGroundMotion sgm) {
checkState(addCount < size, "This %s instance is already full", ID);
gmMap.get(imt).get(gmm).add(sgm);
addCount++;
return this;
}
GroundMotions build() {
checkState(!built, "This %s instance has already been used", ID);
checkState(addCount == size, "Only %s of %s entries have been added", addCount, size);
built = true;
GroundMotions gms = new GroundMotions(inputs, gmMap);
return gms;
}
static Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> initGmMap(
Set<Imt> imts,
Set<Gmm> gmms,
int size) {
Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> imtMap = Maps.newEnumMap(Imt.class);
for (Imt imt : imts) {
Map<Gmm, List<ScalarGroundMotion>> gmmMap = Maps.newEnumMap(Gmm.class);
for (Gmm gmm : gmms) {
gmmMap.put(gmm, new ArrayList<ScalarGroundMotion>(size));
}
imtMap.put(imt, gmmMap);
}
return imtMap;
}
/*
* For internal use only. Combines multiple ordered GroundMotions that
* result from InputList partitioning. Can only be called once after
* intializing the builder with the original master InputList.
*/
private Builder combine(List<GroundMotions> groundMotions) {
for (GroundMotions gms : groundMotions) {
addCount += addValues(gmMap, gms.gmMap);
}
return this;
}
private static int addValues(
Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> sgmTargetMap,
Map<Imt, Map<Gmm, List<ScalarGroundMotion>>> sgmValueMap) {
int setCount = 0;
for (Entry<Imt, Map<Gmm, List<ScalarGroundMotion>>> imtEntry : sgmTargetMap.entrySet()) {
Imt imt = imtEntry.getKey();
for (Entry<Gmm, List<ScalarGroundMotion>> gmmEntry : imtEntry.getValue().entrySet()) {
Gmm gmm = gmmEntry.getKey();
List<ScalarGroundMotion> sgmTarget = gmmEntry.getValue();
List<ScalarGroundMotion> sgmValues = sgmValueMap.get(imt).get(gmm);
sgmTarget.addAll(sgmValues);
setCount += sgmValues.size();
}
}
return setCount;
}
}
}