Skip to content
Snippets Groups Projects
Commit 1c578a2c authored by Powers, Peter M.'s avatar Powers, Peter M.
Browse files

removed disagg epsilon service

parent 52fd813c
No related branches found
No related tags found
2 merge requests!577Production Release | nshmp-haz,!564Command line and lib updates
package gov.usgs.earthquake.nshmp.www;
import java.util.EnumMap;
import javax.inject.Inject;
import gov.usgs.earthquake.nshmp.gmm.Imt;
import gov.usgs.earthquake.nshmp.www.services.DisaggEpsilonService;
import gov.usgs.earthquake.nshmp.www.services.DisaggEpsilonService.Query;
import gov.usgs.earthquake.nshmp.www.services.HazardService;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.http.annotation.QueryValue;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
@Tag(name = "Epsilon Disaggregation Service (experimental)")
@Controller("/disagg-epsilon")
public class DisaggEpsilonController {
@Inject
private NshmpMicronautServlet servlet;
@Get(uri = "/usage", produces = MediaType.APPLICATION_JSON)
public HttpResponse<String> doGetUsage(HttpRequest<?> request) {
return HazardService.handleDoGetMetadata(request);
}
/**
* GET method to return usage or hazard curves, query based.
*
* @param request The HTTP request
* @param longitude Longitude (in decimal degrees) ([-360, 360])
* @param latitude Latitude (in decimal degrees) ([-90, 90])
* @param vs30 The site soil class
* @param basin Whether to use basin service
*/
@Operation(
summary = "Compute epsilon disaggregation",
description = "Compute epsilon disaggregation given longitude, latitude, Vs30 and IMT-IML map",
operationId = "disaggEpsilon_doGetDisaggEpsilon")
@ApiResponse(
description = "Epsilon disaggregations",
responseCode = "200")
@Get(uri = "{?longitude,latitude,vs30,basin}")
public HttpResponse<String> doGetDisaggEpsilon(
HttpRequest<?> request,
@Schema(
required = true,
minimum = "-360",
maximum = "360")
@QueryValue
@Nullable
Double longitude,
@Schema(
required = true,
minimum = "-90",
maximum = "90")
@QueryValue
@Nullable
Double latitude,
@Schema(required = true)
@QueryValue
@Nullable
Integer vs30,
@Schema(defaultValue = "false")
@QueryValue
@Nullable
Boolean basin,
@Schema(
defaultValue = "{\"SA0P01\": 0.01}",
required = true)
@QueryValue
@Nullable
EnumMap<Imt, Double> imtImls) {
var query = new Query(request, longitude, latitude, vs30, basin);
return DisaggEpsilonService.handleDoGetDisaggEpsilon(request, query);
}
/**
* GET method to return usage or hazard curves, slash based.
*
* @param request The HTTP request
* @param longitude Longitude (in decimal degrees) ([-360, 360])
* @param latitude Latitude (in decimal degrees) ([-90, 90])
* @param vs30 The site soil class
* @param basin Whether to use basin service
*/
@Operation(
summary = "Compute epsilon disaggregation",
description = "Compute epsilon disaggregation given longitude, latitude, Vs30 and IMT-IML map",
operationId = "disaggEpsilon_doGetDisaggEpsilonSlash")
@ApiResponse(
description = "Epsilon disaggregations",
responseCode = "200")
@Get(uri = "{/longitude}{/latitude}{/vs30}{/basin}")
public HttpResponse<String> doGetDisaggEpsilonSlash(
HttpRequest<?> request,
@Schema(
required = true,
minimum = "-360",
maximum = "360")
@PathVariable
@Nullable
Double longitude,
@Schema(
required = true,
minimum = "-90",
maximum = "90")
@PathVariable
@Nullable
Double latitude,
@Schema(required = true)
@PathVariable
@Nullable
Integer vs30,
@Schema(defaultValue = "false")
@PathVariable
@Nullable
Boolean basin,
@Schema(
defaultValue = "{\"SA0P01\": 0.01}",
required = true)
@QueryValue
@Nullable
EnumMap<Imt, Double> imtImls) {
return doGetDisaggEpsilon(request, longitude, latitude, vs30, basin, null);
}
}
package gov.usgs.earthquake.nshmp.www.services;
import java.net.URL;
import java.util.EnumMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import javax.inject.Singleton;
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import gov.usgs.earthquake.nshmp.calc.CalcConfig;
import gov.usgs.earthquake.nshmp.calc.Disaggregation;
import gov.usgs.earthquake.nshmp.calc.Site;
import gov.usgs.earthquake.nshmp.geo.Location;
import gov.usgs.earthquake.nshmp.gmm.Imt;
import gov.usgs.earthquake.nshmp.model.HazardModel;
import gov.usgs.earthquake.nshmp.www.DisaggEpsilonController;
import gov.usgs.earthquake.nshmp.www.Response;
import gov.usgs.earthquake.nshmp.www.WsUtils;
import gov.usgs.earthquake.nshmp.www.meta.Metadata;
import gov.usgs.earthquake.nshmp.www.meta.Status;
import gov.usgs.earthquake.nshmp.www.services.ServicesUtil.Key;
import gov.usgs.earthquake.nshmp.www.services.SourceServices.SourceModel;
import io.micronaut.context.annotation.Value;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
/**
* Hazard disaggregation handler for {@link DisaggEpsilonController}.
*
* @author U.S. Geological Survey
*/
@Singleton
public final class DisaggEpsilonService {
/* Developer notes: See HazardService. */
private static final String NAME = "Epsilon Disaggregation";
@Value("${nshmp-haz.basin-service-url}")
private static URL basinUrl;
/**
* Handler for {@link DisaggEpsilonController#doGetDisaggEpsilon}. Returns the
* usage or the disagg result.
*
* @param query The query
* @param urlHelper The URL helper
*/
public static HttpResponse<String> handleDoGetDisaggEpsilon(HttpRequest<?> request, Query query) {
try {
var timer = ServletUtil.timer();
if (query.isNull()) {
return HazardService.handleDoGetMetadata(request);
}
query.checkValues();
var data = new RequestData(query, query.vs30);
var response = process(request, data);
var svcResponse = ServletUtil.GSON.toJson(response);
return HttpResponse.ok(svcResponse);
} catch (Exception e) {
return ServicesUtil.handleError(e, NAME, request.getUri().getPath());
}
}
/* Create map of IMT to disagg IML. */
private static EnumMap<Imt, Double> readImtsFromQuery(HttpRequest<?> request) {
var imtImls = new EnumMap<Imt, Double>(Imt.class);
for (var param : request.getParameters().asMap().entrySet()) {
if (isImtParam(param.getKey())) {
imtImls.put(
Imt.valueOf(param.getKey()),
Double.valueOf(param.getValue().get(0)));
}
}
return imtImls;
}
private static boolean isImtParam(String key) {
return key.equals("PGA") || key.startsWith("SA");
}
private static Response<RequestData, ResponseData> process(
HttpRequest<?> request,
RequestData data)
throws InterruptedException, ExecutionException {
var configFunction = new ConfigFunction();
var siteFunction = new SiteFunction(data);
var timer = Stopwatch.createStarted();
var hazard = ServicesUtil.calcHazard(configFunction, siteFunction);
var disagg = Disaggregation.atImls(hazard, data.imtImls, ServletUtil.CALC_EXECUTOR);
return new ResultBuilder()
.disagg(disagg)
.requestData(data)
.timer(timer)
.url(request)
.build();
}
public static class Query extends HazardService.Query {
final EnumMap<Imt, Double> imtImls;
final Boolean basin;
public Query(
HttpRequest<?> request,
Double longitude,
Double latitude,
Integer vs30,
Boolean basin) {
super(longitude, latitude, vs30);
imtImls = readImtsFromQuery(request);
this.basin = basin == null ? false : basin;
}
@Override
public boolean isNull() {
return super.isNull() && vs30 == null;
}
@Override
public void checkValues() {
super.checkValues();
WsUtils.checkValue(Key.BASIN, basin);
}
}
static class ConfigFunction implements Function<HazardModel, CalcConfig> {
@Override
public CalcConfig apply(HazardModel model) {
var configBuilder = CalcConfig.copyOf(model.config());
return configBuilder.build();
}
}
/*
* Developer notes:
*
* We're opting here to fetch basin terms ourselves. If we were to set the
* basin provider in the config, which requires additions to config, the URL
* is tested every time a site is created for a servlet request. While this
* worked for maps it's not good here.
*
* Site has logic for parsing the basin service response, which perhaps it
* shouldn't. TODO is it worth decomposing data objects and services
*/
static class SiteFunction implements Function<CalcConfig, Site> {
final RequestData data;
private SiteFunction(RequestData data) {
this.data = data;
}
@Override
public Site apply(CalcConfig config) {
return Site.builder()
.location(Location.create(data.longitude, data.latitude))
.dataService(data.basin ? Optional.of(basinUrl) : Optional.empty())
.vs30(data.vs30)
.build();
}
}
static final class RequestData extends HazardService.RequestDataOld {
final EnumMap<Imt, Double> imtImls;
final boolean basin;
RequestData(Query query, double vs30) {
super(query, vs30);
imtImls = query.imtImls;
basin = query.basin;
}
}
private static final class ResponseMetadata {
final SourceModel models;
final double longitude;
final double latitude;
final String imt;
final double iml;
final double vs30;
final String rlabel = "Closest Distance, rRup (km)";
final String mlabel = "Magnitude (Mw)";
final String εlabel = "% Contribution to Hazard";
final Object εbins;
ResponseMetadata(Disaggregation disagg, RequestData request, Imt imt) {
this.models = new SourceModel(ServletUtil.model());
this.longitude = request.longitude;
this.latitude = request.latitude;
this.imt = imt.toString();
this.iml = imt.period();
this.vs30 = request.vs30;
this.εbins = disagg.εBins();
}
}
private static final class ResponseData {
final Object server;
final List<DisaggResponse> disaggs;
ResponseData(Object server, List<DisaggResponse> deaggs) {
this.server = server;
this.disaggs = deaggs;
}
}
private static final class DisaggResponse {
final ResponseMetadata metadata;
final Object data;
DisaggResponse(ResponseMetadata metadata, Object data) {
this.metadata = metadata;
this.data = data;
}
}
static final class ResultBuilder {
String url;
Stopwatch timer;
RequestData request;
Disaggregation disagg;
ResultBuilder disagg(Disaggregation disagg) {
this.disagg = disagg;
return this;
}
ResultBuilder url(HttpRequest<?> request) {
url = request.getUri().getPath();
return this;
}
ResultBuilder timer(Stopwatch timer) {
this.timer = timer;
return this;
}
ResultBuilder requestData(RequestData request) {
this.request = request;
return this;
}
Response<RequestData, ResponseData> build() {
ImmutableList.Builder<DisaggResponse> responseListBuilder = ImmutableList.builder();
for (Imt imt : request.imtImls.keySet()) {
ResponseMetadata responseData = new ResponseMetadata(disagg, request, imt);
Object disaggs = disagg.toJsonCompact(imt);
DisaggResponse response = new DisaggResponse(responseData, disaggs);
responseListBuilder.add(response);
}
List<DisaggResponse> responseList = responseListBuilder.build();
Object server = Metadata.serverData(ServletUtil.THREAD_COUNT, timer);
var response = new ResponseData(server, responseList);
return new Response<>(Status.SUCCESS, NAME, request, response, url);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment