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

added alternate dev rate endpoint

parent aef3bb71
No related branches found
No related tags found
1 merge request!810Rate service dev
......@@ -9,7 +9,7 @@ micronautAppVersion = 3.7.10
micronautVersion = 3.10.1
nodePluginVersion = 3.0.1
nodeVersion = 16.3.0
nshmpLibVersion = 1.5.6
nshmpLibVersion = 1.5.8
nshmpUtilsJavaVersion = 0.4.0
openApiVersion = 4.0.0
shadowVersion = 7.1.2
......
......@@ -6,7 +6,6 @@ import gov.usgs.earthquake.nshmp.www.ServletUtil;
import gov.usgs.earthquake.nshmp.www.source.RateService.Metadata;
import gov.usgs.earthquake.nshmp.www.source.RateService.Request;
import gov.usgs.earthquake.nshmp.www.source.RateService.Response;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
......@@ -97,6 +96,42 @@ public class RateController {
}
}
/**
* @param longitude Longitude in decimal degrees in the range
* @param latitude Latitude in decimal degrees in the range
* @param distance Cutoff distance in the range [0.01, 1000] km.
*/
@Operation(
summary = "Compute annual earthquake rates",
description = "Compute incremental annual earthquake rates at a location",
operationId = "rate-calc")
@ApiResponse(
description = "Earthquake annual rate calculation response",
responseCode = "200",
content = @Content(
schema = @Schema(implementation = RateResponse.class)))
@Get(
uri = "/dev/{longitude}/{latitude}/{distance}",
produces = MediaType.APPLICATION_JSON)
public HttpResponse<String> doGetRateDev(
HttpRequest<?> http,
@PathVariable double longitude,
@PathVariable double latitude,
@Schema(
minimum = "0.01",
maximum = "1000") @PathVariable double distance) {
try {
RateService.Request request = new RateService.Request(
http, longitude, latitude, distance);
return RateService.getRateDev(request);
} catch (Exception e) {
return ServletUtil.error(
RateService.LOG, e,
RateService.NAME_RATE,
http.getUri().getPath());
}
}
// Swagger schema
private static class RateResponse extends ResponseBody<Request, Response> {}
......
......@@ -7,7 +7,6 @@ import static gov.usgs.earthquake.nshmp.geo.Coordinates.checkLongitude;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.slf4j.Logger;
......@@ -15,13 +14,16 @@ import org.slf4j.LoggerFactory;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Range;
import com.google.common.util.concurrent.ListenableFuture;
import gov.usgs.earthquake.nshmp.calc.CalcConfig;
import gov.usgs.earthquake.nshmp.calc.EqRate;
import gov.usgs.earthquake.nshmp.calc.Site;
import gov.usgs.earthquake.nshmp.data.MutableXySequence;
import gov.usgs.earthquake.nshmp.data.XySequence;
import gov.usgs.earthquake.nshmp.geo.Location;
import gov.usgs.earthquake.nshmp.model.HazardModel;
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;
......@@ -29,7 +31,6 @@ import gov.usgs.earthquake.nshmp.www.ServletUtil;
import gov.usgs.earthquake.nshmp.www.ServletUtil.Server;
import gov.usgs.earthquake.nshmp.www.meta.DoubleParameter;
import gov.usgs.earthquake.nshmp.www.source.SourceService.SourceModel;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import jakarta.inject.Singleton;
......@@ -58,6 +59,25 @@ public final class RateService {
private static final String TOTAL_KEY = "Total";
public static HttpResponse<String> getRateDev(Request request) {
var stopwatch = Stopwatch.createStarted();
var rates = calcRate(request);
var response = new Response.Builder()
.timer(stopwatch)
.request(request)
.ratesDev(rates)
.build();
var body = ResponseBody.success()
.name(NAME_RATE)
.url(request.http.getUri().getPath())
.metadata(new ResponseMetadata(HazVersion.appVersions(ServletUtil.model().root())))
.request(request)
.response(response)
.build();
String json = ServletUtil.GSON2.toJson(body);
return HttpResponse.ok(json);
}
public static HttpResponse<String> getRate(Request request) {
var stopwatch = Stopwatch.createStarted();
var rates = calcRate(request);
......@@ -107,59 +127,38 @@ public final class RateService {
private static EqRate calc(Request request, OptionalDouble timespan) {
var location = Location.create(request.longitude, request.latitude);
var site = Site.builder().location(location).build();
var futureRates = new ArrayList<ListenableFuture<EqRate>>();
/*
* Because we need to combine model results, intially calculate incremental
* annual rates and only convert to cumulative probabilities at the end if
* probability service has been called.
*/
var model = ServletUtil.model();
var rate = process(model, site, request.distance, timespan);
futureRates.add(rate);
var rates = futureRates.stream()
.map((future) -> {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList())
.toArray(new EqRate[] {});
var ratesCombined = EqRate.combine(rates);
HazardModel model = ServletUtil.model();
EqRate rate = process(model, site, request.distance, timespan);
if (timespan.isPresent()) {
ratesCombined = EqRate.toCumulative(ratesCombined);
ratesCombined = EqRate.toPoissonProbability(ratesCombined, timespan.orElseThrow());
rate = EqRate.toCumulative(rate);
rate = EqRate.toPoissonProbability(rate, timespan.orElseThrow());
}
return ratesCombined;
return rate;
}
private static ListenableFuture<EqRate> process(
private static EqRate process(
HazardModel model,
Site site,
double distance,
OptionalDouble timespan) {
var configBuilder = CalcConfig.copyOf(model.config()).distance(distance);
CalcConfig.Builder configBuilder = CalcConfig.copyOf(model.config()).distance(distance);
if (timespan.isPresent()) {
/* Also sets value format to Poisson probability. */
configBuilder.timespan(timespan.getAsDouble());
}
var config = configBuilder.build();
var task = EqRate.callable(model, config, site);
return ServletUtil.CALC_EXECUTOR.submit(task);
CalcConfig config = configBuilder.build();
return EqRate.create(model, config, site);
}
static class Response {
final Metadata metadata;
final List<Sequence> data;
final List<?> data;
Response(Metadata metadata, List<Sequence> data) {
Response(Metadata metadata, List<?> data) {
this.metadata = metadata;
this.data = data;
}
......@@ -168,7 +167,7 @@ public final class RateService {
return metadata;
}
public List<Sequence> getData() {
public List<?> getData() {
return data;
}
......@@ -198,7 +197,7 @@ public final class RateService {
Stopwatch timer;
Request request;
List<Sequence> data;
List<?> data;
Builder timer(Stopwatch timer) {
this.timer = timer;
......@@ -215,6 +214,11 @@ public final class RateService {
return this;
}
Builder ratesDev(EqRate rates) {
this.data = buildSequencesDev(rates);
return this;
}
private List<Sequence> buildSequences(EqRate rates) {
var sequences = new ArrayList<Sequence>();
......@@ -243,6 +247,30 @@ public final class RateService {
return List.copyOf(sequences);
}
private List<SequenceDev> buildSequencesDev(EqRate rates) {
var sequences = new ArrayList<SequenceDev>();
/* Total mfd. */
var total = (!rates.totalMfd.isClear()) ? rates.totalMfd.trim() : rates.totalMfd;
var totalOut = new SequenceDev(TOTAL_KEY, null, null, null, total);
sequences.add(totalOut);
MutableXySequence totalMfdCheck = MutableXySequence.emptyCopyOf(rates.totalMfd);
/* Source type mfds. */
for (EqRate.Contributor contrib : rates.mfds) {
var contribOut = new SequenceDev(
contrib.component,
contrib.id,
contrib.setting,
contrib.type,
contrib.mfd.trim());
sequences.add(contribOut);
totalMfdCheck.add(contrib.mfd);
}
return sequences;
}
Response build() {
Server server = ServletUtil.serverData(ServletUtil.THREAD_COUNT, timer);
return new Response(new Response.Metadata(server), data);
......@@ -255,6 +283,7 @@ public final class RateService {
* HazardService.Curve
*/
private static class Sequence {
final String component;
final List<Double> xvalues;
final List<Double> yvalues;
......@@ -278,6 +307,49 @@ public final class RateService {
}
}
private static class SequenceDev {
final String component;
final Integer id;
final TectonicSetting setting;
final SourceType type;
final XySequence values;
SequenceDev(
String component,
Integer id,
TectonicSetting setting,
SourceType type,
XySequence values) {
this.component = component;
this.id = id;
this.setting = setting;
this.type = type;
this.values = values;
}
public String getComponent() {
return component;
}
public Integer getId() {
return id;
}
public TectonicSetting getSetting() {
return setting;
}
public SourceType getSourceType() {
return type;
}
public XySequence getValues() {
return values;
}
}
private static final Range<Double> DISTANCE_RANGE = Range.closed(0.01, 1000.0);
private static final Range<Double> TIMESPAN_RANGE = Range.closed(1.0, 10000.0);
......
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