From 10cd1d580d7ccfe8e117ffddf7ff3c669b2f7930 Mon Sep 17 00:00:00 2001
From: Peter Powers <pmpowers@usgs.gov>
Date: Wed, 1 Jun 2022 13:19:31 -0600
Subject: [PATCH] HazardModel reports Bounds; bounds required in model-info

---
 .../earthquake/nshmp/model/HazardModel.java   | 57 +++++++++++--------
 .../model/test-model/model-info.json          |  6 ++
 2 files changed, 39 insertions(+), 24 deletions(-)

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 bd5f14be..3d0044cc 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/model/HazardModel.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/model/HazardModel.java
@@ -12,7 +12,6 @@ import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.EnumMap;
 import java.util.EnumSet;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -25,14 +24,12 @@ import java.util.function.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import com.google.common.collect.Streams;
 import com.google.gson.annotations.SerializedName;
 
 import gov.usgs.earthquake.nshmp.calc.CalcConfig;
+import gov.usgs.earthquake.nshmp.geo.Bounds;
 import gov.usgs.earthquake.nshmp.geo.Location;
 import gov.usgs.earthquake.nshmp.geo.LocationList;
 import gov.usgs.earthquake.nshmp.geo.Locations;
@@ -61,30 +58,30 @@ public final class HazardModel implements Iterable<SourceTree> {
 
   private final Path root;
   private final String name;
-  private final CalcConfig config;
   private final Map<NehrpSiteClass, Double> siteClassMap;
-  private final Map<String, Double> bounds;
+  private final Bounds bounds;
+  private final CalcConfig config;
 
   private final Multimap<SourceType, RuptureSet<? extends Source>> ruptureSetMap;
   private final Set<TectonicSetting> settings;
   private final Map<TectonicSetting, MapRegion> mapRegionMap;
   private final SiteData siteData;
+  private final Set<Gmm> gmms;
 
   private final Multimap<TectonicSetting, SourceTree> treesMap;
   private final Map<Integer, SourceTree> idMap;
 
   private HazardModel(Builder builder) {
     this.root = builder.root;
-    this.name = builder.info.name;
+    this.name = builder.name;
+    this.siteClassMap = builder.siteClassMap;
+    this.bounds = builder.bounds;
     this.config = builder.config;
-    this.siteClassMap = Maps.immutableEnumMap(builder.info.siteClassMap);
-    this.bounds = builder.info.bounds != null
-        ? new HashMap<>(builder.info.bounds)
-        : new HashMap<>(); // TODO make immutable
     this.ruptureSetMap = builder.ruptureSetMap;
-    this.settings = Sets.immutableEnumSet(builder.settings);
-    this.mapRegionMap = Maps.immutableEnumMap(builder.mapRegionMap);
+    this.settings = builder.settings;
+    this.mapRegionMap = builder.mapRegionMap;
     this.siteData = builder.siteData;
+    this.gmms = builder.gmms;
     this.treesMap = builder.treesMap;
     this.idMap = builder.idMap;
   }
@@ -147,9 +144,7 @@ public final class HazardModel implements Iterable<SourceTree> {
    * The set of {@code Gmm}s used by this model.
    */
   public Set<Gmm> gmms() {
-    return Streams.stream(this)
-        .flatMap(tree -> tree.gmms().gmms().stream())
-        .collect(toCollection(() -> EnumSet.noneOf(Gmm.class)));
+    return EnumSet.copyOf(gmms);
   }
 
   /**
@@ -163,7 +158,7 @@ public final class HazardModel implements Iterable<SourceTree> {
    * The set of {@code TectonicSetting}s included in this model.
    */
   public Set<TectonicSetting> settings() {
-    return settings;
+    return EnumSet.copyOf(settings);
   }
 
   /**
@@ -188,13 +183,13 @@ public final class HazardModel implements Iterable<SourceTree> {
    * this model.
    */
   public Map<NehrpSiteClass, Double> siteClasses() {
-    return siteClassMap;
+    return new EnumMap<>(siteClassMap);
   }
 
   /**
    * The latitude and longitude range over which this model is applicable.
    */
-  public Map<String, Double> bounds() {
+  public Bounds bounds() {
     return bounds;
   }
 
@@ -248,12 +243,13 @@ public final class HazardModel implements Iterable<SourceTree> {
     boolean built = false;
 
     private Path root;
-    private Info info;
+    private String name;
+    private Map<NehrpSiteClass, Double> siteClassMap;
+    private Bounds bounds;
     CalcConfig config; // also accessible during model initialization
-    private SetMultimap<SourceType, RuptureSet<? extends Source>> ruptureSetMap;
 
+    private SetMultimap<SourceType, RuptureSet<? extends Source>> ruptureSetMap;
     private ImmutableSetMultimap.Builder<SourceType, RuptureSet<? extends Source>> ruptureMapBuilder;
-
     private Set<TectonicSetting> settings = EnumSet.noneOf(TectonicSetting.class);
     private Map<TectonicSetting, MapRegion> mapRegionMap = new EnumMap<>(TectonicSetting.class);
     private SiteData siteData;
@@ -261,6 +257,7 @@ public final class HazardModel implements Iterable<SourceTree> {
     private ImmutableListMultimap.Builder<TectonicSetting, SourceTree> treesMapBuilder;
     private Multimap<TectonicSetting, SourceTree> treesMap;
     private Map<Integer, SourceTree> idMap;
+    private Set<Gmm> gmms;
 
     // Not used but will be (uncertainty)
     private List<SourceTree> trees = new ArrayList<>();
@@ -272,7 +269,14 @@ public final class HazardModel implements Iterable<SourceTree> {
     }
 
     Builder info(Info info) {
-      this.info = checkNotNull(info);
+      checkNotNull(info);
+      this.name = info.name;
+      this.siteClassMap = new EnumMap<>(info.siteClassMap);
+      this.bounds = Bounds.create(
+          info.bounds.get("min-latitude"),
+          info.bounds.get("min-longitude"),
+          info.bounds.get("max-latitude"),
+          info.bounds.get("max-longitude"));
       return this;
     }
 
@@ -308,7 +312,9 @@ public final class HazardModel implements Iterable<SourceTree> {
 
     private void validateState(String mssgID) {
       checkState(!built, "This %s instance as already been used", mssgID);
-      checkState(info != null, "%s info not set", mssgID);
+      checkState(name != null, "%s name not set", mssgID);
+      checkState(siteClassMap != null, "%s siteClassMap not set", mssgID);
+      checkState(bounds != null, "%s bounds not set", mssgID);
       checkState(config != null, "%s config not set", mssgID);
       checkState(ruptureSetMap.size() > 0, "%s has no source sets", mssgID);
       checkState(settings.size() > 0, "%s has no tectonic settings", mssgID);
@@ -325,6 +331,9 @@ public final class HazardModel implements Iterable<SourceTree> {
           .collect(toUnmodifiableMap(
               SourceTree::id,
               Function.identity()));
+      gmms = treesMap.values().stream()
+          .flatMap(tree -> tree.gmms().gmms().stream())
+          .collect(toCollection(() -> EnumSet.noneOf(Gmm.class)));
       validateState(ID);
       return new HazardModel(this);
     }
diff --git a/src/test/resources/model/test-model/model-info.json b/src/test/resources/model/test-model/model-info.json
index a6da9bd5..67cec1ef 100644
--- a/src/test/resources/model/test-model/model-info.json
+++ b/src/test/resources/model/test-model/model-info.json
@@ -10,5 +10,11 @@
     "D": 260,
     "DE": 185,
     "E": 150
+  },
+  "bounds": {
+    "min-latitude": 24.6,
+    "min-longitude": -125.0,
+    "max-latitude": 50.0,
+    "max-longitude": -65.0
   }
 }
-- 
GitLab