diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5c0fd36e28ace78c9606115349710516527660d6..da74d6a8241d78244d04d9766f967d5d2a409c74 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,10 +23,12 @@ stages: .templates: adjust-image-names-haz: &adjust-image-names-haz |- + DOCKERFILE="Dockerfile"; IMAGE_NAME=${IMAGE_NAME_HAZ/:master/:latest}; - INTERNAL_IMAGE_NAME=${CI_REGISTRY_IMAGE}/${IMAGE_NAME_WS}; + INTERNAL_IMAGE_NAME=${CI_REGISTRY_IMAGE}/${IMAGE_NAME_HAZ}; adjust-image-names-ws: &adjust-image-names-ws |- - IMAGE_NAME=${IMAGE_NAME_HAZ/:master/:latest}; + DOCKERFILE="ws.Dockerfile"; + IMAGE_NAME=${IMAGE_NAME_WS/:master/:latest}; INTERNAL_IMAGE_NAME=${CI_REGISTRY_IMAGE}/${IMAGE_NAME_WS}; ssh-key: &ssh-key |- eval $(ssh-agent -s); @@ -50,7 +52,11 @@ stages: - apk add git; - *ssh-key - mkdir ${DOCKER_DIR} - - docker build --build-arg ssh_private_key="${SSH_PRIVATE_KEY}" -t local/${IMAGE_NAME} . + - | + docker build \ + --build-arg ssh_private_key="${SSH_PRIVATE_KEY}" \ + -f ${DOCKERFILE} \ + -t local/${IMAGE_NAME} . - docker save local/${IMAGE_NAME} > ${DOCKER_TAR} artifacts: paths: @@ -64,7 +70,9 @@ stages: - master@ghsc/nshmp/nshmp-haz-v2 - tags@ghsc/nshmp/nshmp-haz-v2 script: - - echo "${CHS_PASSWORD}" | docker login --username ${CHS_USERNAME} --password-stdin ${CODE_REGISTRY} + - | + echo "${CHS_PASSWORD}" | \ + docker login --username ${CHS_USERNAME} --password-stdin ${CODE_REGISTRY} - docker load -i ${DOCKER_TAR} - docker tag local/${IMAGE_NAME} ${INTERNAL_IMAGE_NAME} - docker push ${INTERNAL_IMAGE_NAME} @@ -186,15 +194,11 @@ Build Haz Image: extends: .docker-build before_script: - *adjust-image-names-haz - variables: - IMAGE_NAME: ${IMAGE_NAME_HAZ} Build WS Image: extends: .docker-build before_script: - *adjust-image-names-ws - variables: - IMAGE_NAME: ${IMAGE_NAME_WS} #### # Stage: Publish diff --git a/scripts/docker-entrypoint.ws.sh b/scripts/docker-entrypoint.ws.sh index d90d2ce27aacceb5b16a409b90b7f61a0afeb68e..e7e99aaf0639001c91fe92d01dc49b1e8cd39d7a 100644 --- a/scripts/docker-entrypoint.ws.sh +++ b/scripts/docker-entrypoint.ws.sh @@ -6,14 +6,14 @@ exit_status=${?}; [ "${exit_status}" -eq 0 ] || exit "${exit_status}"; # Download models to use -get_models "${MODEL}" "${NSHM_VERSION}"; +model_path=$(get_models "${MODEL}" "${NSHM_VERSION}"); exit_status=${?}; check_exit_status ${exit_status}; # Run web services java -jar "${PROJECT}-ws.jar" \ "-Dmicronaut.server.context-path=${CONTEXT_PATH}" \ - --model="${MODEL}"; + --models="${model_path}"; exit_status=${?}; check_exit_status ${exit_status}; diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/BaseModel.java b/src/main/java/gov/usgs/earthquake/nshmp/www/BaseModel.java deleted file mode 100644 index 5db87cbbb8431825e75c4a4c1ae44b2197bd7c2a..0000000000000000000000000000000000000000 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/BaseModel.java +++ /dev/null @@ -1,92 +0,0 @@ -package gov.usgs.earthquake.nshmp.www; - -import static gov.usgs.earthquake.nshmp.calc.Vs30.VS_1150; -import static gov.usgs.earthquake.nshmp.calc.Vs30.VS_180; -import static gov.usgs.earthquake.nshmp.calc.Vs30.VS_2000; -import static gov.usgs.earthquake.nshmp.calc.Vs30.VS_259; -import static gov.usgs.earthquake.nshmp.calc.Vs30.VS_360; -import static gov.usgs.earthquake.nshmp.calc.Vs30.VS_537; -import static gov.usgs.earthquake.nshmp.calc.Vs30.VS_760; -import static gov.usgs.earthquake.nshmp.gmm.Imt.PGA; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA0P1; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA0P2; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA0P3; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA0P5; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA0P75; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA1P0; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA2P0; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA3P0; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA4P0; -import static gov.usgs.earthquake.nshmp.gmm.Imt.SA5P0; - -import java.nio.file.Paths; -import java.util.EnumSet; -import java.util.Set; - -import com.google.common.collect.Sets; - -import gov.usgs.earthquake.nshmp.calc.Vs30; -import gov.usgs.earthquake.nshmp.gmm.Imt; - -public enum BaseModel { - - AK_2007( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA1P0, SA2P0), - EnumSet.of(VS_760)), - - CEUS_2008( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA1P0, SA2P0), - EnumSet.of(VS_760, VS_2000)), - - WUS_2008( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA0P75, SA1P0, SA2P0, SA3P0), - EnumSet.of(VS_1150, VS_760, VS_537, VS_360, VS_259, VS_180)), - - CEUS_2014( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA1P0, SA2P0), - EnumSet.of(VS_760, VS_2000)), - - WUS_2014( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA0P75, SA1P0, SA2P0, SA3P0), - EnumSet.of(VS_1150, VS_760, VS_537, VS_360, VS_259, VS_180)), - - WUS_2014B( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA0P75, SA1P0, SA2P0, SA3P0, SA4P0, SA5P0), - EnumSet.of(VS_1150, VS_760, VS_537, VS_360, VS_259, VS_180)), - - CEUS_2018( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA0P75, SA1P0, SA2P0, SA3P0, SA4P0, SA5P0), - EnumSet.of(VS_1150, VS_760, VS_537, VS_360, VS_259, VS_180)), - - WUS_2018( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA0P75, SA1P0, SA2P0, SA3P0, SA4P0, SA5P0), - EnumSet.of(VS_1150, VS_760, VS_537, VS_360, VS_259, VS_180)), - - HI_2020( - EnumSet.of(PGA, SA0P1, SA0P2, SA0P3, SA0P5, SA0P75, SA1P0, SA2P0, SA3P0, SA5P0), - EnumSet.of(VS_1150, VS_760, VS_537, VS_360, VS_259, VS_180)); - - private static final String MODEL_DIR = "models"; - - public final Set<Imt> imts; - public final Set<Vs30> vs30s; - - public final String path; - public final String year; - - private BaseModel(Set<Imt> imts, Set<Vs30> vs30s) { - this.imts = Sets.immutableEnumSet(imts); - this.vs30s = Sets.immutableEnumSet(vs30s); - var region = deriveRegion(name()); - year = name().substring(name().lastIndexOf('_') + 1); - path = Paths.get(MODEL_DIR) - .resolve(region.toLowerCase()) - .resolve(year.toLowerCase()) - .toString(); - } - - private static String deriveRegion(String s) { - return s.startsWith("AK") ? "AK" : s.startsWith("WUS") ? "WUS" - : s.startsWith("HI") ? "HI" : "CEUS"; - } -} diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/Model.java b/src/main/java/gov/usgs/earthquake/nshmp/www/Model.java deleted file mode 100644 index d5ad0d9e9272d37b9cd31d55858dfd4d8ed32368..0000000000000000000000000000000000000000 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/Model.java +++ /dev/null @@ -1,54 +0,0 @@ -package gov.usgs.earthquake.nshmp.www; - -import java.util.Set; - -import gov.usgs.earthquake.nshmp.www.meta.Region; - -public enum Model { - - AK_2007(Set.of(BaseModel.AK_2007)), - - CONUS_2008(Set.of(BaseModel.CEUS_2008, BaseModel.WUS_2008)), - - CONUS_2014(Set.of(BaseModel.CEUS_2014, BaseModel.WUS_2014)), - - CONUS_2014B(Set.of(BaseModel.CEUS_2014, BaseModel.WUS_2014B)), - - CONUS_2018(Set.of(BaseModel.CEUS_2018, BaseModel.WUS_2018)), - - HI_2020(Set.of(BaseModel.HI_2020)); - - private final String label; - private final String year; - private final Set<BaseModel> models; - private final Region region; - - private Model(Set<BaseModel> models) { - year = name().substring(name().lastIndexOf("_") + 1); - region = deriveRegion(name()); - label = String.format("%s %s Hazard Model", year, region.label); - this.models = models; - } - - public String label() { - return label; - } - - public Set<BaseModel> models() { - return Set.copyOf(models); - } - - public Region region() { - return region; - } - - public String year() { - return year; - } - - private Region deriveRegion(String region) { - return region.startsWith("AK") ? Region.AK - : region.startsWith("HI") ? Region.HI : Region.CONUS; - } - -} diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/meta/MetaUtil.java b/src/main/java/gov/usgs/earthquake/nshmp/www/meta/MetaUtil.java index fa3f6f87f1dae3647fbc7fe662f22b59d78ebd6f..d5b961201f5bc96f1c8f3814db20581756a669c9 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/meta/MetaUtil.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/meta/MetaUtil.java @@ -97,6 +97,10 @@ public final class MetaUtil { public static final class DoubleSerializer implements JsonSerializer<Double> { @Override public JsonElement serialize(Double d, Type type, JsonSerializationContext context) { + if (Double.isNaN(d)) { + return null; + } + double dOut = Double.valueOf(String.format("%.8g", d)); return new JsonPrimitive(dOut); } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/DeaggEpsilonService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/DeaggEpsilonService.java index 1036e20e12320af73e4830aa34ff4da55e72fef0..9722ce1189313ce4e591df33987cad63f296f2f0 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/DeaggEpsilonService.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/DeaggEpsilonService.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Properties; import java.util.concurrent.ExecutionException; import java.util.function.Function; -import java.util.logging.Logger; import com.google.common.collect.ImmutableList; import com.google.common.io.Resources; @@ -19,13 +18,13 @@ import gov.usgs.earthquake.nshmp.calc.CalcConfig; import gov.usgs.earthquake.nshmp.calc.Deaggregation; import gov.usgs.earthquake.nshmp.calc.Site; import gov.usgs.earthquake.nshmp.calc.Vs30; +import gov.usgs.earthquake.nshmp.eq.model.HazardModel; import gov.usgs.earthquake.nshmp.geo.Location; import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.internal.www.NshmpMicronautServlet.UrlHelper; import gov.usgs.earthquake.nshmp.internal.www.Response; import gov.usgs.earthquake.nshmp.internal.www.WsUtils; import gov.usgs.earthquake.nshmp.internal.www.meta.Status; -import gov.usgs.earthquake.nshmp.www.BaseModel; import gov.usgs.earthquake.nshmp.www.DeaggEpsilonController; import gov.usgs.earthquake.nshmp.www.meta.Metadata; import gov.usgs.earthquake.nshmp.www.services.ServicesUtil.Key; @@ -45,7 +44,6 @@ public final class DeaggEpsilonService { /* Developer notes: See HazardService. */ private static final String NAME = "Epsilon Deaggregation"; - private static final Logger LOGGER = Logger.getLogger(DeaggEpsilonService.class.getName()); private static URL basinUrl; public static void init() { @@ -77,7 +75,6 @@ public final class DeaggEpsilonService { public static HttpResponse<String> handleDoGetDeaggEpsilon(Query query, UrlHelper urlHelper) { try { var timer = ServletUtil.timer(); - LOGGER.info(NAME + " - Request:\n" + ServletUtil.GSON.toJson(query)); if (query.isNull()) { return HazardService.handleDoGetUsage(urlHelper); @@ -87,10 +84,9 @@ public final class DeaggEpsilonService { var data = new RequestData(query, Vs30.fromValue(query.vs30)); var response = process(data, timer, urlHelper); var svcResponse = ServletUtil.GSON.toJson(response); - LOGGER.info(NAME + " - Response:\n" + svcResponse); return HttpResponse.ok(svcResponse); } catch (Exception e) { - return ServicesUtil.handleError(e, NAME, LOGGER, urlHelper); + return ServicesUtil.handleError(e, NAME, urlHelper); } } @@ -155,12 +151,10 @@ public final class DeaggEpsilonService { } } - static class ConfigFunction implements Function<BaseModel, CalcConfig> { + static class ConfigFunction implements Function<HazardModel, CalcConfig> { @Override - public CalcConfig apply(BaseModel baseModel) { - var hazardModel = ServletUtil.hazardModels().get(baseModel); - var configBuilder = CalcConfig.copyOf(hazardModel.config()); - configBuilder.imts(baseModel.imts); + public CalcConfig apply(HazardModel model) { + var configBuilder = CalcConfig.copyOf(model.config()); return configBuilder.build(); } } @@ -206,7 +200,7 @@ public final class DeaggEpsilonService { @SuppressWarnings("unused") private static final class ResponseMetadata { - final SourceModel model; + final List<SourceModel> models; final double longitude; final double latitude; final String imt; @@ -218,7 +212,7 @@ public final class DeaggEpsilonService { final Object εbins; ResponseMetadata(Deaggregation deagg, RequestData request, Imt imt) { - this.model = request.model; + this.models = request.models; this.longitude = request.longitude; this.latitude = request.latitude; this.imt = imt.toString(); diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/HazardService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/HazardService.java index 4039651427c294977b67c1a5ba36d224bdc90e52..8b36bc0bd977c3d5e13f53c7b57257cab14d07a3 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/HazardService.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/HazardService.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.function.Function; -import java.util.logging.Logger; import gov.usgs.earthquake.nshmp.calc.CalcConfig; import gov.usgs.earthquake.nshmp.calc.Hazard; @@ -17,6 +16,7 @@ import gov.usgs.earthquake.nshmp.calc.Site; import gov.usgs.earthquake.nshmp.calc.Vs30; import gov.usgs.earthquake.nshmp.data.MutableXySequence; import gov.usgs.earthquake.nshmp.data.XySequence; +import gov.usgs.earthquake.nshmp.eq.model.HazardModel; import gov.usgs.earthquake.nshmp.eq.model.SourceType; import gov.usgs.earthquake.nshmp.geo.Location; import gov.usgs.earthquake.nshmp.gmm.Imt; @@ -24,7 +24,6 @@ import gov.usgs.earthquake.nshmp.internal.www.NshmpMicronautServlet.UrlHelper; import gov.usgs.earthquake.nshmp.internal.www.Response; import gov.usgs.earthquake.nshmp.internal.www.WsUtils; import gov.usgs.earthquake.nshmp.internal.www.meta.Status; -import gov.usgs.earthquake.nshmp.www.BaseModel; import gov.usgs.earthquake.nshmp.www.HazardController; import gov.usgs.earthquake.nshmp.www.meta.Metadata; import gov.usgs.earthquake.nshmp.www.services.ServicesUtil.Key; @@ -51,7 +50,6 @@ public final class HazardService { */ private static final String NAME = "Hazard Service"; - private static final Logger LOGGER = Logger.getLogger(HazardService.class.getName()); /** * Handler for {@link HazardController#doGetUsage}. Returns the usage for the @@ -61,14 +59,12 @@ public final class HazardService { */ public static HttpResponse<String> handleDoGetUsage(UrlHelper urlHelper) { try { - LOGGER.info(NAME + " - Request:\n" + urlHelper.url); var usage = new SourceServices.ResponseData(); var response = new Response<>(Status.USAGE, NAME, urlHelper.url, usage, urlHelper); var svcResponse = ServletUtil.GSON.toJson(response); - LOGGER.info(NAME + " - Response:\n" + svcResponse); return HttpResponse.ok(svcResponse); } catch (Exception e) { - return ServicesUtil.handleError(e, NAME, LOGGER, urlHelper); + return ServicesUtil.handleError(e, NAME, urlHelper); } } @@ -82,7 +78,6 @@ public final class HazardService { public static HttpResponse<String> handleDoGetHazard(Query query, UrlHelper urlHelper) { try { var timer = ServletUtil.timer(); - LOGGER.info(NAME + " - Request:\n" + ServletUtil.GSON.toJson(query)); if (query.isNull()) { return handleDoGetUsage(urlHelper); @@ -92,10 +87,9 @@ public final class HazardService { var data = new RequestData(query, Vs30.fromValue(query.vs30)); var response = process(data, timer, urlHelper); var svcResponse = ServletUtil.GSON.toJson(response); - LOGGER.info(NAME + " - Response:\n" + svcResponse); return HttpResponse.ok(svcResponse); } catch (Exception e) { - return ServicesUtil.handleError(e, NAME, LOGGER, urlHelper); + return ServicesUtil.handleError(e, NAME, urlHelper); } } @@ -115,12 +109,10 @@ public final class HazardService { .build(); } - static class ConfigFunction implements Function<BaseModel, CalcConfig> { + static class ConfigFunction implements Function<HazardModel, CalcConfig> { @Override - public CalcConfig apply(BaseModel baseModel) { - var hazardModel = ServletUtil.hazardModels().get(baseModel); - var configBuilder = CalcConfig.copyOf(hazardModel.config()); - configBuilder.imts(baseModel.imts); + public CalcConfig apply(HazardModel model) { + var configBuilder = CalcConfig.copyOf(model.config()); return configBuilder.build(); } } @@ -173,7 +165,7 @@ public final class HazardService { @SuppressWarnings("unused") private static final class ResponseMetadata { - final SourceModel model; + final List<SourceModel> models; final double latitude; final double longitude; final Imt imt; @@ -182,7 +174,7 @@ public final class HazardService { final String ylabel = "Annual Frequency of Exceedence"; ResponseMetadata(RequestData request, Imt imt) { - model = new SourceModel(ServletUtil.installedModel()); + models = SourceModel.getList(); latitude = request.latitude; longitude = request.longitude; this.imt = imt; diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java index d88510f5baf37aa7d3ddd9c55f065365e680ee6c..ada84547e6c40a6e5be1d0173e54f341d7a3e8aa 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; -import java.util.logging.Logger; import java.util.stream.Collectors; import com.google.common.util.concurrent.ListenableFuture; @@ -48,7 +47,6 @@ public final class RateService { * WUS models. */ - private static final Logger LOGGER = Logger.getLogger(RateService.class.getName()); private static final String TOTAL_KEY = "Total"; /** @@ -64,7 +62,7 @@ public final class RateService { var svcResponse = ServletUtil.GSON.toJson(response); return HttpResponse.ok(String.format(svcResponse, urlHelper.urlPrefix, urlHelper.urlPrefix)); } catch (Exception e) { - return ServicesUtil.handleError(e, service.name, LOGGER, urlHelper); + return ServicesUtil.handleError(e, service.name, urlHelper); } } @@ -83,7 +81,6 @@ public final class RateService { try { var timer = ServletUtil.timer(); - LOGGER.info(service.name + " - Request:\n" + ServletUtil.GSON.toJson(query)); if (query.isNull()) { return handleDoGetUsage(service, urlHelper); @@ -93,10 +90,9 @@ public final class RateService { var requestData = new RequestData(query); var response = processRequest(service, requestData, urlHelper, timer); var svcResponse = ServletUtil.GSON.toJson(response); - LOGGER.info(service.name + " - Response:\n" + svcResponse); return HttpResponse.ok(svcResponse); } catch (Exception e) { - return ServicesUtil.handleError(e, service.name, LOGGER, urlHelper); + return ServicesUtil.handleError(e, service.name, urlHelper); } } @@ -128,8 +124,8 @@ public final class RateService { * probability service has been called. */ - for (var entry : ServletUtil.hazardModels().entrySet()) { - var rate = process(service, entry.getValue(), site, data.distance, data.timespan); + for (var model : ServletUtil.hazardModels()) { + var rate = process(service, model, site, data.distance, data.timespan); futureRates.add(rate); } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServicesUtil.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServicesUtil.java index f3ef2cb6e46c2893e78789beecd021866731255d..dcc95dd1e77ba202a4de848f88d0ce7ca92cce23 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServicesUtil.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServicesUtil.java @@ -1,9 +1,9 @@ package gov.usgs.earthquake.nshmp.www.services; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.Function; -import java.util.logging.Logger; import java.util.stream.Collectors; import com.google.gson.GsonBuilder; @@ -12,11 +12,11 @@ import gov.usgs.earthquake.nshmp.calc.CalcConfig; import gov.usgs.earthquake.nshmp.calc.Hazard; import gov.usgs.earthquake.nshmp.calc.HazardCalcs; import gov.usgs.earthquake.nshmp.calc.Site; +import gov.usgs.earthquake.nshmp.eq.model.HazardModel; import gov.usgs.earthquake.nshmp.internal.www.NshmpMicronautServlet.UrlHelper; import gov.usgs.earthquake.nshmp.internal.www.Response; import gov.usgs.earthquake.nshmp.internal.www.WsUtils; import gov.usgs.earthquake.nshmp.internal.www.meta.Status; -import gov.usgs.earthquake.nshmp.www.BaseModel; import gov.usgs.earthquake.nshmp.www.services.SourceServices.SourceModel; import io.micronaut.http.HttpResponse; @@ -26,25 +26,23 @@ class ServicesUtil { static HttpResponse<String> handleError( Throwable e, String name, - Logger logger, UrlHelper urlHelper) { var msg = e.getMessage() + " (see logs)"; var svcResponse = new Response<>(Status.ERROR, name, urlHelper.url, msg, urlHelper); var gson = new GsonBuilder().setPrettyPrinting().create(); var response = gson.toJson(svcResponse); - logger.severe(name + " -\n" + response); e.printStackTrace(); return HttpResponse.serverError(response); } static Hazard calcHazard( - Function<BaseModel, CalcConfig> configFunction, + Function<HazardModel, CalcConfig> configFunction, Function<CalcConfig, Site> siteFunction) throws InterruptedException, ExecutionException { - var futuresList = ServletUtil.installedModel().models().stream() - .map(baseModel -> { - var config = configFunction.apply(baseModel); + var futuresList = ServletUtil.hazardModels().stream() + .map(model -> { + var config = configFunction.apply(model); var site = siteFunction.apply(config); - return calcHazard(baseModel, config, site); + return calcHazard(model, config, site); }) .collect(Collectors.toList()); @@ -82,12 +80,12 @@ class ServicesUtil { } static class ServiceRequestData { - public final SourceModel model; + public final List<SourceModel> models; public final double longitude; public final double latitude; public ServiceRequestData(ServiceQueryData query) { - model = new SourceModel(ServletUtil.installedModel()); + models = SourceModel.getList(); longitude = query.longitude; latitude = query.latitude; } @@ -126,13 +124,13 @@ class ServicesUtil { } private static CompletableFuture<Hazard> calcHazard( - BaseModel baseModel, + HazardModel model, CalcConfig config, Site site) { return CompletableFuture .supplyAsync( () -> HazardCalcs.hazard( - ServletUtil.hazardModels().get(baseModel), config, site, ServletUtil.CALC_EXECUTOR), + model, config, site, ServletUtil.CALC_EXECUTOR), ServletUtil.TASK_EXECUTOR); } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServletUtil.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServletUtil.java index e11d2e22e19cf7f4c0e74453c0d8be5c1d287fdf..aa0ad2b1c0d5c6dc74c640b3519275fc9a65d0e8 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServletUtil.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/ServletUtil.java @@ -2,17 +2,23 @@ package gov.usgs.earthquake.nshmp.www.services; import static java.lang.Runtime.getRuntime; +import java.io.IOException; +import java.lang.reflect.Type; import java.net.URI; import java.net.URL; import java.nio.file.FileSystem; import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.time.format.DateTimeFormatter; -import java.util.EnumMap; +import java.util.ArrayList; import java.util.HashMap; -import java.util.Map; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -21,6 +27,10 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; import gov.usgs.earthquake.nshmp.calc.Site; import gov.usgs.earthquake.nshmp.calc.ValueFormat; @@ -28,8 +38,6 @@ import gov.usgs.earthquake.nshmp.calc.Vs30; import gov.usgs.earthquake.nshmp.eq.model.HazardModel; import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.internal.www.meta.ParamType; -import gov.usgs.earthquake.nshmp.www.BaseModel; -import gov.usgs.earthquake.nshmp.www.Model; import gov.usgs.earthquake.nshmp.www.meta.MetaUtil; import gov.usgs.earthquake.nshmp.www.meta.Region; @@ -59,11 +67,11 @@ public class ServletUtil { static long hitCount = 0; static long missCount = 0; - @Value("${nshmp-haz.installed-model}") - private Model model; + @Value("${nshmp-haz.model-path}") + private Path modelPath; - private static Model INSTALLED_MODEL; - private static Map<BaseModel, HazardModel> HAZARD_MODELS = new EnumMap<>(BaseModel.class); + private static List<HazardModel> HAZARD_MODELS = new ArrayList<>(); + private static final String MODEL_INFO = "model-info.json"; static { /* TODO modified for deagg-epsilon branch; should be context var */ @@ -78,18 +86,15 @@ public class ServletUtil { .registerTypeAdapter(Double.class, new MetaUtil.DoubleSerializer()) .registerTypeAdapter(ParamType.class, new MetaUtil.ParamTypeSerializer()) .registerTypeAdapter(Site.class, new MetaUtil.SiteSerializer()) + .registerTypeHierarchyAdapter(Path.class, new PathConverter()) .disableHtmlEscaping() .serializeNulls() .setPrettyPrinting() .create(); } - static Model installedModel() { - return INSTALLED_MODEL; - } - - static Map<BaseModel, HazardModel> hazardModels() { - return HAZARD_MODELS; + static List<HazardModel> hazardModels() { + return List.copyOf(HAZARD_MODELS); } @EventListener @@ -100,17 +105,16 @@ public class ServletUtil { @EventListener void startup(StartupEvent event) { - INSTALLED_MODEL = model; - - model.models().forEach(baseModel -> { - HAZARD_MODELS.put(baseModel, loadModel(baseModel)); - }); - - HAZARD_MODELS = Map.copyOf(HAZARD_MODELS); + try { + var modelFinder = new ModelFinder(); + Files.walkFileTree(modelPath, modelFinder); + modelFinder.paths().forEach(path -> HAZARD_MODELS.add(loadModel(path))); + } catch (IOException e) { + throw new RuntimeException(e); + } } - private HazardModel loadModel(BaseModel model) { - Path path; + private HazardModel loadModel(Path path) { URL url; URI uri; String uriString; @@ -118,7 +122,7 @@ public class ServletUtil { FileSystem fs; try { - url = Paths.get(model.path).toUri().toURL(); + url = path.toUri().toURL(); uri = new URI(url.toString().replace(" ", "%20")); uriString = uri.toString(); @@ -148,7 +152,6 @@ public class ServletUtil { } return HazardModel.load(path); - } catch (Exception e) { throw new RuntimeException(e); } @@ -180,4 +183,38 @@ public class ServletUtil { } } + private static class ModelFinder extends SimpleFileVisitor<Path> { + private List<Path> paths; + + ModelFinder() { + paths = new ArrayList<>(); + } + + List<Path> paths() { + return List.copyOf(paths); + } + + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { + var fileName = path.getFileName(); + + if (fileName != null && fileName.toString().equals(MODEL_INFO)) { + paths.add(path.getParent()); + } + + return FileVisitResult.CONTINUE; + } + } + + private static class PathConverter implements JsonSerializer<Path> { + + @Override + public JsonElement serialize( + Path path, + Type type, + JsonSerializationContext context) { + return new JsonPrimitive(path.toAbsolutePath().normalize().toString()); + } + } + } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java index 99c80fb53d9eb1befd88f6ed6f7bd379ededb303..25ad6451a0d28d21c9838a9ea213044653de9b34 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java @@ -4,7 +4,6 @@ import java.lang.reflect.Type; import java.util.EnumSet; import java.util.List; import java.util.Set; -import java.util.logging.Logger; import java.util.stream.Collectors; import com.google.gson.Gson; @@ -14,15 +13,16 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import gov.usgs.earthquake.nshmp.calc.CalcConfig; import gov.usgs.earthquake.nshmp.calc.Vs30; +import gov.usgs.earthquake.nshmp.eq.model.HazardModel; +import gov.usgs.earthquake.nshmp.gmm.Gmm; import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.internal.www.NshmpMicronautServlet.UrlHelper; import gov.usgs.earthquake.nshmp.internal.www.Response; import gov.usgs.earthquake.nshmp.internal.www.meta.EnumParameter; import gov.usgs.earthquake.nshmp.internal.www.meta.ParamType; import gov.usgs.earthquake.nshmp.internal.www.meta.Status; -import gov.usgs.earthquake.nshmp.www.BaseModel; -import gov.usgs.earthquake.nshmp.www.Model; import gov.usgs.earthquake.nshmp.www.meta.DoubleParameter; import gov.usgs.earthquake.nshmp.www.meta.MetaUtil; import gov.usgs.earthquake.nshmp.www.meta.Metadata; @@ -44,8 +44,6 @@ public class SourceServices { private static final String SERVICE_DESCRIPTION = "Utilities for querying earthquake source models"; - private static final Logger LOGGER = Logger.getLogger(SourceServices.class.getName()); - public static final Gson GSON; static { @@ -62,14 +60,12 @@ public class SourceServices { public static HttpResponse<String> handleDoGetUsage(UrlHelper urlHelper) { try { - LOGGER.info(NAME + "- Request:\n" + urlHelper.url); var response = new Response<>( Status.USAGE, NAME, urlHelper.url, new ResponseData(), urlHelper); var jsonString = GSON.toJson(response); - LOGGER.info(NAME + "- Response:\n" + jsonString); return HttpResponse.ok(jsonString); } catch (Exception e) { - return ServicesUtil.handleError(e, NAME, LOGGER, urlHelper); + return ServicesUtil.handleError(e, NAME, urlHelper); } } @@ -90,14 +86,16 @@ public class SourceServices { } static class Parameters { - SourceModel model; + List<SourceModel> models; EnumParameter<Region> region; DoubleParameter returnPeriod; EnumParameter<Imt> imt; EnumParameter<Vs30> vs30; Parameters() { - model = new SourceModel(ServletUtil.installedModel()); + models = ServletUtil.hazardModels().stream() + .map(SourceModel::new) + .collect(Collectors.toList()); region = new EnumParameter<>( "Region", @@ -109,72 +107,24 @@ public class SourceServices { ParamType.NUMBER, 100.0, 1e6); - - imt = new EnumParameter<>( - "Intensity measure type", - ParamType.STRING, - modelUnionImts()); - - vs30 = new EnumParameter<>( - "Site soil (Vs30)", - ParamType.STRING, - modelUnionVs30s()); } } - /* Union of IMTs across all models. */ - static Set<Imt> modelUnionImts() { - return EnumSet.copyOf(ServletUtil.installedModel().models().stream() - .flatMap(model -> model.imts.stream()) - .collect(Collectors.toSet())); - } - - /* Union of Vs30s across all models. */ - static Set<Vs30> modelUnionVs30s() { - return EnumSet.copyOf(ServletUtil.installedModel().models().stream() - .flatMap(model -> model.vs30s.stream()) - .collect(Collectors.toSet())); - } - public static class SourceModel { - String region; String display; - String value; - String year; - List<BaseSourceModel> models; - - public SourceModel(Model model) { - this.display = model.label(); - this.region = model.region().name(); - this.value = model.toString(); - this.year = model.year(); - models = model.models().stream() - .map(m -> new BaseSourceModel(m)) - .collect(Collectors.toList()); - } - } + Set<Gmm> gmms; + CalcConfig config; - public static class BaseSourceModel { - String year; - String path; - ModelConstraints constraints; - - BaseSourceModel(BaseModel model) { - year = model.year; - path = model.path; - constraints = new ModelConstraints(model); + private SourceModel(HazardModel model) { + display = model.name(); + gmms = model.gmms(); + config = model.config(); } - } - private static class ModelConstraints { - final List<String> imt; - final List<String> vs30; - - ModelConstraints(BaseModel model) { - this.imt = MetaUtil.enumsToNameList(model.imts); - this.vs30 = MetaUtil.enumsToStringList( - model.vs30s, - vs30 -> vs30.name().substring(3)); + public static List<SourceModel> getList() { + return ServletUtil.hazardModels().stream() + .map(SourceModel::new) + .collect(Collectors.toList()); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9ca633b45994682ad1431edfb7a69d55647cebc1..b31875a05c370d469a7def95a5a80f703cf559b9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -16,10 +16,7 @@ micronaut: nshmp-haz: ## - # The NSHM to use. - # Models must reside in the models directory in the root of the project. + # The path to the models. # To specify the model to use: - # java -jar build/libs/nshmp-haz-v2-all.jar -model=<MODEL> - # See nshmp.www.Model for Model enums - # See build.gradle for more information on models directory - installed-model: ${model:CONUS_2018} + # java -jar build/libs/nshmp-haz-v2-all.jar --models=<path/to/models> + model-path: ${models:models}