diff --git a/src/main/java/gov/usgs/earthquake/nshmp/fault/FocalMech.java b/src/main/java/gov/usgs/earthquake/nshmp/fault/FocalMech.java index b066ecf3ce53a0808eb1e8001f9325ceeea64428..a34747bc3e79f50cd5fdc0bb01a83ac11e150a49 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/fault/FocalMech.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/fault/FocalMech.java @@ -27,6 +27,15 @@ public enum FocalMech { this.rake = rake; } + /** + * Returns the focal mechanism for the supplied rake. Divisions are on 45° + * diagonals. + */ + public static FocalMech fromRake(double rake) { + return (rake >= 45 && rake <= 135) ? REVERSE + : (rake >= -135 && rake <= -45) ? NORMAL : STRIKE_SLIP; + } + /** * Returns a 'standard' dip value for this mechanism. * @return the dip diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/ClusterRuptureSet.java b/src/main/java/gov/usgs/earthquake/nshmp/model/ClusterRuptureSet.java index d5a4e8d1d11b02a841cf5b44348f68faf6e02c5e..a7576d800c284f56c66ca7102b3443e0af11d1c5 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/ClusterRuptureSet.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/ClusterRuptureSet.java @@ -222,8 +222,6 @@ public class ClusterRuptureSet implements RuptureSet { faultRuptureSets = new ArrayList<>(); for (FaultRuptureSet.Builder frsb : faultRuptureSetBuilders) { frsb.modelData(data); - frsb.featureMap(featureMap); - faultRuptureSets.add(frsb.build()); } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/Deserialize.java b/src/main/java/gov/usgs/earthquake/nshmp/model/Deserialize.java index 0a67ca867abd701ff5616f21cebef3e3fd0bbcf7..b13027fdf9291e99a8660add6d3610acdd163bd3 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/Deserialize.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/Deserialize.java @@ -238,13 +238,18 @@ class Deserialize { } /* Create a rupture set builder, initialized with data from file. */ - static FaultRuptureSet.Builder ruptureSet(Path json, ModelData data) { + static FaultRuptureSet.Builder faultRuptureSet( + Path json, + ModelData data) { + JsonObject obj = jsonObject(json); - return ruptureSet(obj, data); + return faultRuptureSet(obj, data); } /* Create a rupture set builder, initialized with data from file. */ - private static FaultRuptureSet.Builder ruptureSet(JsonObject obj, ModelData data) { + private static FaultRuptureSet.Builder faultRuptureSet( + JsonObject obj, + ModelData data) { FaultRuptureSet.Builder ruptureSet = FaultRuptureSet.builder(); @@ -267,7 +272,9 @@ class Deserialize { } /* Create a rupture set builder, initialized with data from file. */ - static ClusterRuptureSet.Builder clusterSet(Path json, ModelData data) { + static ClusterRuptureSet.Builder clusterRuptureSet( + Path json, + ModelData data) { JsonObject obj = jsonObject(json); ClusterRuptureSet.Builder clusterSet = ClusterRuptureSet.builder(); @@ -277,7 +284,7 @@ class Deserialize { JsonArray ruptures = obj.get(RUPTURE_SETS).getAsJsonArray(); for (JsonElement rupture : ruptures) { - FaultRuptureSet.Builder ruptureSet = ruptureSet(rupture.getAsJsonObject(), data); + FaultRuptureSet.Builder ruptureSet = faultRuptureSet(rupture.getAsJsonObject(), data); clusterSet.addRuptureSet(ruptureSet); } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/FaultRuptureSet.java b/src/main/java/gov/usgs/earthquake/nshmp/model/FaultRuptureSet.java index c5a872b6a3be5952b57cc29bc7e1ae4d4ee196da..114ef37c2efb511be9d7be89ebaa7dc1cf536b7d 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/FaultRuptureSet.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/FaultRuptureSet.java @@ -3,21 +3,16 @@ package gov.usgs.earthquake.nshmp.model; 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 gov.usgs.earthquake.nshmp.Text.checkName; import static gov.usgs.earthquake.nshmp.model.SourceType.FAULT; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toUnmodifiableList; -import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import gov.usgs.earthquake.nshmp.Earthquakes; import gov.usgs.earthquake.nshmp.Faults; -import gov.usgs.earthquake.nshmp.data.XyPoint; import gov.usgs.earthquake.nshmp.data.XySequence; import gov.usgs.earthquake.nshmp.fault.surface.DefaultGriddedSurface; import gov.usgs.earthquake.nshmp.fault.surface.GriddedSurface; @@ -32,70 +27,46 @@ import gov.usgs.earthquake.nshmp.tree.Branch; import gov.usgs.earthquake.nshmp.tree.LogicTree; /** - * Fault source representation. This class wraps a model of a fault 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>A {@code FaultSource} cannot be created directly; it may only be created - * by a private parser. + * Crustal finite fault rupture set. * * @author U.S. Geological Survey */ public class FaultRuptureSet implements RuptureSet { - final String name; - final int id; + final SourceFeature.NshmFault feature; + final ModelData data; final LogicTree<Mfd> mfdTree; + // final Mfd mfdTotal; - @Deprecated - final LogicTree<Mfd.Properties> mfdPropsTree; - @Deprecated - XySequence mfdTotal; + final List<Integer> sectionIds; // reference: actually needed? - final List<Integer> sections; - final SourceFeature.NshmFault feature; final GriddedSurface surface; - // private final List<List<Rupture>> ruptureLists; // 1:1 with Mfds - - @Deprecated // shouldn't need field once a FRS is a source - final SourceConfig.Fault config; - FaultRuptureSet(Builder builder) { - - this.name = builder.name; - this.id = builder.id; + this.feature = builder.feature; + this.data = builder.data; this.mfdTree = builder.mfdTree; - this.mfdPropsTree = builder.mfdPropsTreeOut; - // this.mfdTree = builder.mfdTree; - // this.mfdTotal = builder.mfdTotal; - - this.config = builder.config; - this.sections = builder.sections; - this.feature = builder.feature; + this.sectionIds = builder.sectionIds; this.surface = builder.surface; - - // this.ruptureLists = builder.ruptureLists; } @Override public String name() { - return name; + return feature.name; } @Override - public int size() { - return 0; + public int id() { + return feature.id; } @Override - public int id() { - return id; + public int size() { + // TODO what should this be ?? + // a value based on the size of the Mfds?? + return 1; } @Override @@ -112,22 +83,11 @@ public class FaultRuptureSet implements RuptureSet { return Locations.closestPoint(site, feature.trace); } - // TODO this needs significant improvement; the mfd tree size - // is the product of the props tree and rate tree, - // if present; when FRS implements source should - // be able to deal with logic trees - @Deprecated - public List<Mfd.Properties> mfdProps() { - return mfdPropsTree.branches().stream() - .map(Branch::value) - .collect(toUnmodifiableList()); - } - @Override public String toString() { return getClass().getSimpleName() + " " + Map.of( - "name", name, - "id", id, + "name", name(), + "id", id(), "feature", feature.source.toJson()); } @@ -140,46 +100,37 @@ public class FaultRuptureSet implements RuptureSet { private boolean built = false; + private SourceFeature.NshmFault feature; private ModelData data; - private LogicTree<Mfd.Properties> mfdPropsTree; - private Optional<String> mfdTreeKey = Optional.empty(); - // required - private String name; - private Integer id; - private List<Integer> sections; - private Map<Integer, SourceFeature.NshmFault> featureMap; - private SourceFeature.NshmFault feature; + private LogicTree<Mfd.Properties> mfdPropsTree; + private LogicTree<Mfd.Properties> mfdPropsTreeOut; /* created on build */ private LogicTree<Mfd> mfdTree; private GriddedSurface surface; - @Deprecated - private LogicTree<Mfd.Properties> mfdPropsTreeOut; - - private SourceConfig.Fault config; + /* + * Name, id, and and sectionIds Validated and carried forward in rupture set + * feature. + */ + private String name; + private Integer id; + private List<Integer> sectionIds; Builder name(String name) { - this.name = checkName(name, "FaultRuptureSet"); + this.name = name; return this; } Builder id(int id) { - checkArgument(id > 0, "ID [%s] < 1", id); this.id = id; return this; } - /* Set the section IDs; optional. */ Builder sections(List<Integer> sections) { checkArgument(sections.size() >= 1); - this.sections = List.copyOf(sections); - return this; - } - - Builder featureMap(Map<Integer, SourceFeature.NshmFault> featureMap) { - this.featureMap = Map.copyOf(featureMap); + this.sectionIds = List.copyOf(sections); return this; } @@ -195,38 +146,36 @@ public class FaultRuptureSet implements RuptureSet { return this; } + FaultRuptureSet build() { + validateAndInit("FaultRuptureSet.Builder"); + return new FaultRuptureSet(this); + } + private void validateAndInit(String label) { checkState(!built, "Single use builder"); - checkNotNull(name, "%s name", label); - checkNotNull(id, "%s geometry ID", label); - checkNotNull(data, "%s model reference data", label); + checkNotNull(sectionIds, "%s section ID list", label); + checkNotNull(data, "%s model data", label); - if (mfdTreeKey.isPresent()) { - String key = mfdTreeKey.get(); - mfdPropsTree = data.mfdMap().get().get(key); - } - checkNotNull(mfdPropsTree, "%s MFD tree", label); + checkNotNull(name, "%s name", label); + checkNotNull(id, "%s id", label); + checkNotNull(mfdPropsTree, "%s MFD logic tree", label); mfdTree = buildMfdTree(data, mfdPropsTree); // mfdTotal = buildTotalMfd(mfdTree); mfdPropsTreeOut = buildMfdPropsTree(data, mfdPropsTree); - checkNotNull(sections, "%s section ID list", label); - checkNotNull(featureMap, "%s feature map", label); - checkState(featureMap.keySet().containsAll(sections)); + // if feature.rateMap + feature = createFeature(); - if (sections.size() > 1) { - Feature f = joinFeatures(sections.stream() - .map(featureMap::get) - .map(feature -> feature.source) - .collect(toList())); - feature = new SourceFeature.NshmFault(f); - } else { - feature = featureMap.get(sections.get(0)); - } + System.out.println(); + System.out.println(mfdPropsTree); + System.out.println(feature); + System.out.println(feature.rateMap); + System.out.println(); + System.out.println(); - config = (SourceConfig.Fault) data.sourceConfig(); + SourceConfig.Fault config = (SourceConfig.Fault) data.sourceConfig(); surface = DefaultGriddedSurface.builder() .trace(feature.trace) .depth(feature.upperDepth) @@ -238,26 +187,46 @@ public class FaultRuptureSet implements RuptureSet { .spacing(config.surfaceSpacing) .build(); - // ruptureLists = initRuptureLists(); - // TODO reenable - // checkState(Iterables.size(Iterables.concat(ruptureLists)) > 0, - // "%s has no ruptures", label); - built = true; } - FaultRuptureSet build() { - validateAndInit("FaultRuptureSet.Builder"); - return new FaultRuptureSet(this); + private SourceFeature.NshmFault createFeature() { + Map<Integer, SourceFeature.NshmFault> featureMap = + data.faultFeatureMap().orElseThrow(); + checkState(featureMap.keySet().containsAll(sectionIds)); + + Feature f = joinFeatures(sectionIds.stream() + .map(featureMap::get) + .map(feature -> feature.source) + .collect(toList())); + return new SourceFeature.NshmFault(f); } + /* + * TODO: consider short citcuiting singletons if feature as represented in + * model is consistent with rupture set requirements + * + * TODO: Split into 3 features for normal faults; this may happen prior to + * getting here + * + * TODO: Copy properties from multi segment ruptures (mostly 2008 model) + * + * TODO: For documentaiton; there are many options avilable when defining + * both sfautl and grid based sources that may necessarily be able to be + * combined. For example, normal fault dip variants are difficult to handle + * in the context of a cluster model. + */ + /* * Joins the traces in the supplied features into a new Feature with the - * properties of the last sfeature supplied. + * properties of the first feature supplied. */ private Feature joinFeatures(List<Feature> features) { - if (features.size() == 1) { - return features.get(0); + Feature.Builder feature = (features.size() == 1) + ? Feature.copyOf(features.get(0)) + : joinFaultSections(features); + if (features.size() > 1) { + } Feature last = features.get(features.size() - 1); Map<String, ?> props = Properties.fromFeature(last).build(); @@ -272,6 +241,7 @@ public class FaultRuptureSet implements RuptureSet { * identical points at the ends of sections. */ private static Feature.Builder joinFaultSections(List<Feature> features) { + // TODO copy properties of first feature into builder LocationList joined = features.stream() .map(Feature::asLineString) .flatMap(LocationList::stream) @@ -281,58 +251,13 @@ public class FaultRuptureSet implements RuptureSet { LocationList::copyOf)); return Feature.lineString(joined); } - - // see FaultSource - @Deprecated - private List<List<Rupture>> initRuptureLists() { - List<List<Rupture>> rupLists = new ArrayList<>(); - - List<Mfd> mfds = mfdTree.branches().stream() - .map(Branch::value) - .collect(toList()); - for (Mfd mfd : mfds) { - List<Rupture> rupList = createRuptureList(mfd); - // TODO reenable - // checkState(rupList.size() > 0, "Rupture list is empty"); - rupLists.add(rupList); - } - return List.copyOf(rupLists); - } - - // see FaultSource - @Deprecated - private List<Rupture> createRuptureList(Mfd mfd) { - List<Rupture> rupList = new ArrayList<>(); - for (XyPoint xy : mfd.data()) { - double mag = xy.x(); - double rate = xy.y(); - - // TODO necessary? derive from config and apply elsewhere - if (rate < 1e-14) { - continue; // shortcut low rates - } - - // TODO revisit, floating rupture behavior controlled by - // magnitude and RuptureFloating; OFF forces full rupture - // at whatever magnitude - - // former singleton rupture TODO clean - // Rupture rup = Rupture.create(mag, rate, feature.rake, surface); - // rupListbuilder.add(rup); - - List<Rupture> floaters = config.ruptureFloating.createFloatingRuptures( - surface, config.ruptureScaling, mag, rate, feature.rake, false); - rupList.addAll(floaters); - - } - return List.copyOf(rupList); - } } private static LogicTree<Mfd.Properties> buildMfdPropsTree( ModelData mfdData, LogicTree<Mfd.Properties> mfdPropertiesTree) { + // Not true, def model branches have epitemic uncertainty applied // shouldn't have rate-tree AND epistemic uncertainty, both // of which increase the number of branches if (mfdData.rateTree().isPresent()) { diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/HazardModel.java b/src/main/java/gov/usgs/earthquake/nshmp/model/HazardModel.java index da914d18d018e0758a8023d076fb1f6bcf50d5b6..5bdd233b510cea47388ec791fdbc15c33ec30ee1 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/HazardModel.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/HazardModel.java @@ -294,22 +294,25 @@ public final class HazardModel implements Iterable<SourceSet<? extends Source>> FaultRuptureSet frs, double leafWeight) { + SourceFeature.NshmFault feature = frs.feature; + SourceConfig.Fault config = (SourceConfig.Fault) frs.data.sourceConfig(); + return new FaultSource.Builder() - .name(frs.name) - .id(frs.id) - .trace(frs.feature.trace) - .dip(frs.feature.dip) + .name(feature.name) + .id(feature.id) + .trace(feature.trace) + .dip(feature.dip) .width(Faults.width( - frs.feature.dip, - frs.feature.upperDepth, - frs.feature.lowerDepth)) - .depth(frs.feature.upperDepth) - .rake(frs.feature.rake) + feature.dip, + feature.upperDepth, + feature.lowerDepth)) + .depth(feature.upperDepth) + .rake(feature.rake) .mfdTree(frs.mfdTree) - .surfaceSpacing(frs.config.surfaceSpacing) - .ruptureScaling(frs.config.ruptureScaling) - .ruptureFloating(frs.config.ruptureFloating) - .ruptureVariability(frs.config.ruptureVariability) + .surfaceSpacing(config.surfaceSpacing) + .ruptureScaling(config.ruptureScaling) + .ruptureFloating(config.ruptureFloating) + .ruptureVariability(config.ruptureVariability) .branchWeight(leafWeight) // List.of(Mfd.copyOf(frs.mfdTotal).scale(leafWeight).build())) .buildFaultSource(); diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/InterfaceRuptureSet.java b/src/main/java/gov/usgs/earthquake/nshmp/model/InterfaceRuptureSet.java index a070df8b4dfa79685ecb2d7919fbaf2cc77339b0..29ea7bb809728940a5752c5db9a991514ff56f3b 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/InterfaceRuptureSet.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/InterfaceRuptureSet.java @@ -22,20 +22,19 @@ import gov.usgs.earthquake.nshmp.tree.Branch; import gov.usgs.earthquake.nshmp.tree.LogicTree; /** - * Subduction interface rupture set implemention. + * Subduction interface rupture set. * * @author U.S. Geological Survey */ public class InterfaceRuptureSet implements RuptureSet { - // TODO if single section, should be fault section; if stitched, - // should be new feature with id and name from reupture-set.json + /* May be original interface section or stitched. */ final SourceFeature.Interface feature; final ModelData data; final LogicTree<Mfd> mfdTree; - final List<Integer> sections;// reference: actually needed? + final List<Integer> sectionIds;// reference: actually needed? final GriddedSurface surface; @@ -44,7 +43,7 @@ public class InterfaceRuptureSet implements RuptureSet { this.data = builder.data; this.mfdTree = builder.mfdTree; - this.sections = builder.sections; + this.sectionIds = builder.sectionIds; this.surface = builder.surface; } @@ -54,15 +53,15 @@ public class InterfaceRuptureSet implements RuptureSet { } @Override - public int size() { - // TODO what should this be for fault and interface rupture sets?? - // a value based on the size of the Mfds?? - return 1; + public int id() { + return feature.id; } @Override - public int id() { - return feature.id; + public int size() { + // TODO what should this be ?? + // a value based on the size of the Mfds?? + return 1; } @Override @@ -87,8 +86,8 @@ public class InterfaceRuptureSet implements RuptureSet { @Override public String toString() { Map<Object, Object> data = Map.of( - "name", feature.name, - "id", feature.id, + "name", name(), + "id", id(), "feature", feature.source.toJson()); return getClass().getSimpleName() + " " + data; } @@ -104,7 +103,7 @@ public class InterfaceRuptureSet implements RuptureSet { private SourceFeature.Interface feature; private ModelData data; - private List<Integer> sections; + private List<Integer> sectionIds; private LogicTree<Mfd.Properties> mfdPropsTree; @@ -112,7 +111,7 @@ public class InterfaceRuptureSet implements RuptureSet { private LogicTree<Mfd> mfdTree; private GriddedSurface surface; - /* These will be validated when creating rupture set feature. */ + /* Validated and carried forward in rupture set feature. */ private String name; private Integer id; @@ -128,7 +127,7 @@ public class InterfaceRuptureSet implements RuptureSet { Builder sections(List<Integer> sections) { checkArgument(sections.size() >= 1); - this.sections = List.copyOf(sections); + this.sectionIds = List.copyOf(sections); return this; } @@ -144,14 +143,18 @@ public class InterfaceRuptureSet implements RuptureSet { return this; } + InterfaceRuptureSet build() { + validateAndInit("InterfaceRuptureSet.Builder"); + return new InterfaceRuptureSet(this); + } + private void validateAndInit(String label) { checkState(!built, "Single use builder"); - checkNotNull(sections, "%s section ID list", label); + checkNotNull(sectionIds, "%s section ID list", label); checkNotNull(data, "%s model data", label); checkNotNull(name, "%s name", label); checkNotNull(id, "%s id", label); - checkNotNull(mfdPropsTree, "%s MFD logic tree", label); // TODO temp checking props are always the same; @@ -175,16 +178,12 @@ public class InterfaceRuptureSet implements RuptureSet { built = true; } - InterfaceRuptureSet build() { - validateAndInit("InterfaceRuptureSet.Builder"); - return new InterfaceRuptureSet(this); - } - private SourceFeature.Interface createFeature() { - Map<Integer, SourceFeature.Interface> featureMap = data.interfaceFeatureMap().orElseThrow(); - checkState(featureMap.keySet().containsAll(sections)); + Map<Integer, SourceFeature.Interface> featureMap = + data.interfaceFeatureMap().orElseThrow(); + checkState(featureMap.keySet().containsAll(sectionIds)); - Feature f = joinFeatures(sections.stream() + Feature f = joinFeatures(sectionIds.stream() .map(featureMap::get) .map(feature -> feature.source) .collect(toList())); diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/ModelData.java b/src/main/java/gov/usgs/earthquake/nshmp/model/ModelData.java index b532573df348b61ba83764bef5498a5ddaab4167..56875ddeef4871d3ffc76bfad8f0f9295fecc2ff 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/ModelData.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/ModelData.java @@ -15,10 +15,6 @@ import gov.usgs.earthquake.nshmp.tree.LogicTree; * information used when parsing models and (2) static classes and methods used * when building MFDs. * - * Although ModelLoader will require certain resources in specific locations - * (e.g. the fault-sections directory), this class enforces that resources that - * can only exist in one location are only set once per instance. - * * @author U.S. Geological Survey */ class ModelData { @@ -121,7 +117,6 @@ class ModelData { } void interfaceFeatureMap(Map<Integer, SourceFeature.Interface> interfaceFeatureMap) { - checkState(this.interfaceFeatureMap.isEmpty()); this.interfaceFeatureMap = Optional.of(checkNotNull(interfaceFeatureMap)); } @@ -130,7 +125,6 @@ class ModelData { } void faultFeatureMap(Map<Integer, SourceFeature.NshmFault> faultFeatureMap) { - checkState(this.faultFeatureMap.isEmpty()); this.faultFeatureMap = Optional.of(checkNotNull(faultFeatureMap)); } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/ModelLoader.java b/src/main/java/gov/usgs/earthquake/nshmp/model/ModelLoader.java index 317f0e8f2f3b35219a471d25440e6a7dc58b2086..176de270dbb03dcd7009a80a32738bda8049c963 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/ModelLoader.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/ModelLoader.java @@ -6,8 +6,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static gov.usgs.earthquake.nshmp.model.ModelFiles.CALC_CONFIG; import static gov.usgs.earthquake.nshmp.model.ModelFiles.CLUSTER_SET; +import static gov.usgs.earthquake.nshmp.model.ModelFiles.FAULT_SOURCES; import static gov.usgs.earthquake.nshmp.model.ModelFiles.GRID_DATA_DIR; -import static gov.usgs.earthquake.nshmp.model.ModelFiles.GRID_SOURCES; import static gov.usgs.earthquake.nshmp.model.ModelFiles.MODEL_INFO; import static gov.usgs.earthquake.nshmp.model.ModelFiles.RUPTURE_SET; import static gov.usgs.earthquake.nshmp.model.ModelFiles.SOURCE_TREE; @@ -48,8 +48,11 @@ import com.google.common.collect.Iterables; import com.google.gson.JsonElement; import gov.usgs.earthquake.nshmp.calc.CalcConfig; +import gov.usgs.earthquake.nshmp.fault.FocalMech; +import gov.usgs.earthquake.nshmp.geo.json.Feature; import gov.usgs.earthquake.nshmp.geo.json.Properties; import gov.usgs.earthquake.nshmp.mfd.Mfd; +import gov.usgs.earthquake.nshmp.model.SourceFeature.Key; import gov.usgs.earthquake.nshmp.tree.Branch; import gov.usgs.earthquake.nshmp.tree.LogicGroup; import gov.usgs.earthquake.nshmp.tree.LogicTree; @@ -65,7 +68,7 @@ import gov.usgs.earthquake.nshmp.tree.LogicTree; abstract class ModelLoader { public static void main(String[] args) throws IOException { - Path testModel = Paths.get("../nshm-conus-2018"); + Path testModel = Paths.get("../nshm-conus-2018-tmp"); HazardModel model = ModelLoader.load(testModel); System.out.println(model); } @@ -123,9 +126,9 @@ abstract class ModelLoader { Path dir) { switch (setting) { - // case ACTIVE_CRUST: - // case STABLE_CRUST: - // return loadCrustalSources(dir); + case ACTIVE_CRUST: + // case STABLE_CRUST: + return loadCrustalSources(dir); case SUBDUCTION_INTERFACE: return ModelLoader.interfaceSources(dir); // case SUBDUCTION_SLAB: @@ -147,12 +150,12 @@ abstract class ModelLoader { if (!Files.isDirectory(path)) continue; String filename = checkNotNull(path.getFileName()).toString(); switch (filename) { - // case FAULT_SOURCES: - // trees.addAll(ModelLoader.faultSources(path, gmms)); - // break; - case GRID_SOURCES: - trees.addAll(ModelLoader.gridSources(path, gmms)); + case FAULT_SOURCES: + trees.addAll(ModelLoader.faultSources(path, gmms)); break; + // case GRID_SOURCES: + // trees.addAll(ModelLoader.gridSources(path, gmms)); + // break; // case ZONE_SOURCES: // trees.addAll(ModelLoader.zoneSources(path, gmms)); // break; @@ -233,6 +236,10 @@ abstract class ModelLoader { /* (3) Lastly, recurse into any nested directories. */ try (DirectoryStream<Path> nestedDirStream = newDirectoryStream(dir, NESTED_DIR_FILTER)) { for (Path path : nestedDirStream) { + // TODO temp clean + if (path.getFileName().toString().equals("ucerf3")) { + continue; + } trees.addAll(loadSourceDirectory(path, data)); } } catch (IOException ioe) { @@ -284,38 +291,111 @@ abstract class ModelLoader { Path geojson, ModelData data) { + SourceFeature.NshmFault feature = SourceFeature.newNshmFault(geojson); + + /* Possibly split on normal fault dip variants. */ + SourceConfig.Fault config = (SourceConfig.Fault) data.sourceConfig(); + boolean isNormal = FocalMech.fromRake(feature.rake) == FocalMech.NORMAL; + if (config.normalDipTree.isPresent() && isNormal) { + System.out.println("dip tree: " + root.relativize(geojson)); + return loadNormalDipTree(feature, data); + } + System.out.println(" source: " + root.relativize(geojson)); - SourceFeature.NshmFault fault = SourceFeature.newNshmFault(geojson); + + // SourceFeature.NshmFault feature = SourceFeature.newNshmFault(geojson); + data.faultFeatureMap(Map.of(feature.id, feature)); + + // FaultRuptureSet ruptureSet = FaultRuptureSet.builder() + // .modelData(data) + // .name(feature.name) + // .id(feature.id) + // .sections(List.of(feature.id)) + // .mfdTree(mfdTree) + // .build(); + + LogicTree<Path> root = LogicTree.singleton(geojson); + SourceTree.Builder treeBuilder = SourceTree.builder() + .name(feature.name) + .type(FAULT) + .gmms(data.gmms()) + .root(root); + + // .addLeaf(root.branches().get(0), ruptureSet) + // .build(); + + return loadSingleRuptureSet( + root.branches().get(0), + treeBuilder, + data, + feature); + } + + private SourceTree loadSingleRuptureSet( + Branch<Path> branch, + SourceTree.Builder treeBuilder, + ModelData data, + SourceFeature.NshmFault feature) { // TODO dummy mfds for now Mfd.Properties.Single mfdProps = Mfd.Properties.Single.dummy(); - // singleProps.m = 7.0; - // double rate = 0.001; - // Mfd.Properties mfdProps = new Mfd.Properties(Type.SINGLE, singleProps); + LogicTree<Mfd.Properties> mfdTree = LogicTree.singleton(mfdProps); - LogicTree<Mfd.Properties> mfdTree = LogicTree.<Mfd.Properties> builder() - .addBranch("singleton", mfdProps, 1.0) - .build(); + data.faultFeatureMap(Map.of(feature.id, feature)); FaultRuptureSet ruptureSet = FaultRuptureSet.builder() .modelData(data) - .name(fault.name) - .id(fault.id) - .sections(List.of(fault.id)) - .featureMap(Map.of(fault.id, fault)) + .name(feature.name) + .id(feature.id) + .sections(List.of(feature.id)) .mfdTree(mfdTree) .build(); - LogicTree<Path> root = LogicTree.singleton(geojson); - SourceTree tree = SourceTree.builder() - .name(fault.name) + return treeBuilder.addLeaf(branch, ruptureSet).build(); + } + + SourceTree loadNormalDipTree( + SourceFeature.NshmFault feature, + ModelData data) { + + SourceConfig.Fault config = (SourceConfig.Fault) data.sourceConfig(); + + // Feature source = GeoJson.from(geojson).toFeature(); + // Properties props = source.properties(); + double dip = feature.dip;// props.getDouble(Key.DIP).orElseThrow(); + String name = feature.name;// props.getString(Key.NAME).orElseThrow(); + + LogicTree<Double> dipTree = config.normalDipTree.orElseThrow(); + LogicTree<Path> dipPathTree = ModelUtil.toPathTree(dipTree); + + SourceTree.Builder treeBuilder = SourceTree.builder() + .name(name) .type(FAULT) .gmms(data.gmms()) - .root(root) - .addLeaf(root.branches().get(0), ruptureSet) - .build(); + .root(dipPathTree); + + // SourceFeature.NshmFault feature = SourceFeature.newNshmFault(geojson); + + // Properties.Builder props = Properties.fromFeature(source); + + for (int i = 0; i < dipTree.size(); i++) { + // for (Branch<Double> dipBranch : dipTree) { + Branch<Double> dipBranch = dipTree.branches().get(i); + int branchDip = (int) (dip + dipBranch.value()); + String branchName = String.format("%s [%s°]", name, dip); + Feature dipFeature = Feature.copyOf(feature.source) + .properties(Properties.fromFeature(feature.source) + .put(Key.NAME, name) + .put(Key.DIP, dip + dipBranch.value()) + .build()) + .build(); - return tree; + // createSingleRuptureSet + + processBranch(dipPathTree.branches().get(i), treeBuilder, data); + } + + return treeBuilder.build(); } @Override @@ -325,8 +405,7 @@ abstract class ModelLoader { System.out.println(" tree: " + root.relativize(dir)); LogicTree<Path> tree = readSourceTree(dir).orElseThrow(); - Map<Integer, SourceFeature.NshmFault> featureMap = readFaultSections(dir).orElseThrow(); - data.faultFeatureMap(featureMap); + data.faultFeatureMap(readFaultSections(dir).orElseThrow()); SourceTree.Builder treeBuilder = SourceTree.builder() .name(checkNotNull(dir.getFileName()).toString()) @@ -373,25 +452,21 @@ abstract class ModelLoader { } else { Path ruptureSetPath = dir.resolve(RUPTURE_SET); - boolean isRuptureSet = Files.exists(ruptureSetPath); + boolean isFaultRuptureSet = Files.exists(ruptureSetPath); - Path setPath = isRuptureSet + Path setPath = isFaultRuptureSet ? ruptureSetPath : dir.resolve(CLUSTER_SET); - if (isRuptureSet) { + if (isFaultRuptureSet) { - FaultRuptureSet frs = Deserialize.ruptureSet(setPath, data) - .featureMap(data.faultFeatureMap().orElseThrow()) - .modelData(data) + FaultRuptureSet frs = Deserialize.faultRuptureSet(setPath, data) .build(); treeBuilder.addLeaf(branch, frs); } else { - ClusterRuptureSet crs = Deserialize.clusterSet(setPath, data) - .featureMap(data.faultFeatureMap().orElseThrow()) - .modelData(data) + ClusterRuptureSet crs = Deserialize.clusterRuptureSet(setPath, data) .build(); treeBuilder.addLeaf(branch, crs); @@ -425,7 +500,7 @@ abstract class ModelLoader { ModelData data) { System.out.println(" source: " + root.relativize(geojson)); - SourceFeature.Interface fault = SourceFeature.newInterfaceSection(geojson); + SourceFeature.Interface feature = SourceFeature.newInterfaceSection(geojson); // TODO dummy mfds for now TODO TODO TODO System.out.println(" -- STOP -- this isnt working correctly"); @@ -437,16 +512,15 @@ abstract class ModelLoader { InterfaceRuptureSet ruptureSet = InterfaceRuptureSet.builder() .modelData(data) - .name(fault.name) - .id(fault.id) - .sections(List.of(fault.id)) - // .featureMap(Map.of(fault.id, fault)) + .name(feature.name) + .id(feature.id) + .sections(List.of(feature.id)) .mfdTree(mfdTree) .build(); LogicTree<Path> root = LogicTree.singleton(geojson); SourceTree tree = SourceTree.builder() - .name(fault.name) + .name(feature.name) .type(INTERFACE) .gmms(data.gmms()) .root(root) @@ -463,8 +537,7 @@ abstract class ModelLoader { System.out.println(" tree: " + root.relativize(dir)); LogicTree<Path> tree = readSourceTree(dir).orElseThrow(); - Map<Integer, SourceFeature.Interface> featureMap = readInterfaceSections(dir).orElseThrow(); - data.interfaceFeatureMap(featureMap); + data.interfaceFeatureMap(readInterfaceSections(dir).orElseThrow()); SourceTree.Builder treeBuilder = SourceTree.builder() .name(checkNotNull(dir.getFileName()).toString()) @@ -512,7 +585,6 @@ abstract class ModelLoader { Path ruptureSetPath = dir.resolve(RUPTURE_SET); InterfaceRuptureSet irs = Deserialize.interfaceRuptureSet(ruptureSetPath, data) - // .featureMap(data.interfaceFeatureMap().orElseThrow()) .build(); treeBuilder.addLeaf(branch, irs); } @@ -639,7 +711,7 @@ abstract class ModelLoader { */ LogicTree<Path> rateTree = data.gridRateTree().orElseThrow(); - LogicTree<Path> rateChildren = ModelUtil.rateToSourceTree(rateTree); + LogicTree<Path> rateChildren = ModelUtil.toPathTree(rateTree); treeBuilder.addBranches(branch, rateChildren); for (int i = 0; i < rateTree.branches().size(); i++) { diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/ModelUtil.java b/src/main/java/gov/usgs/earthquake/nshmp/model/ModelUtil.java index 383abbe498c1721bde43cbfb1eab4658253d3455..d3cb43aebf5b5478caf746bc7448a6f47407d9ac 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/ModelUtil.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/ModelUtil.java @@ -136,17 +136,47 @@ class ModelUtil { .toImmutable(); } + // TODO clean + // /* + // * Convert grid rate-tree (of paths to *.csv files) to a tree of + // pseudo-paths + // * to mimic branches in a source-tree. + // */ + // static LogicTree<Path> rateToPathTree(LogicTree<Path> rateTree) { + // LogicTree.Builder<Path> sourceTree = LogicTree.builder(); + // rateTree.forEach(branch -> sourceTree.addBranch( + // branch.id(), + // Path.of(branch.id()), + // branch.weight())); + // return sourceTree.build(); + // } + // + // /* + // * Convert normal fault dip-tree to a tree of pseudo-paths to mimic branches + // * in a source-tree. + // */ + // static LogicTree<Path> dipToPathTree(LogicTree<Double> dipTree) { + // LogicTree.Builder<Path> sourceTree = LogicTree.builder(); + // dipTree.forEach(branch -> sourceTree.addBranch( + // branch.id(), + // Path.of(branch.id()), + // branch.weight())); + // return sourceTree.build(); + // } + /* - * Convert grid rate-tree (of paths to *.csv files) to a tree of pseudo-paths - * to mimic branches in a source-tree. + * Convert any LogicTree to a tree of pseudo-paths based on the id() field of + * the supplied tree. This is used to mimic branches in a source-tree. + * Examples uses include conversion of a grid rate tree of paths to *.csv + * files or a fault slip variant tree. */ - static LogicTree<Path> rateToSourceTree(LogicTree<Path> rateTree) { - LogicTree.Builder<Path> sourceTree = LogicTree.builder(); - rateTree.forEach(branch -> sourceTree.addBranch( + static <T> LogicTree<Path> toPathTree(LogicTree<T> tree) { + LogicTree.Builder<Path> pathTree = LogicTree.builder(); + tree.forEach(branch -> pathTree.addBranch( branch.id(), Path.of(branch.id()), branch.weight())); - return sourceTree.build(); + return pathTree.build(); } /* diff --git a/src/main/java/gov/usgs/earthquake/nshmp/model/SourceConfig.java b/src/main/java/gov/usgs/earthquake/nshmp/model/SourceConfig.java index 672625b2130178c8ab114043b9917c71d6753b67..8692293c994fcb735c2a5b8bcfe88e1269cb6123 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/model/SourceConfig.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/model/SourceConfig.java @@ -31,6 +31,14 @@ abstract class SourceConfig { this.resource = resource; } + Fault getAsFault() { + return (Fault) this; + } + + Grid getAsGrid() { + return (Grid) this; + } + static class Fault extends SourceConfig { final double surfaceSpacing;