diff --git a/gradle.properties b/gradle.properties index c97c988f51647e4f24ca18df5a54d66ee1f6cb5d..04ae04e2d10f92e45bc0d81598dffd799e627f7d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ micronautVersion = 3.2.3 micronautRxVersion = 2.1.1 nodePluginVersion = 3.0.1 nodeVersion = 16.3.0 -nshmpLibVersion = 1.2.8 +nshmpLibVersion = 1.2.10 nshmpWsUtilsVersion = 0.3.11 openApiVersion = 4.0.0 shadowVersion = 7.1.2 diff --git a/gradle/nshm.gradle b/gradle/nshm.gradle index 5eecb87f60f13bc56d519bbdc4b64f494cd659df..0e1a39a17c9477faf6afe3985adf691099b5e3bc 100644 --- a/gradle/nshm.gradle +++ b/gradle/nshm.gradle @@ -43,7 +43,7 @@ clean.dependsOn cleanNshm task nshms() { dependsOn cleanNshm def yaml = new Yaml() - def nshmConfig = new Yaml().load(new File("nshms.yml").newInputStream()) + def nshmConfig = new Yaml().load(new File("${projectDir}/nshms.yml").newInputStream()) doLast { for (nshm in nshmConfig.nshms) { diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/source/LogicTreesController.java b/src/main/java/gov/usgs/earthquake/nshmp/www/source/LogicTreesController.java index 1c6b2396ffb5f88780752728a34d06fbdc555631..2f941ff14789f3fe25383dea32c0bb8b150c654b 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/source/LogicTreesController.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/source/LogicTreesController.java @@ -70,7 +70,7 @@ public class LogicTreesController { description = "Returns the logic tree of features for the supplied ID", operationId = "source-tree-features") @ApiResponse( - description = "NSHM source logic tree", + description = "NSHM source logic tree of features", responseCode = "200", content = @Content( schema = @Schema(implementation = TreeResponse.class))) @@ -94,7 +94,7 @@ public class LogicTreesController { description = "Returns the logic tree of MFDs for the supplied ID", operationId = "source-tree-mfds") @ApiResponse( - description = "NSHM source logic tree", + description = "NSHM source logic tree of MFDs", responseCode = "200", content = @Content( schema = @Schema(implementation = TreeResponse.class))) diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/source/MfdsController.java b/src/main/java/gov/usgs/earthquake/nshmp/www/source/MfdsController.java new file mode 100644 index 0000000000000000000000000000000000000000..3d87c87bb4dd583ed65f3528671a0d2511829333 --- /dev/null +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/source/MfdsController.java @@ -0,0 +1,131 @@ +package gov.usgs.earthquake.nshmp.www.source; + +import java.util.Optional; + +import gov.usgs.earthquake.nshmp.model.SourceType; +import gov.usgs.earthquake.nshmp.model.TectonicSetting; +import gov.usgs.earthquake.nshmp.www.NshmpMicronautServlet; +import gov.usgs.earthquake.nshmp.www.ResponseBody; +import gov.usgs.earthquake.nshmp.www.ServletUtil; +import gov.usgs.earthquake.nshmp.www.source.MfdsService.Metadata; +import gov.usgs.earthquake.nshmp.www.source.MfdsService.RequestData; + +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.PathVariable; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Inject; + +/** + * Micronaut web service controller for summed MFDs in the installed model. + * These endpoints return the magnitude frequency distributions (MFDs) + * associated with the different tectonic settings and source types present in + * the model. MFDs for requested tetonic settings and source types are scaled by + * their branch weights and then summed. + * + * <p>See src/main/resources/application.yml nshmp-haz.model-path for installed + * model. + * + * <p>To run the Micronaut jar file with a model: java -jar + * path/to/nshmp-haz.jar --model=<path/to/model> + * + * @author U.S. Geological Survey + */ +@Tag( + name = MfdsService.NAME, + description = "USGS NSHM source model MFD service") +@Controller("/mfds") +public class MfdsController { + + @Inject + private NshmpMicronautServlet servlet; + + @Operation( + summary = "Source model tectonic settings and source types", + description = "Returns the tectonic settings and source types in the model", + operationId = "source-mfd-metadata") + @ApiResponse( + description = "Source MFD metadata", + responseCode = "200", + content = @Content( + schema = @Schema( + implementation = MetadataResponse.class))) + @Get + public HttpResponse<String> doGetMetadata(HttpRequest<?> http) { + try { + return LogicTreesService.getMetadata(http); + } catch (Exception e) { + return ServletUtil.error( + LogicTreesService.LOG, e, + LogicTreesService.NAME, + http.getUri().toString()); + } + } + + /** + * @param setting model tectonic setting + */ + @Operation( + summary = "Get a source model MFD for a tectonic setting", + description = "Returns the total MFD for the supplied tectonic setting", + operationId = "source-setting-mfd") + @ApiResponse( + description = "NSHM source MFD", + responseCode = "200", + content = @Content( + schema = @Schema(implementation = Response.class))) + @Get(uri = "/{setting}") + public HttpResponse<String> doGetMfdSettingGroup( + HttpRequest<?> http, + @PathVariable TectonicSetting setting) { + try { + return MfdsService.getMfdGroup(http, setting, Optional.empty()); + } catch (Exception e) { + return ServletUtil.error( + LogicTreesService.LOG, e, + LogicTreesService.NAME, + http.getUri().toString()); + } + } + + /** + * @param setting model tectonic setting + * @param type model source type} + */ + @Operation( + summary = "Get a source model MFD for a tectonic setting and source type", + description = "Returns the total MFD for the supplied tectonic setting and source type", + operationId = "source-setting-type-mfd") + @ApiResponse( + description = "NSHM source MFD", + responseCode = "200", + content = @Content( + schema = @Schema(implementation = Response.class))) + @Get(uri = "/{setting}/{type}") + public HttpResponse<String> doGetMfdTypeGroup( + HttpRequest<?> http, + @PathVariable TectonicSetting setting, + @PathVariable SourceType type) { + try { + return MfdsService.getMfdGroup(http, setting, Optional.of(type)); + } catch (Exception e) { + return ServletUtil.error( + LogicTreesService.LOG, e, + LogicTreesService.NAME, + http.getUri().toString()); + } + } + + // Swagger schema + private static class MetadataResponse extends ResponseBody<String, Metadata> {} + + // Swagger schema + private static class Response extends ResponseBody<RequestData, Object> {} + +} diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/source/MfdsService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/source/MfdsService.java new file mode 100644 index 0000000000000000000000000000000000000000..4062fd449bc564e643924d10a62246d07410fe06 --- /dev/null +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/source/MfdsService.java @@ -0,0 +1,107 @@ +package gov.usgs.earthquake.nshmp.www.source; + +import java.util.Optional; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import gov.usgs.earthquake.nshmp.model.HazardModel; +import gov.usgs.earthquake.nshmp.model.Models; +import gov.usgs.earthquake.nshmp.model.SourceType; +import gov.usgs.earthquake.nshmp.model.TectonicSetting; +import gov.usgs.earthquake.nshmp.www.HazVersion; +import gov.usgs.earthquake.nshmp.www.ResponseBody; +import gov.usgs.earthquake.nshmp.www.ResponseMetadata; +import gov.usgs.earthquake.nshmp.www.ServletUtil; +import gov.usgs.earthquake.nshmp.www.source.SourceService.SourceModel; + +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import jakarta.inject.Singleton; + +/** + * Source model MFD handler {@link MfdsController} + * + * @author U.S. Geological Survey + */ +@Singleton +public class MfdsService { + + static final String NAME = "Model MFDs"; + static final Logger LOG = LoggerFactory.getLogger(LogicTreesService.class); + + public static HttpResponse<String> getMetadata(HttpRequest<?> request) { + var url = request.getUri().toString(); + var metadata = new Metadata(ServletUtil.model()); + var response = ResponseBody.usage() + .name(NAME) + .url(url) + .metadata(new ResponseMetadata(HazVersion.appVersions())) + .request(url) + .response(metadata) + .build(); + return HttpResponse.ok(ServletUtil.GSON2.toJson(response)); + } + + public static HttpResponse<String> getMfdGroup( + HttpRequest<?> request, + TectonicSetting setting, + Optional<SourceType> type) { + + var url = request.getUri().toString(); + var mfd = Models.mfd(ServletUtil.model(), setting, type); + var requestData = new RequestData(setting, type.orElse(null)); + var response = ResponseBody.success() + .name(NAME) + .url(url) + .metadata(new ResponseMetadata(HazVersion.appVersions())) + .request(requestData) + .response(mfd) + .build(); + return HttpResponse.ok(ServletUtil.GSON2.toJson(response)); + } + + static class Metadata { + final SourceModel model; + final Set<TectonicSetting> settings; + final Set<SourceType> types; + + Metadata(HazardModel model) { + this.model = new SourceModel(model); + this.settings = model.settings(); + this.types = model.types(); + } + + public SourceModel getModel() { + return model; + } + + public Set<TectonicSetting> getSettings() { + return settings; + } + + public Set<SourceType> getTypes() { + return types; + } + } + + static class RequestData { + final TectonicSetting setting; + final SourceType type; + + RequestData(TectonicSetting setting, SourceType type) { + this.setting = setting; + this.type = type; + } + + public TectonicSetting getSetting() { + return setting; + } + + public SourceType getType() { + return type; + } + } + +}