diff --git a/gradle.properties b/gradle.properties index 2d2aa1c4280abb7ce209c866f5ccdd0cfffc5f36..6d842ead731f80e01295e1d01548fce08b5f0507 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ micronautPluginVersion = 3.1.1 nodePluginVersion = 3.0.1 nodeVersion = 16.3.0 nshmFaultSectionsTag = v0.1 -nshmpLibVersion = 0.8.2 +nshmpLibVersion = 0.9.11 nshmpWsUtilsVersion = 0.1.7 shadowVersion = 7.1.2 spotbugsVersion = 4.7.0 diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/DistanceService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/DistanceService.java deleted file mode 100644 index 864711fda20e57e4e396d985f2d398c06bccb1c6..0000000000000000000000000000000000000000 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/DistanceService.java +++ /dev/null @@ -1,75 +0,0 @@ -package gov.usgs.earthquake.nshmp.www.gmm; - -import java.util.Optional; -import java.util.Set; - -import gov.usgs.earthquake.nshmp.gmm.Gmm; -import gov.usgs.earthquake.nshmp.gmm.GmmInput; -import gov.usgs.earthquake.nshmp.gmm.Imt; -import gov.usgs.earthquake.nshmp.www.ResponseBody; -import gov.usgs.earthquake.nshmp.www.gmm.Service.Id; -import gov.usgs.earthquake.nshmp.www.gmm.Service.Response; - -import io.micronaut.http.HttpRequest; -import io.micronaut.http.HttpResponse; -import jakarta.inject.Singleton; - -@Singleton -class DistanceService { - - private static final double R_MIN = -100.0; - private static final double R_MAX = 100.0; - private final static int R_POINTS = 100; - - static HttpResponse<String> processRequestDistance( - DistanceService.Request request) { - - var rArray = distanceArray(request); - var gmvr = GroundMotions.versusDistance( - request.gmms, - request.input, - request.imt, - rArray); - var response = Response.create(request.serviceId, request, gmvr); - var body = ResponseBody.success() - .name(request.serviceId.name) - .url(request.http.getUri().getPath()) - .request(request) - .response(response) - .build(); - var json = Service.GSON.toJson(body); - return HttpResponse.ok(json); - } - - private static double[] distanceArray( - DistanceService.Request request) { - var isLog = request.serviceId.equals(Id.DISTANCE) ? true : false; - var rStep = isLog - ? (Math.log10(request.rMax / request.rMin)) / (R_POINTS - 1) - : 1.0; - return isLog - ? GmmServices.sequenceLog(request.rMin, request.rMax, rStep) - : GmmServices.sequenceLinear(request.rMin, request.rMax, rStep); - - } - - static class Request extends Service.Request { - - Imt imt; - double rMin; - double rMax; - - Request( - HttpRequest<?> http, Service.Id serviceId, - Set<Gmm> gmms, GmmInput in, - Optional<Imt> imt, - Optional<Double> rMin, - Optional<Double> rMax) { - - super(http, serviceId, gmms, in); - this.imt = imt.orElse(Imt.PGA); - this.rMin = rMin.orElse(R_MIN); - this.rMax = rMax.orElse(R_MAX); - } - } -} diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmController.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmController.java index 56bcffe80c9b9eca9bdd6b7c3ad496f20a33e742..525e960172d2f7311e049a7c2b54ba87edace9ae 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmController.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmController.java @@ -8,7 +8,7 @@ import gov.usgs.earthquake.nshmp.gmm.GmmInput; import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.www.NshmpMicronautServlet; import gov.usgs.earthquake.nshmp.www.Utils; -import gov.usgs.earthquake.nshmp.www.gmm.Service.Id; +import gov.usgs.earthquake.nshmp.www.gmm.GmmService.Id; import io.micronaut.core.annotation.Nullable; import io.micronaut.http.HttpRequest; @@ -26,7 +26,7 @@ import jakarta.inject.Inject; @Tag(name = "Ground Motion Models") @Controller("/gmm") -public class GmmController { +class GmmController { /* * Developer Notes @@ -106,21 +106,20 @@ public class GmmController { responseCode = "200", content = @Content(schema = @Schema(type = "string"))) @Get(uri = "/spectra", produces = MediaType.APPLICATION_JSON) - public HttpResponse<String> doGetSpectra( - HttpRequest<?> http) { + public HttpResponse<String> doGetSpectra(HttpRequest<?> http) { Id serviceId = Id.SPECTRA; try { - Optional<Set<Gmm>> gmms = GmmServices.readGmms(http); + Set<Gmm> gmms = GmmServices.readGmms(http); if (gmms.isEmpty()) { - return Service.metadata(http, serviceId); + return GmmServices.metadata(http, serviceId); } GmmInput in = GmmServices.readGmmInput(http); - Service.Request gmmRequest = new Service.Request( + GmmService.Request gmmRequest = new GmmService.Request( http, serviceId, - gmms.orElseThrow(), + gmms, in); - return SpectraService.processRequestSpectra(gmmRequest); + return GmmService.Spectra.processRequestSpectra(gmmRequest); } catch (Exception e) { return Utils.handleError(e, serviceId.name, http.getUri().getPath()); } @@ -227,17 +226,17 @@ public class GmmController { maximum = "10") @QueryValue @Nullable Double z2p5) { Id serviceId = Id.SPECTRA; try { - Optional<Set<Gmm>> gmms = GmmServices.readGmms(http); + Set<Gmm> gmms = GmmServices.readGmms(http); if (gmms.isEmpty()) { - return Service.metadata(http, serviceId); + return GmmServices.metadata(http, serviceId); } GmmInput in = GmmServices.readGmmInput(http); - Service.Request gmmRequest = new Service.Request( + GmmService.Request gmmRequest = new GmmService.Request( http, serviceId, - gmms.orElseThrow(), + gmms, in); - return SpectraService.processRequestSpectra(gmmRequest); + return GmmService.Spectra.processRequestSpectra(gmmRequest); } catch (Exception e) { return Utils.handleError(e, serviceId.name, http.getUri().getPath()); } @@ -357,16 +356,16 @@ public class GmmController { maximum = "10") @QueryValue @Nullable Double z2p5) { Id serviceId = Id.DISTANCE; try { - Optional<Set<Gmm>> gmms = GmmServices.readGmms(http); + Set<Gmm> gmms = GmmServices.readGmms(http); if (gmms.isEmpty()) { - return Service.metadata(http, serviceId); + return GmmServices.metadata(http, serviceId); } GmmInput in = GmmServices.readGmmInput(http); - DistanceService.Request request = new DistanceService.Request( + GmmService.Distance.Request request = new GmmService.Distance.Request( http, serviceId, - gmms.orElseThrow(), in, + gmms, in, imt, rMin, rMax); - return DistanceService.processRequestDistance(request); + return GmmService.Distance.processRequestDistance(request); } catch (Exception e) { return Utils.handleError(e, serviceId.name, http.getUri().getPath()); } @@ -468,16 +467,16 @@ public class GmmController { Id serviceId = Id.HW_FW; try { - Optional<Set<Gmm>> gmms = GmmServices.readGmms(http); + Set<Gmm> gmms = GmmServices.readGmms(http); if (gmms.isEmpty()) { - return Service.metadata(http, serviceId); + return GmmServices.metadata(http, serviceId); } GmmInput in = GmmServices.readGmmInput(http); - DistanceService.Request request = new DistanceService.Request( + GmmService.Distance.Request request = new GmmService.Distance.Request( http, serviceId, - gmms.orElseThrow(), in, + gmms, in, imt, rMin, rMax); - return DistanceService.processRequestDistance(request); + return GmmService.Distance.processRequestDistance(request); } catch (Exception e) { return Utils.handleError(e, serviceId.name, http.getUri().getPath()); } @@ -588,16 +587,16 @@ public class GmmController { maximum = "10") @QueryValue @Nullable Double z2p5) { Id serviceId = Id.MAGNITUDE; try { - Optional<Set<Gmm>> gmms = GmmServices.readGmms(http); + Set<Gmm> gmms = GmmServices.readGmms(http); if (gmms.isEmpty()) { - return Service.metadata(http, serviceId); + return GmmServices.metadata(http, serviceId); } GmmInput in = GmmServices.readGmmInput(http); - MagnitudeService.Request gmmRequest = new MagnitudeService.Request( + GmmService.Magnitude.Request gmmRequest = new GmmService.Magnitude.Request( http, serviceId, - gmms.orElseThrow(), in, + gmms, in, imt, mMin, mMax, step, distance); - return MagnitudeService.processRequestMagnitude(gmmRequest); + return GmmService.Magnitude.processRequestMagnitude(gmmRequest); } catch (Exception e) { return Utils.handleError(e, serviceId.name, http.getUri().getPath()); } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/Service.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmService.java similarity index 62% rename from src/main/java/gov/usgs/earthquake/nshmp/www/gmm/Service.java rename to src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmService.java index 8a0d70495913d7db99046d6b74db8a5c218808f1..a75c69ad05693bfbd355df2138f7022dcf4b42a8 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/Service.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmService.java @@ -6,20 +6,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - import gov.usgs.earthquake.nshmp.Maths; import gov.usgs.earthquake.nshmp.data.DoubleData; import gov.usgs.earthquake.nshmp.data.XySequence; import gov.usgs.earthquake.nshmp.gmm.Gmm; import gov.usgs.earthquake.nshmp.gmm.GmmInput; -import gov.usgs.earthquake.nshmp.gmm.GmmInput.Constraints; import gov.usgs.earthquake.nshmp.gmm.Imt; -import gov.usgs.earthquake.nshmp.www.WsUtils; +import gov.usgs.earthquake.nshmp.www.ResponseBody; import gov.usgs.earthquake.nshmp.www.gmm.ResponseSpectra.GmmData; import gov.usgs.earthquake.nshmp.www.gmm.XYDataGroup.EpiSeries; @@ -28,33 +25,13 @@ import io.micronaut.http.HttpResponse; import jakarta.inject.Singleton; @Singleton -public class Service { - - static final Gson GSON; - - static { - GSON = new GsonBuilder() - .setPrettyPrinting() - .serializeNulls() - .disableHtmlEscaping() - .registerTypeAdapter(Double.class, new WsUtils.NaNSerializer()) - .registerTypeAdapter(GmmServices.Parameters.class, - new GmmServices.Parameters.Serializer()) - .registerTypeAdapter(Imt.class, new WsUtils.EnumSerializer<Imt>()) - .registerTypeAdapter(Constraints.class, new WsUtils.ConstraintsSerializer()) - .create(); - } - - public static HttpResponse<String> metadata(HttpRequest<?> request, Id service) { - var metadata = GSON.toJson(GmmServices.getMetadata(request, service)); - return HttpResponse.ok(metadata); - } +public class GmmService { /* Base request object for all GMM services. */ public static class Request { - transient HttpRequest<?> http; - transient Id serviceId; + transient final HttpRequest<?> http; + transient final Id serviceId; final Set<Gmm> gmms; final GmmInput input; @@ -69,12 +46,31 @@ public class Service { } } - static class SpectraResponse { + static class Spectra { + + static HttpResponse<String> processRequestSpectra( + GmmService.Request request) { + + Map<Gmm, GmmData> spectra = ResponseSpectra.spectra(request.gmms, request.input, false); + Response response = Response.create(request.serviceId, spectra); + var body = ResponseBody.success() + .name(request.serviceId.name) + .url(request.http.getUri().getPath()) + .request(request) + .response(response) + .build(); + String json = GmmServices.GSON.toJson(body); + return HttpResponse.ok(json); + } + + } + + static class Response { XYDataGroup means; XYDataGroup sigmas; - private SpectraResponse(Id service) { + private Response(Id service) { means = XYDataGroup.create( service.groupNameMean, service.xLabel, @@ -86,14 +82,16 @@ public class Service { service.yLabelSigma); } - static SpectraResponse create( + static Response create( Id service, Map<Gmm, GmmData> result) { - return new SpectraResponse(service).setXY(result); + Response response = new Response(service); + response.setXY(result); + return response; } - private SpectraResponse setXY(Map<Gmm, GmmData> result) { + private void setXY(Map<Gmm, GmmData> result) { for (Entry<Gmm, GmmData> entry : result.entrySet()) { Gmm gmm = entry.getKey(); @@ -133,11 +131,127 @@ public class Service { means.add(gmm.name(), gmm.toString(), μTotal, meanEpi); sigmas.add(gmm.name(), gmm.toString(), σTotal, sigmaEpi); } - return this; + } + } + + static class Distance { + + private static final double R_MIN = -100.0; + private static final double R_MAX = 100.0; + private final static int R_POINTS = 100; + + static HttpResponse<String> processRequestDistance( + GmmService.Distance.Request request) { + + double[] rArray = distanceArray(request); + + Map<Gmm, GmmData> gmvr = GroundMotionData.versusDistance2( + request.gmms, + request.input, + request.imt, + rArray); + Response response = Response.create(request.serviceId, gmvr); + var body = ResponseBody.success() + .name(request.serviceId.name) + .url(request.http.getUri().getPath()) + .request(request) + .response(response) + .build(); + String json = GmmServices.GSON.toJson(body); + return HttpResponse.ok(json); + } + + private static double[] distanceArray( + GmmService.Distance.Request request) { + var isLog = request.serviceId.equals(Id.DISTANCE) ? true : false; + var rStep = isLog + ? (Math.log10(request.rMax / request.rMin)) / (R_POINTS - 1) + : 1.0; + return isLog + ? GmmServices.sequenceLog(request.rMin, request.rMax, rStep) + : GmmServices.sequenceLinear(request.rMin, request.rMax, rStep); + } + + static class Request extends GmmService.Request { + + Imt imt; + double rMin; + double rMax; + + Request( + HttpRequest<?> http, GmmService.Id serviceId, + Set<Gmm> gmms, GmmInput in, + Optional<Imt> imt, + Optional<Double> rMin, + Optional<Double> rMax) { + + super(http, serviceId, gmms, in); + this.imt = imt.orElse(Imt.PGA); + this.rMin = rMin.orElse(R_MIN); + this.rMax = rMax.orElse(R_MAX); + } + } + } + + static class Magnitude { + + public static final double M_MIN = 5.0; + public static final double M_MAX = 8.0; + public static final double M_STEP = 0.1; + public static final double M_DISTANCE = 10.0; + + static HttpResponse<String> processRequestMagnitude( + GmmService.Magnitude.Request request) { + + double[] mArray = GmmServices.sequenceLinear( + request.mMin, request.mMax, request.step); + + Map<Gmm, GmmData> gmvm = GroundMotionData.versusMagnitude2( + request.gmms, + request.input, + request.imt, + mArray, + request.distance); + Response response = Response.create(request.serviceId, gmvm); + var body = ResponseBody.success() + .name(request.serviceId.name) + .url(request.http.getUri().getPath()) + .request(request) + .response(response) + .build(); + String json = GmmServices.GSON.toJson(body); + return HttpResponse.ok(json); } + static class Request extends GmmService.Request { + + Imt imt; + double mMin; + double mMax; + double step; + double distance; + + Request( + HttpRequest<?> http, GmmService.Id serviceId, + Set<Gmm> gmms, GmmInput in, + Optional<Imt> imt, + Optional<Double> mMin, + Optional<Double> mMax, + Optional<Double> step, + Optional<Double> distance) { + + super(http, serviceId, gmms, in); + this.imt = imt.orElse(Imt.PGA); + this.mMin = mMin.orElse(M_MIN); + this.mMax = mMax.orElse(M_MAX); + this.step = step.orElse(M_STEP); + this.distance = distance.orElse(M_DISTANCE); + } + } } + /* ***********************************************/ + /* * Consolidators of epi branches. GMMs return logic trees that represent all * combinations of means and sigmas. For the response spectra service we want @@ -185,12 +299,13 @@ public class Service { } // currently used for distance and magnitude - static class Response { + @Deprecated + static class Response2 { XYDataGroup means; XYDataGroup sigmas; - private Response(Id service) { + private Response2(Id service) { means = XYDataGroup.create( service.groupNameMean, service.xLabel, @@ -202,18 +317,19 @@ public class Service { service.yLabelSigma); } - static Response create( + static Response2 create( Id service, - Request request, - GroundMotions result) { + GroundMotionData result) { - return new Response(service).setXY( + Response2 response = new Response2(service); + response.setXY( result.xs(), result.means(), result.sigmas()); + return response; } - private Response setXY( + private Response2 setXY( Map<Gmm, List<Double>> xs, Map<Gmm, List<Double>> means, Map<Gmm, List<Double>> sigmas) { diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmServices.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmServices.java index b178ba7cc6ec3e9e4a73376e8fa055ce81b35b6f..5db6efd4e0e5621b9ac988f870fe0b84f2374b54 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmServices.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GmmServices.java @@ -12,12 +12,12 @@ import static gov.usgs.earthquake.nshmp.gmm.GmmInput.Field.WIDTH; import static gov.usgs.earthquake.nshmp.gmm.GmmInput.Field.Z1P0; import static gov.usgs.earthquake.nshmp.gmm.GmmInput.Field.Z2P5; import static gov.usgs.earthquake.nshmp.gmm.GmmInput.Field.ZHYP; -import static gov.usgs.earthquake.nshmp.gmm.GmmInput.Field.ZTOP; +import static gov.usgs.earthquake.nshmp.gmm.GmmInput.Field.ZTOR; import static gov.usgs.earthquake.nshmp.gmm.Imt.AI; import static gov.usgs.earthquake.nshmp.gmm.Imt.PGV; import static io.micronaut.core.type.Argument.BOOLEAN; import static io.micronaut.core.type.Argument.DOUBLE; -import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toCollection; import java.lang.reflect.Type; import java.util.ArrayList; @@ -31,6 +31,8 @@ import java.util.stream.Collectors; import com.google.common.collect.Range; import com.google.common.primitives.Doubles; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; @@ -44,11 +46,13 @@ import gov.usgs.earthquake.nshmp.gmm.GmmInput.Constraints; import gov.usgs.earthquake.nshmp.gmm.GmmInput.Field; import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.www.ResponseBody; -import gov.usgs.earthquake.nshmp.www.gmm.Service.Id; +import gov.usgs.earthquake.nshmp.www.WsUtils; +import gov.usgs.earthquake.nshmp.www.gmm.GmmService.Id; import gov.usgs.earthquake.nshmp.www.meta.EnumParameter; import io.micronaut.http.HttpParameters; import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; class GmmServices { @@ -58,6 +62,26 @@ class GmmServices { static final double MAGNITUDE_DEFAULT_DISTANCE = 10.0; static final Range<Double> DISTANCE_DEFAULT_VALUES = Range.closed(-100.0, 100.0); + static final Gson GSON; + + static { + GSON = new GsonBuilder() + .setPrettyPrinting() + .serializeNulls() + .disableHtmlEscaping() + .registerTypeAdapter(Double.class, new WsUtils.NaNSerializer()) + .registerTypeAdapter(GmmServices.Parameters.class, + new GmmServices.Parameters.Serializer()) + .registerTypeAdapter(Imt.class, new WsUtils.EnumSerializer<Imt>()) + .registerTypeAdapter(Constraints.class, new WsUtils.ConstraintsSerializer()) + .create(); + } + + public static HttpResponse<String> metadata(HttpRequest<?> request, Id service) { + var metadata = GSON.toJson(GmmServices.getMetadata(request, service)); + return HttpResponse.ok(metadata); + } + /** Query and JSON reqest/response keys. */ static final class Key { public static final String DISTANCE = "distance"; @@ -91,7 +115,7 @@ class GmmServices { params.getFirst(RX.id, DOUBLE).ifPresent(b::rX); params.getFirst(DIP.id, DOUBLE).ifPresent(b::dip); params.getFirst(WIDTH.id, DOUBLE).ifPresent(b::width); - params.getFirst(ZTOP.id, DOUBLE).ifPresent(b::zTop); + params.getFirst(ZTOR.id, DOUBLE).ifPresent(b::zTor); params.getFirst(ZHYP.id, DOUBLE).ifPresent(b::zHyp); params.getFirst(RAKE.id, DOUBLE).ifPresent(b::rake); params.getFirst(VS30.id, DOUBLE).ifPresent(b::vs30); @@ -102,18 +126,14 @@ class GmmServices { } /* Read the 'gmm' query values. */ - static Optional<Set<Gmm>> readGmms(HttpRequest<?> request) { - List<Gmm> gmmList = request.getParameters() + static Set<Gmm> readGmms(HttpRequest<?> request) { + return request.getParameters() .getAll(Key.GMM) .stream() .map(s -> s.split(",")) .flatMap(Arrays::stream) .map(Gmm::valueOf) - .collect(toList()); - - return gmmList.isEmpty() - ? Optional.empty() - : Optional.of(EnumSet.copyOf(gmmList)); + .collect(toCollection(() -> EnumSet.noneOf(Gmm.class))); } static ResponseBody<String, MetadataResponse> getMetadata( @@ -372,7 +392,7 @@ class GmmServices { Value(Gmm gmm) { this.id = gmm.name(); this.label = gmm.toString(); - this.supportedImts = SupportedImts(gmm.supportedIMTs()); + this.supportedImts = SupportedImts(gmm.supportedImts()); this.constraints = gmm.constraints(); } } diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GroundMotions.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GroundMotionData.java similarity index 60% rename from src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GroundMotions.java rename to src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GroundMotionData.java index 947c7b716e63f11a0e5a3f23125be76d0fd49a63..855788ce8f96b9dd866dfa9b5728c1dd6437cf2d 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GroundMotions.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/GroundMotionData.java @@ -9,6 +9,7 @@ import static java.lang.Math.toRadians; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -18,22 +19,21 @@ import java.util.stream.Collectors; import com.google.common.primitives.Doubles; import gov.usgs.earthquake.nshmp.Maths; -import gov.usgs.earthquake.nshmp.data.DoubleData; import gov.usgs.earthquake.nshmp.gmm.Gmm; import gov.usgs.earthquake.nshmp.gmm.GmmInput; import gov.usgs.earthquake.nshmp.gmm.GroundMotion; import gov.usgs.earthquake.nshmp.gmm.GroundMotionModel; import gov.usgs.earthquake.nshmp.gmm.Imt; -import gov.usgs.earthquake.nshmp.tree.Branch; import gov.usgs.earthquake.nshmp.tree.LogicTree; +import gov.usgs.earthquake.nshmp.www.gmm.ResponseSpectra.GmmData; -class GroundMotions { +class GroundMotionData { private TreeMap<Gmm, List<Double>> means; private TreeMap<Gmm, List<Double>> sigmas; private TreeMap<Gmm, List<Double>> xs; - private GroundMotions( + private GroundMotionData( TreeMap<Gmm, List<Double>> means, TreeMap<Gmm, List<Double>> sigmas, TreeMap<Gmm, List<Double>> xs) { @@ -50,13 +50,30 @@ class GroundMotions { * @param imt The intensity measure type * @param distance The distances to calculate ground motions */ - static GroundMotions versusDistance( + static GroundMotionData versusDistance( Set<Gmm> gmms, GmmInput inputModel, Imt imt, - double[] distance) { - var gmmInputList = hangingWallDistances(inputModel, distance); - return calculateGroundMotions(gmms, gmmInputList, imt, distance); + double[] distances) { + var gmmInputList = hangingWallDistances(inputModel, distances); + return calculateGroundMotions(gmms, gmmInputList, imt, distances); + } + + /** + * Calculate ground motion VS distance. + * + * @param gmms The GMMs + * @param inputModel The GMM input + * @param imt The intensity measure type + * @param distance The distances to calculate ground motions + */ + static Map<Gmm, GmmData> versusDistance2( + Set<Gmm> gmms, + GmmInput inputModel, + Imt imt, + double[] distances) { + var gmmInputList = hangingWallDistances(inputModel, distances); + return calculateGroundMotions2(gmms, gmmInputList, imt, distances); } /** @@ -68,7 +85,7 @@ class GroundMotions { * @param magnitudes The magnitudes to calculate the ground motions * @param distance The distance to calculate ground motions */ - static GroundMotions versusMagnitude( + static GroundMotionData versusMagnitude( Set<Gmm> gmms, GmmInput inputModel, Imt imt, @@ -82,6 +99,29 @@ class GroundMotions { return calculateGroundMotions(gmms, gmmInputs, imt, magnitudes); } + /** + * Calculate ground motion VS magnitude. + * + * @param gmms The GMMs + * @param inputModel The GMM input + * @param imt The intensity measure type + * @param magnitudes The magnitudes to calculate the ground motions + * @param distance The distance to calculate ground motions + */ + static Map<Gmm, GmmData> versusMagnitude2( + Set<Gmm> gmms, + GmmInput inputModel, + Imt imt, + double[] magnitudes, + double distance) { + var gmmInputs = Arrays.stream(magnitudes) + .mapToObj(Mw -> GmmInput.builder().fromCopy(inputModel).mag(Mw).build()) + .map(gmmInput -> hangingWallDistance(gmmInput, distance)) + .collect(Collectors.toList()); + + return calculateGroundMotions2(gmms, gmmInputs, imt, magnitudes); + } + Map<Gmm, List<Double>> means() { return Collections.unmodifiableMap(this.means); } @@ -94,7 +134,7 @@ class GroundMotions { return Collections.unmodifiableMap(this.xs); } - private static GroundMotions calculateGroundMotions( + private static GroundMotionData calculateGroundMotions( Set<Gmm> gmms, List<GmmInput> gmmInputs, Imt imt, @@ -109,7 +149,8 @@ class GroundMotions { GroundMotionModel model = gmm.instance(imt); for (GmmInput gmmInput : gmmInputs) { - GroundMotion gm = combine(model.calc(gmmInput)); + GroundMotion gm = gov.usgs.earthquake.nshmp.gmm.GroundMotions.combine( + model.calc(gmmInput)); means.add(gm.mean()); sigmas.add(gm.sigma()); } @@ -119,34 +160,54 @@ class GroundMotions { xsMap.put(gmm, Doubles.asList(distance)); } - return new GroundMotions( + return new GroundMotionData( meanMap, sigmaMap, xsMap); } - @Deprecated - static GroundMotion combine(LogicTree<GroundMotion> tree) { - // once GroundMotions in lib is exposed remove this - if (tree.size() == 1) { - return tree.get(0).value(); + private static Map<Gmm, GmmData> calculateGroundMotions2( + Set<Gmm> gmms, + List<GmmInput> gmmInputs, + Imt imt, + double[] distances) { + + // var xsMap = new TreeMap<Gmm, List<Double>>(); + // var meanMap = new TreeMap<Gmm, List<Double>>(); + // var sigmaMap = new TreeMap<Gmm, List<Double>>(); + + Map<Gmm, GmmData> gmValues = new EnumMap<>(Gmm.class); + + for (Gmm gmm : gmms) { + + List<LogicTree<GroundMotion>> trees = new ArrayList<>(); + + // var means = new ArrayList<Double>(); + // var sigmas = new ArrayList<Double>(); + + GroundMotionModel model = gmm.instance(imt); + + for (GmmInput gmmInput : gmmInputs) { + + trees.add(model.calc(gmmInput)); + + // GroundMotion gm = GroundMotions.combine(model.calc(gmmInput)); + // means.add(gm.mean()); + // sigmas.add(gm.sigma()); + } + + GmmData dataGroup = ResponseSpectra.treesToDataGroup(Doubles.asList(distances), trees); + gmValues.put(gmm, dataGroup); + // meanMap.put(gmm, List.copyOf(means)); + // sigmaMap.put(gmm, List.copyOf(sigmas)); + // xsMap.put(gmm, Doubles.asList(distance)); } - double[] means = tree.stream() - .map(Branch::value) - .mapToDouble(GroundMotion::mean) - .toArray(); - double[] sigmas = tree.stream() - .map(Branch::value) - .mapToDouble(GroundMotion::sigma) - .toArray(); - double[] weights = tree.stream() - .mapToDouble(Branch::weight) - .toArray(); - double mean = DoubleData.weightedSumLn(means, weights); - double sigma = DoubleData.weightedSum(sigmas, weights); - // TODO update NGA-East test results - // double sigma = Maths.srssWeighted(sigmas, weights); - return GroundMotion.create(mean, sigma); + + return gmValues; + // return new GroundMotionData( + // meanMap, + // sigmaMap, + // xsMap); } /* @@ -161,19 +222,19 @@ class GroundMotions { double v = sin(δ) * inputModel.width; /* Depth to bottom of rupture */ - double zBot = inputModel.zTop + v; + double zBot = inputModel.zTor + v; /* Distance range over which site is normal to fault plane */ - double rCutLo = tan(δ) * inputModel.zTop; + double rCutLo = tan(δ) * inputModel.zTor; double rCutHi = tan(δ) * zBot + h; /* rRup values corresponding to cutoffs above */ - double rRupLo = Maths.hypot(inputModel.zTop, rCutLo); + double rRupLo = Maths.hypot(inputModel.zTor, rCutLo); double rRupHi = Maths.hypot(zBot, rCutHi - h); double rJB = (r < 0) ? -r : (r < h) ? 0.0 : r - h; double rRup = (r < rCutLo) - ? hypot(r, inputModel.zTop) + ? hypot(r, inputModel.zTor) : (r > rCutHi) ? hypot(r - h, zBot) : rRupScaled( diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/MagnitudeService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/MagnitudeService.java deleted file mode 100644 index 83ffef9ca011e1d2c9f496755238efe412500e6d..0000000000000000000000000000000000000000 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/MagnitudeService.java +++ /dev/null @@ -1,71 +0,0 @@ -package gov.usgs.earthquake.nshmp.www.gmm; - -import java.util.Optional; -import java.util.Set; - -import gov.usgs.earthquake.nshmp.gmm.Gmm; -import gov.usgs.earthquake.nshmp.gmm.GmmInput; -import gov.usgs.earthquake.nshmp.gmm.Imt; -import gov.usgs.earthquake.nshmp.www.ResponseBody; -import gov.usgs.earthquake.nshmp.www.gmm.Service.Response; - -import io.micronaut.http.HttpRequest; -import io.micronaut.http.HttpResponse; -import jakarta.inject.Singleton; - -@Singleton -class MagnitudeService { - - public static final double M_MIN = 5.0; - public static final double M_MAX = 8.0; - public static final double M_STEP = 0.1; - public static final double M_DISTANCE = 10.0; - - static HttpResponse<String> processRequestMagnitude( - MagnitudeService.Request request) { - - var magArray = GmmServices.sequenceLinear( - request.mMin, request.mMax, request.step); - var gmvm = GroundMotions.versusMagnitude( - request.gmms, - request.input, - request.imt, - magArray, - request.distance); - var response = Response.create(request.serviceId, request, gmvm); - var body = ResponseBody.success() - .name(request.serviceId.name) - .url(request.http.getUri().getPath()) - .request(request) - .response(response) - .build(); - var json = Service.GSON.toJson(body); - return HttpResponse.ok(json); - } - - static class Request extends Service.Request { - - Imt imt; - double mMin; - double mMax; - double step; - double distance; - - Request( - HttpRequest<?> http, Service.Id serviceId, - Set<Gmm> gmms, GmmInput in, - Optional<Imt> imt, - Optional<Double> mMin, - Optional<Double> mMax, - Optional<Double> step, - Optional<Double> distance) { - - super(http, serviceId, gmms, in); - this.imt = imt.orElse(Imt.PGA); - this.mMin = mMin.orElse(M_MIN); - this.mMax = mMax.orElse(M_MAX); - this.step = step.orElse(M_STEP); - this.distance = distance.orElse(M_DISTANCE); - } - } -} diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/ResponseSpectra.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/ResponseSpectra.java index 44da5982fe8a2d588bd8e5c9ec70faf27ea3d9b7..e7fec23c87606a9dfb7316970642f8d9163263bc 100644 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/ResponseSpectra.java +++ b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/ResponseSpectra.java @@ -12,6 +12,7 @@ import com.google.common.collect.ImmutableList; import gov.usgs.earthquake.nshmp.gmm.Gmm; import gov.usgs.earthquake.nshmp.gmm.GmmInput; import gov.usgs.earthquake.nshmp.gmm.GroundMotion; +import gov.usgs.earthquake.nshmp.gmm.GroundMotions; import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.tree.Branch; import gov.usgs.earthquake.nshmp.tree.LogicTree; @@ -50,7 +51,7 @@ class ResponseSpectra { */ /* Common imts and periods; may not be used. */ - Set<Imt> saImts = Gmm.responseSpectrumIMTs(gmms); + Set<Imt> saImts = Gmm.responseSpectrumImts(gmms); List<Double> periods = new ArrayList<>(); periods.add(PGA_PERIOD); periods.addAll(Imt.periods(saImts)); @@ -58,7 +59,7 @@ class ResponseSpectra { Map<Gmm, GmmData> gmmSpectra = new EnumMap<>(Gmm.class); for (Gmm gmm : gmms) { if (!commonImts) { - saImts = gmm.responseSpectrumIMTs(); + saImts = gmm.responseSpectrumImts(); periods = ImmutableList.<Double> builder() .add(PGA_PERIOD) .addAll(Imt.periods(saImts)) @@ -143,7 +144,7 @@ class ResponseSpectra { static class GmmData { - final double[] periods; + final double[] periods; // should be any x-value final double[] μs; final double[] σs; final List<EpiBranch> tree; diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/SpectraService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/SpectraService.java deleted file mode 100644 index 8fff43eb009a5f56880fdb28eede02e0c44c20fb..0000000000000000000000000000000000000000 --- a/src/main/java/gov/usgs/earthquake/nshmp/www/gmm/SpectraService.java +++ /dev/null @@ -1,26 +0,0 @@ -package gov.usgs.earthquake.nshmp.www.gmm; - -import gov.usgs.earthquake.nshmp.www.ResponseBody; -import gov.usgs.earthquake.nshmp.www.gmm.Service.SpectraResponse; - -import io.micronaut.http.HttpResponse; -import jakarta.inject.Singleton; - -@Singleton -public class SpectraService { - - public static HttpResponse<String> processRequestSpectra( - Service.Request request) { - - var spectra = ResponseSpectra.spectra(request.gmms, request.input, false); - var response = SpectraResponse.create(request.serviceId, spectra); - var body = ResponseBody.success() - .name(request.serviceId.name) - .url(request.http.getUri().getPath()) - .request(request) - .response(response) - .build(); - var json = Service.GSON.toJson(body); - return HttpResponse.ok(json); - } -}