diff --git a/gradle/nshm.gradle b/gradle/nshm.gradle index c125f642a9a432ab3c473d8eaae3be7899c7a20a..2bcfe0831e6ac942d904f3b7f9d62b2609253667 100644 --- a/gradle/nshm.gradle +++ b/gradle/nshm.gradle @@ -100,7 +100,6 @@ task generateAlaska2023(type: JavaExec) { main = "gov.usgs.earthquake.nshmp.model.GenerateActual" } - // Generate CONUS 2018 for CI task generateConus2018(type: JavaExec) { description = "Generate conus-2018 acutal for CI/CD" diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/GenerateActual.java b/src/test/java/gov/usgs/earthquake/nshmp/model/GenerateActual.java index 4a9c54d1114efbee5f249eafb6a582df206ca2f9..8996fb07eab4d24e9aa3d09ff4f3f2248ab08e11 100644 --- a/src/test/java/gov/usgs/earthquake/nshmp/model/GenerateActual.java +++ b/src/test/java/gov/usgs/earthquake/nshmp/model/GenerateActual.java @@ -2,9 +2,14 @@ package gov.usgs.earthquake.nshmp.model; import java.io.IOException; import java.util.Optional; +import java.util.concurrent.ExecutionException; import gov.usgs.earthquake.nshmp.model.NshmTestUtils.Nshm; import gov.usgs.earthquake.nshmp.model.NshmTestUtils.NshmModel; +import gov.usgs.earthquake.nshmp.www.Application; + +import io.micronaut.context.ApplicationContext; +import io.micronaut.runtime.Micronaut; /** * Generate actual results to compare to expected results. @@ -15,10 +20,21 @@ import gov.usgs.earthquake.nshmp.model.NshmTestUtils.NshmModel; */ class GenerateActual { - public static void main(String[] args) throws IOException { + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException { Nshm nshm = NshmTests.NSHMS.get(System.getProperty("NSHM")); + + // Generate command line NshmModel nshmModel = NshmTestUtils.loadModel(nshm); NshmTestUtils.writeExpecteds(nshmModel, Optional.of(NshmTests.DATA_PATH)); nshmModel.exec.shutdown(); + + // Generate web + ApplicationContext context = Micronaut + .build("--model=" + nshm.modelPath()) + .mainClass(Application.class) + .start(); + NshmTestUtils.writeWebExpecteds(nshm, Optional.of(NshmTests.WEB_DATA_PATH)); + context.close(); } } diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java index 8b32caf6a58c1398beffbd37ac579701efd0d803..89852afa2adca428b55a8c4d794d7ad655cd53c1 100644 --- a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java +++ b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java @@ -16,6 +16,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger; @@ -37,7 +38,11 @@ import gov.usgs.earthquake.nshmp.calc.Site; import gov.usgs.earthquake.nshmp.data.XySequence; import gov.usgs.earthquake.nshmp.geo.Location; import gov.usgs.earthquake.nshmp.gmm.Imt; +import gov.usgs.earthquake.nshmp.www.Application; +import gov.usgs.earthquake.nshmp.www.hazard.HazardServiceUtils; +import io.micronaut.context.ApplicationContext; +import io.micronaut.runtime.Micronaut; import io.swagger.v3.core.util.Yaml; /** @@ -83,16 +88,50 @@ class NshmTestUtils { * Test a NSHM. * * @param nshm The NSHM to test + * @throws ExecutionException + * @throws InterruptedException */ - static void testNshm(Nshm nshm, Optional<Path> dataPath) { - NshmModel nshmModel = loadModel(nshm); + static void testNshm(Nshm nshm, Optional<Path> dataPath) + throws InterruptedException, ExecutionException { + Optional<NshmModel> nshmModel = Optional.empty(); + + if (dataPath.isEmpty()) { + nshmModel = Optional.of(loadModel(nshm)); + } + + for (NamedLocation location : nshm.locations()) { + LOGGER.info("Location: " + location.toString()); + compareCurves(nshm, location, nshmModel, dataPath); + } + + nshmModel.ifPresent(model -> model.exec.shutdown()); + } + + /** + * Test a NSHM. + * + * @param nshm The NSHM to test + * @throws ExecutionException + * @throws InterruptedException + */ + static void testWebNshm(Nshm nshm, Optional<Path> dataPath) + throws InterruptedException, ExecutionException { + + Optional<ApplicationContext> context = Optional.empty(); + + if (dataPath.isEmpty()) { + context = Optional.of(Micronaut + .build("--model=" + nshm.modelPath()) + .mainClass(Application.class) + .start()); + } for (NamedLocation location : nshm.locations()) { LOGGER.info("Location: " + location.toString()); - compareCurves(nshmModel, location, dataPath); + compareWebCurves(nshm, location, dataPath); } - nshmModel.exec.shutdown(); + context.ifPresent(ApplicationContext::close); } /** @@ -110,6 +149,18 @@ class NshmTestUtils { } } + static void writeWebExpecteds( + Nshm nshm, + Optional<Path> dataPath) throws InterruptedException, ExecutionException, IOException { + for (NamedLocation location : nshm.locations()) { + Map<String, XySequence> xyMap = HazardServiceUtils.generateActual(location, nshm.imts()); + String json = new StringBuilder(GSON.toJson(xyMap)) + .append(Text.NEWLINE) + .toString(); + writeExpected(nshm, location, json, dataPath); + } + } + private static void assertCurveEquals(XySequence expected, XySequence actual, double tol) { // IMLs close but not exact due to exp() transform assertArrayEquals( @@ -137,11 +188,28 @@ class NshmTestUtils { Double.valueOf(expected).equals(Double.valueOf(actual)); } - private static void compareCurves(NshmModel nshmModel, NamedLocation location, - Optional<Path> dataPath) { + private static void compareCurves( + Nshm nshm, + NamedLocation location, + Optional<NshmModel> nshmModel, + Optional<Path> dataPath) throws ExecutionException { + Map<String, XySequence> actual = dataPath.isPresent() && nshmModel.isEmpty() + ? readExpected(nshm, location, dataPath) : generateActual(nshmModel.get(), location); + Map<String, XySequence> expected = readExpected(nshm, location, Optional.empty()); + + for (String key : actual.keySet()) { + assertCurveEquals(expected.get(key), actual.get(key), TOLERANCE); + } + } + + private static void compareWebCurves( + Nshm nshm, + NamedLocation location, + Optional<Path> dataPath) throws InterruptedException, ExecutionException { Map<String, XySequence> actual = dataPath.isPresent() - ? readExpected(nshmModel, location, dataPath) : generateActual(nshmModel, location); - Map<String, XySequence> expected = readExpected(nshmModel, location, Optional.empty()); + ? readExpected(nshm, location, dataPath) + : HazardServiceUtils.generateActual(location, nshm.imts()); + Map<String, XySequence> expected = readExpected(nshm, location, Optional.empty()); for (String key : actual.keySet()) { assertCurveEquals(expected.get(key), actual.get(key), TOLERANCE); @@ -176,11 +244,11 @@ class NshmTestUtils { return xyMap; } - private static Map<String, XySequence> readExpected(NshmModel nshmModel, NamedLocation loc, + private static Map<String, XySequence> readExpected(Nshm nshm, NamedLocation loc, Optional<Path> dataPath) { Path resultPath = dataPath.orElse(DATA_PATH) - .resolve(nshmModel.nshm.modelName()) - .resolve(nshmModel.nshm.resultFilename(loc)); + .resolve(nshm.modelName()) + .resolve(nshm.resultFilename(loc)); JsonObject obj = null; try (BufferedReader br = Files.newBufferedReader(resultPath)) { diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java index 0c24c00cfaf3e0f54f8245c552655d4b5c900b82..38f8f37da8cf448fc88ad4829913ff5adb675e3e 100644 --- a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java +++ b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ExecutionException; import org.junit.jupiter.api.Test; @@ -26,6 +27,7 @@ import gov.usgs.earthquake.nshmp.site.NshmpSite; */ class NshmTests { static Path DATA_PATH = Paths.get("src/test/resources/e2e/actual"); + static Path WEB_DATA_PATH = Paths.get("src/test/resources/e2e/actual/web"); /* Alaska test sites */ private static final List<NamedLocation> ALASKA_LOCATIONS = List.of( @@ -126,55 +128,70 @@ class NshmTests { * Test Alaska 2007 NSHM * * To run test: ./gradlew testAlaska2007 + * @throws ExecutionException + * @throws InterruptedException */ @Test - final void testAlaska2007() throws IOException { + final void testAlaska2007() throws IOException, InterruptedException, ExecutionException { Nshm nshm = NSHMS.get("nshm-alaska-2007"); NshmTestUtils.testNshm(nshm, getDataPath(nshm)); + NshmTestUtils.testWebNshm(nshm, getWebDataPath(nshm)); } /** * Test Alaska 2023 NSHM * * To run test: ./gradlew testAlaska2023 + * @throws ExecutionException + * @throws InterruptedException */ @Test - final void testAlaska2023() throws IOException { + final void testAlaska2023() throws IOException, InterruptedException, ExecutionException { Nshm nshm = NSHMS.get("nshm-alaska-2023"); NshmTestUtils.testNshm(nshm, getDataPath(nshm)); + NshmTestUtils.testWebNshm(nshm, getWebDataPath(nshm)); } /** * Test CONUS 2018 NSHM * * To run test: ./gradlew testConus2018 + * @throws ExecutionException + * @throws InterruptedException */ @Test - final void testConus2018() throws IOException { + final void testConus2018() throws IOException, InterruptedException, ExecutionException { Nshm nshm = NSHMS.get("nshm-conus-2018"); NshmTestUtils.testNshm(nshm, getDataPath(nshm)); + NshmTestUtils.testWebNshm(nshm, getWebDataPath(nshm)); } /** * Test CONUS 2023 NSHM * * To run test: ./gradlew testConus2023 + * @throws ExecutionException + * @throws InterruptedException */ @Test - final void testConus2023() throws IOException { + final void testConus2023() throws IOException, InterruptedException, ExecutionException { Nshm nshm = NSHMS.get("nshm-conus-2023"); NshmTestUtils.testNshm(nshm, getDataPath(nshm)); + NshmTestUtils.testWebNshm(nshm, getWebDataPath(nshm)); } /** * Test Hawaii 2021 NSHM * * To run test: ./gradlew testHawaii2021 + * @throws ExecutionException + * @throws InterruptedException */ @Test - final void testHawaii2021() throws IOException { + final void testHawaii2021() throws IOException, InterruptedException, ExecutionException { Nshm nshm = NSHMS.get("nshm-hawaii-2021"); NshmTestUtils.testNshm(nshm, getDataPath(nshm)); + NshmTestUtils.testWebNshm(nshm, getWebDataPath(nshm)); } /** @@ -192,4 +209,9 @@ class NshmTests { return Files.exists(DATA_PATH.resolve(nshm.modelName())) ? Optional.of(DATA_PATH) : Optional.empty(); } + + private static Optional<Path> getWebDataPath(Nshm nshm) { + return Files.exists(DATA_PATH.resolve(nshm.modelName())) ? Optional.of(DATA_PATH) + : Optional.empty(); + } } diff --git a/src/test/java/gov/usgs/earthquake/nshmp/www/hazard/HazardServiceUtils.java b/src/test/java/gov/usgs/earthquake/nshmp/www/hazard/HazardServiceUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..d7649d099cd72867b6208e7193700c5791f90d36 --- /dev/null +++ b/src/test/java/gov/usgs/earthquake/nshmp/www/hazard/HazardServiceUtils.java @@ -0,0 +1,44 @@ +package gov.usgs.earthquake.nshmp.www.hazard; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import gov.usgs.earthquake.nshmp.NamedLocation; +import gov.usgs.earthquake.nshmp.calc.Hazard; +import gov.usgs.earthquake.nshmp.data.XySequence; +import gov.usgs.earthquake.nshmp.gmm.Imt; +import gov.usgs.earthquake.nshmp.www.hazard.HazardService.Request; + +import io.micronaut.http.HttpRequest; + +public class HazardServiceUtils { + + public static Map<String, XySequence> generateActual( + NamedLocation loc, + Set<Imt> imts) + throws InterruptedException, ExecutionException { + Request request = new Request( + HttpRequest.GET(""), + loc.location().longitude, + loc.location().latitude, + 760, + imts, + false, + false); + + Hazard hazard = HazardService.calcHazard(request); + + Map<String, XySequence> xyMap = hazard.curves().entrySet().stream() + .collect(Collectors.toMap( + e -> e.getKey().name(), + Entry::getValue, + (o1, o2) -> o1, + LinkedHashMap::new)); // preserve IMT enum order + + return xyMap; + } +}