diff --git a/README.md b/README.md
index 9d1b3b73..8020df36 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
![Livermore logo](llnl-logo.gif)
The `Coda Calibration Tool` (CCT) is a Java based application for calibrating 1D shear wave coda measurement models to observed data using a much smaller set of reference MWs calculated from other means (waveform modeling, etc.).
-
These calibrated measurement models can then be used in other tools to generate coda MW measurements, source spectra, estimated stress drop, and other useful measurements against the rest of the events and any new data collected in the calibrated region.
+
These calibrated measurement models can then be used in other tools to generate coda MW measurements, source spectra, estimated stress, and other useful measurements against the rest of the events and any new data collected in the calibrated region.
> ***note***
> The `Coda Calibration Tool` currently only does calibration; it requires data to be pre-processed for loading using other tools.
@@ -97,7 +97,7 @@ As of 1.0, CCT is capable of loading four basic file types
A simple space delimited text file of format:
```text
- EVID MW [STRESS_DROP_IN_MPA|0.0]
+ EVID MW [APPARENT_STRESS_IN_MPA|0.0]
(e.g. 999999 5.1 0.0)
```
> ***note***
diff --git a/calibration-gui/pom.xml b/calibration-gui/pom.xml
index 25179af8..dcab9ce0 100644
--- a/calibration-gui/pom.xml
+++ b/calibration-gui/pom.xml
@@ -177,6 +177,10 @@
mockito-junit-jupiter
test
+
+ io.netty
+ netty-tcnative-boringssl-static
+
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/AppProperties.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/AppProperties.java
index c70ff08d..2bed41c6 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/AppProperties.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/AppProperties.java
@@ -18,22 +18,16 @@
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.stereotype.Component;
-import gov.llnl.gnem.apps.coda.common.mapping.MapProperties;
import gov.llnl.gnem.apps.coda.common.mapping.WMSLayerDescriptor;
-@Component
-@Configuration
@ConfigurationProperties("app")
public class AppProperties {
private String baseTitle = "Coda Calibration";
private Integer height = 800;
private Integer width = 600;
- private Boolean debugEnabled = false;
+ private Boolean debugEnabled = Boolean.FALSE;
private List wmsLayers = new ArrayList<>();
public Boolean getDebugEnabled() {
@@ -75,9 +69,4 @@ public List getWmsLayers() {
public void setWmsLayers(List wmsLayers) {
this.wmsLayers = wmsLayers;
}
-
- @Bean
- public MapProperties getMapProperties() {
- return new MapProperties().setLayers(wmsLayers);
- }
}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java
index ce9212f4..d73a31ef 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/CodaGuiController.java
@@ -22,7 +22,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -49,14 +48,16 @@
import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationClient;
import gov.llnl.gnem.apps.coda.calibration.gui.data.exporters.ParamExporter;
import gov.llnl.gnem.apps.coda.calibration.gui.events.CalibrationStageShownEvent;
+import gov.llnl.gnem.apps.coda.calibration.gui.events.MapIconActivationCallback;
+import gov.llnl.gnem.apps.coda.calibration.gui.plotting.WaveformGui;
import gov.llnl.gnem.apps.coda.calibration.gui.util.CalibrationProgressListener;
import gov.llnl.gnem.apps.coda.calibration.model.messaging.CalibrationStatusEvent;
import gov.llnl.gnem.apps.coda.calibration.model.messaging.CalibrationStatusEvent.Status;
import gov.llnl.gnem.apps.coda.common.gui.controllers.ProgressGui;
-import gov.llnl.gnem.apps.coda.common.gui.events.EnvelopeLoadCompleteEvent;
+import gov.llnl.gnem.apps.coda.common.gui.data.client.api.WaveformClient;
import gov.llnl.gnem.apps.coda.common.gui.events.ShowFailureReportEvent;
import gov.llnl.gnem.apps.coda.common.gui.util.ProgressMonitor;
-import gov.llnl.gnem.apps.coda.common.mapping.LeafletMapController;
+import gov.llnl.gnem.apps.coda.common.mapping.api.GeoMap;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
@@ -79,11 +80,12 @@ public class CodaGuiController {
@FXML
private Node rootElement;
+ private WaveformGui waveformGui;
private DataController data;
private ParametersController param;
private ShapeController shape;
private PathController path;
- private SiteController site;
+ private SiteController site;
@FXML
private Tab dataTab;
@@ -117,7 +119,9 @@ public class CodaGuiController {
private Label showMapIcon;
- private LeafletMapController mapController;
+ private GeoMap mapController;
+
+ private WaveformClient waveformClient;
private EnvelopeLoadingController envelopeLoadingController;
@@ -153,16 +157,18 @@ public class CodaGuiController {
});
@Autowired
- public CodaGuiController(LeafletMapController mapController, EnvelopeLoadingController waveformLoadingController, CodaParamLoadingController codaParamLoadingController,
- ReferenceEventLoadingController refEventLoadingController, CalibrationClient calibrationClient, ParamExporter paramExporter, DataController data, ParametersController param,
- ShapeController shape, PathController path, SiteController site, EventBus bus) throws IOException {
+ public CodaGuiController(GeoMap mapController, WaveformClient waveformClient, EnvelopeLoadingController waveformLoadingController, CodaParamLoadingController codaParamLoadingController,
+ ReferenceEventLoadingController refEventLoadingController, CalibrationClient calibrationClient, ParamExporter paramExporter, WaveformGui waveformGui, DataController data,
+ ParametersController param, ShapeController shape, PathController path, SiteController site, EventBus bus) throws IOException {
super();
this.mapController = mapController;
+ this.waveformClient = waveformClient;
this.envelopeLoadingController = waveformLoadingController;
this.codaParamLoadingController = codaParamLoadingController;
this.refEventLoadingController = refEventLoadingController;
this.calibrationClient = calibrationClient;
this.paramExporter = paramExporter;
+ this.waveformGui = waveformGui;
this.data = data;
this.param = param;
this.shape = shape;
@@ -213,6 +219,11 @@ private void showMapWindow() {
});
}
+ @FXML
+ private void openWaveformDisplay() {
+ waveformGui.toFront();
+ }
+
@FXML
private void openFailureReportDisplay() {
bus.post(new ShowFailureReportEvent());
@@ -295,21 +306,24 @@ private void openMdacFiWindow() {
@FXML
private void runCalibration() {
- calibrationClient.runCalibration(Boolean.FALSE).subscribe(value -> log.trace(value.toString()), err -> log.trace(err.getMessage(), err));
+ calibrationClient.runCalibration(Boolean.FALSE).subscribe(value -> log.trace(value), err -> log.trace(err.getMessage(), err));
}
@FXML
private void clearData() {
- calibrationClient.clearData().subscribe(value -> log.trace(value.toString()), err -> log.trace(err.getMessage(), err));
+ calibrationClient.clearData().subscribe(value -> log.trace(value), err -> log.trace(err.getMessage(), err), () -> dataRefresh.run());
}
@FXML
private void runAutoPickingCalibration() {
- calibrationClient.runCalibration(Boolean.TRUE).subscribe(value -> log.trace(value.toString()), err -> log.trace(err.getMessage(), err));
+ calibrationClient.runCalibration(Boolean.TRUE).subscribe(value -> log.trace(value), err -> log.trace(err.getMessage(), err));
}
@FXML
public void initialize() {
+
+ mapController.registerEventCallback(new MapIconActivationCallback(waveformClient));
+
activeMapIcon = makeMapLabel();
showMapIcon = makeMapLabel();
@@ -396,14 +410,29 @@ private void listener(CalibrationStatusEvent event) {
if (event.getStatus() == Status.COMPLETE || event.getStatus() == Status.ERROR) {
final ProgressMonitor monitor = monitors.remove(event.getId());
+ monitor.setProgressStage("Finished");
service.schedule(() -> loadingGui.removeProgressMonitor(monitor), 15, TimeUnit.MINUTES);
- }
- }
+ } else {
+ ProgressMonitor monitor = monitors.get(event.getId());
+ if (monitor != null) {
+ switch (event.getStatus()) {
+ case PEAK_STARTING:
+ monitor.setProgressStage("Peak starting");
+ break;
+ case SHAPE_STARTING:
+ monitor.setProgressStage("Shape starting");
+ break;
+ case PATH_STARTING:
+ monitor.setProgressStage("Path starting");
+ break;
+ case SITE_STARTING:
+ monitor.setProgressStage("Site starting");
+ break;
+ default:
+ break;
- @Subscribe
- private void listener(EnvelopeLoadCompleteEvent evt) {
- if (dataTab.isSelected()) {
- CompletableFuture.runAsync(dataRefresh);
+ }
+ }
}
}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/GuiApplication.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/GuiApplication.java
index 148a51ea..26372a6a 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/GuiApplication.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/GuiApplication.java
@@ -167,7 +167,7 @@ public void stop() throws Exception {
springContext.stop();
springContext.close();
}).get(1, TimeUnit.SECONDS);
- } catch (TimeoutException | ExecutionException | CancellationException | InterruptedException e) {
+ } catch (TimeoutException | ExecutionException | CancellationException e) {
}
Platform.exit();
System.exit(0);
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/MapConfig.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/MapConfig.java
new file mode 100644
index 00000000..e61c63ff
--- /dev/null
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/MapConfig.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2019, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory
+* CODE-743439.
+* All rights reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at:
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and limitations under the license.
+*
+* This work was performed under the auspices of the U.S. Department of Energy
+* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344.
+*/
+package gov.llnl.gnem.apps.coda.calibration.gui;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+import gov.llnl.gnem.apps.coda.common.mapping.MapProperties;
+
+@Configuration
+@Component
+public class MapConfig {
+
+ private AppProperties props;
+
+ public MapConfig(AppProperties props) {
+ super();
+ this.props = props;
+ }
+
+ @Bean
+ public MapProperties getMapProperties() {
+ return new MapProperties().setLayers(props.getWmsLayers());
+ }
+}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java
index 47791487..9fb1c855 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/CodaParamLoadingController.java
@@ -25,7 +25,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -38,12 +37,11 @@
import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersFI;
import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersPS;
import gov.llnl.gnem.apps.coda.calibration.model.domain.ReferenceMwParameters;
+import gov.llnl.gnem.apps.coda.calibration.model.domain.VelocityConfiguration;
import gov.llnl.gnem.apps.coda.common.model.domain.SharedFrequencyBandParameters;
import reactor.core.publisher.Mono;
-//TODO: This class needs a GUI to display a list of files it's attempting to load and process + pass/fail indicators
@Component
-@ConfigurationProperties("coda.param.client")
public class CodaParamLoadingController {
private static final Logger log = LoggerFactory.getLogger(CodaParamLoadingController.class);
@@ -85,67 +83,77 @@ public void loadFiles(List files) {
}
protected void convertFiles(List validFiles) {
- fileConverters.stream().forEach(fileConverter -> fileConverter.convertFiles(validFiles).subscribe(result -> {
- // TODO: Feedback to the user about failure causes!
- if (result.isSuccess()) {
- Optional> res = result.getResultPayload();
- if (res.isPresent()) {
- if (res.get() instanceof SharedFrequencyBandParameters) {
- SharedFrequencyBandParameters sfb = (SharedFrequencyBandParameters) res.get();
- try {
- Mono request = paramsClient.setSharedFrequencyBandParameter(sfb);
- if (request != null) {
- request.retry(3).subscribe();
- } else {
- log.error("Returned a null request from the parameter client while posting SharedFrequencyBandParameters {}", sfb);
- }
- } catch (JsonProcessingException ex) {
- log.trace(ex.getMessage(), ex);
- }
- } else if (res.get() instanceof MdacParametersPS) {
- MdacParametersPS entry = (MdacParametersPS) res.get();
- try {
- Mono request = paramsClient.setPsParameter(entry);
- if (request != null) {
- request.retry(3).subscribe();
- } else {
- log.error("Returned a null request from the parameter client while posting MdacParametersPS {}", entry);
- }
- } catch (JsonProcessingException ex) {
- log.trace(ex.getMessage(), ex);
- }
- } else if (res.get() instanceof MdacParametersFI) {
- MdacParametersFI entry = (MdacParametersFI) res.get();
- try {
- Mono request = paramsClient.setFiParameter(entry);
- if (request != null) {
- request.retry(3).subscribe();
- } else {
- log.error("Returned a null request from the parameter client while posting MdacParametersFI {}", entry);
- }
- } catch (JsonProcessingException ex) {
- log.trace(ex.getMessage(), ex);
- }
- } else if (res.get() instanceof ReferenceMwParameters) {
- ReferenceMwParameters entry = (ReferenceMwParameters) res.get();
- try {
- Mono request = refMwClient.postReferenceEvents(Collections.singletonList(entry));
- if (request != null) {
- request.retry(3).subscribe();
- } else {
- log.error("Returned a null request from the parameter client while posting MdacParametersFI {}", entry);
- }
- } catch (JsonProcessingException ex) {
- log.trace(ex.getMessage(), ex);
- }
- }
- }
- }
- }));
+ fileConverters.stream()
+ .forEach(fileConverter -> fileConverter.convertFiles(validFiles)
+ .subscribe(result -> {
+ // TODO: Feedback to the user about failure causes!
+ if (result.isSuccess()) {
+ Optional> res = result.getResultPayload();
+ if (res.isPresent()) {
+ if (res.get() instanceof SharedFrequencyBandParameters) {
+ SharedFrequencyBandParameters sfb = (SharedFrequencyBandParameters) res.get();
+ try {
+ Mono request = paramsClient.setSharedFrequencyBandParameter(sfb);
+ if (request != null) {
+ request.retry(3).subscribe();
+ } else {
+ log.error("Returned a null request from the parameter client while posting SharedFrequencyBandParameters {}", sfb);
+ }
+ } catch (JsonProcessingException ex) {
+ log.trace(ex.getMessage(), ex);
+ }
+ } else if (res.get() instanceof MdacParametersPS) {
+ MdacParametersPS entry = (MdacParametersPS) res.get();
+ try {
+ Mono request = paramsClient.setPsParameter(entry);
+ if (request != null) {
+ request.retry(3).subscribe();
+ } else {
+ log.error("Returned a null request from the parameter client while posting MdacParametersPS {}", entry);
+ }
+ } catch (JsonProcessingException ex) {
+ log.trace(ex.getMessage(), ex);
+ }
+ } else if (res.get() instanceof MdacParametersFI) {
+ MdacParametersFI entry = (MdacParametersFI) res.get();
+ try {
+ Mono request = paramsClient.setFiParameter(entry);
+ if (request != null) {
+ request.retry(3).subscribe();
+ } else {
+ log.error("Returned a null request from the parameter client while posting MdacParametersFI {}", entry);
+ }
+ } catch (JsonProcessingException ex) {
+ log.trace(ex.getMessage(), ex);
+ }
+ } else if (res.get() instanceof ReferenceMwParameters) {
+ ReferenceMwParameters entry = (ReferenceMwParameters) res.get();
+ try {
+ Mono request = refMwClient.postReferenceEvents(Collections.singletonList(entry));
+ if (request != null) {
+ request.retry(3).subscribe();
+ } else {
+ log.error("Returned a null request from the parameter client while posting ReferenceMwParameters {}", entry);
+ }
+ } catch (JsonProcessingException ex) {
+ log.trace(ex.getMessage(), ex);
+ }
+ } else if (res.get() instanceof VelocityConfiguration) {
+ VelocityConfiguration entry = (VelocityConfiguration) res.get();
+ Mono request = paramsClient.updateVelocityConfiguration(entry);
+ if (request != null) {
+ request.retry(3).subscribe();
+ } else {
+ log.error("Returned a null request from the parameter client while posting VelocityConfiguration {}", entry);
+ }
+ }
+ }
+ }
+ }));
}
private boolean validPath(Path p) {
- Optional> match = Optional.ofNullable(fileConverters).orElse(Collections.emptyList()).stream().filter(fc -> fc.getMatchingPattern().matches(p)).findAny();
+ Optional> match = Optional.ofNullable(fileConverters).orElseGet(() -> Collections.emptyList()).stream().filter(fc -> fc.getMatchingPattern().matches(p)).findAny();
return match.isPresent();
}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java
index 3a102562..3659254b 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/DataController.java
@@ -16,20 +16,27 @@
import java.text.NumberFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
+import javax.annotation.PreDestroy;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
import gov.llnl.gnem.apps.coda.calibration.gui.plotting.MapPlottingUtilities;
import gov.llnl.gnem.apps.coda.common.gui.data.client.api.WaveformClient;
@@ -44,18 +51,24 @@
import gov.llnl.gnem.apps.coda.common.model.domain.Station;
import gov.llnl.gnem.apps.coda.common.model.domain.Stream;
import gov.llnl.gnem.apps.coda.common.model.domain.Waveform;
+import gov.llnl.gnem.apps.coda.common.model.messaging.WaveformChangeEvent;
+import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
+import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
+import javafx.scene.input.MouseButton;
+import javafx.scene.input.MouseEvent;
@Component
public class DataController implements MapListeningController, RefreshableController {
@@ -71,6 +84,9 @@ public class DataController implements MapListeningController, RefreshableContro
@FXML
private CheckBox selectAllCheckbox;
+ @FXML
+ private TableColumn usedCol;
+
@FXML
private TableColumn stationCol;
@@ -101,6 +117,15 @@ public class DataController implements MapListeningController, RefreshableContro
private final BiConsumer eventSelectionCallback;
private final BiConsumer stationSelectionCallback;
+ private ScheduledExecutorService scheduled = Executors.newSingleThreadScheduledExecutor(r -> {
+ Thread thread = new Thread(r);
+ thread.setDaemon(true);
+ return thread;
+ });
+
+ private List dataUpdateList = Collections.synchronizedList(new ArrayList<>());
+ private List dataDeleteList = Collections.synchronizedList(new ArrayList<>());
+ private List updatedData = Collections.synchronizedList(new ArrayList<>());
@Autowired
public DataController(WaveformClient client, GeoMap mapImpl, MapPlottingUtilities iconFactory, EventBus bus) {
@@ -111,6 +136,7 @@ public DataController(WaveformClient client, GeoMap mapImpl, MapPlottingUtilitie
this.bus = bus;
bus.register(this);
tableChangeListener = buildTableListener();
+ scheduled.scheduleWithFixedDelay(() -> updateData(), 1000l, 1000l, TimeUnit.MILLISECONDS);
eventSelectionCallback = (selected, eventId) -> {
selectDataByCriteria(bus, selected, (w) -> w.getEvent() != null && w.getEvent().getEventId().equalsIgnoreCase(eventId));
@@ -126,13 +152,17 @@ private void selectDataByCriteria(EventBus bus, Boolean selected, Function selectionIndices = new ArrayList<>();
tableView.getSelectionModel().clearSelection();
if (selected) {
- for (int i = 0; i < listData.size(); i++) {
- Waveform w = listData.get(i);
- if (matchCriteria.apply(w)) {
- selection.add(w);
- tableView.getSelectionModel().select(i);
+ tableView.getSelectionModel().getSelectedItems().removeListener(tableChangeListener);
+ synchronized (listData) {
+ for (int i = 0; i < listData.size(); i++) {
+ Waveform w = listData.get(i);
+ if (matchCriteria.apply(w)) {
+ selection.add(w);
+ tableView.getSelectionModel().select(i);
+ }
}
}
+ tableView.getSelectionModel().getSelectedItems().addListener(tableChangeListener);
if (!selection.isEmpty()) {
selection.sort(eventStaFreqComparator);
Long[] ids = selection.stream().sequential().map(w -> w.getId()).collect(Collectors.toList()).toArray(new Long[0]);
@@ -154,11 +184,15 @@ private ListChangeListener super Waveform> buildTableListener() {
List selection = new ArrayList<>();
selection.addAll(tableView.getSelectionModel().getSelectedItems());
selection.sort(eventStaFreqComparator);
- Long[] ids = selection.stream().sequential().map(w -> w.getId()).collect(Collectors.toList()).toArray(new Long[0]);
+ Long[] ids = getIds(selection).toArray(new Long[0]);
bus.post(new WaveformSelectionEvent(ids));
};
}
+ private List getIds(List selection) {
+ return selection.stream().sequential().map(w -> w.getId()).collect(Collectors.toList());
+ }
+
@FXML
private void reloadTable(ActionEvent e) {
CompletableFuture.runAsync(getRefreshFunction());
@@ -167,7 +201,6 @@ private void reloadTable(ActionEvent e) {
@FXML
public void initialize() {
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
-
eventCol.setCellValueFactory(
x -> Bindings.createStringBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(Waveform::getEvent).map(Event::getEventId).orElseGet(String::new)));
eventCol.comparatorProperty().set(new MaybeNumericStringComparator());
@@ -175,6 +208,23 @@ public void initialize() {
CellBindingUtils.attachTextCellFactories(lowFreqCol, Waveform::getLowFrequency, dfmt2);
CellBindingUtils.attachTextCellFactories(highFreqCol, Waveform::getHighFrequency, dfmt2);
+ usedCol.setCellValueFactory(x -> Bindings.createObjectBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(waveform -> {
+ CheckBox box = new CheckBox();
+ box.setSelected(waveform.isActive());
+ if (!waveform.isActive()) {
+ box.setStyle("-fx-background-color: red");
+ } else {
+ box.setStyle("");
+ }
+ box.selectedProperty().addListener((obs, o, n) -> {
+ if (n != null && o != n) {
+ client.setWaveformsActiveByIds(Collections.singletonList(waveform.getId()), n).subscribe();
+ }
+ });
+ return box;
+ }).orElseGet(CheckBox::new)));
+ usedCol.comparatorProperty().set((c1, c2) -> Boolean.compare(c1.isSelected(), c2.isSelected()));
+
stationCol.setCellValueFactory(
x -> Bindings.createStringBinding(
() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(Waveform::getStream).map(Stream::getStation).map(Station::getStationName).orElseGet(String::new)));
@@ -186,18 +236,49 @@ public void initialize() {
tableView.getSelectionModel().clearSelection();
}
});
+
+ ContextMenu menu = new ContextMenu();
+ MenuItem include = new MenuItem("Include Selected");
+ include.setOnAction(evt -> includeWaveforms());
+ menu.getItems().add(include);
+ MenuItem exclude = new MenuItem("Exclude Selected");
+ exclude.setOnAction(evt -> excludeWaveforms());
+ menu.getItems().add(exclude);
+
+ tableView.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler() {
+ @Override
+ public void handle(MouseEvent t) {
+ if (MouseButton.SECONDARY == t.getButton()) {
+ menu.show(tableView, t.getScreenX(), t.getScreenY());
+ } else {
+ menu.hide();
+ }
+ }
+ });
+
tableView.setItems(listData);
}
@Override
public void refreshView() {
- if (listData.isEmpty()) {
- CompletableFuture.runAsync(getRefreshFunction());
- } else {
- CompletableFuture.runAsync(() -> {
- mapImpl.clearIcons();
- listData.forEach(waveform -> mapImpl.addIcons(genIconsFromData(waveform)));
+ CompletableFuture.runAsync(() -> {
+ synchronized (listData) {
+ if (!listData.isEmpty()) {
+ refreshMap();
+ }
+ }
+ Platform.runLater(() -> {
+ if (tableView != null) {
+ tableView.refresh();
+ }
});
+ });
+ }
+
+ private void refreshMap() {
+ mapImpl.clearIcons();
+ synchronized (listData) {
+ listData.forEach(waveform -> mapImpl.addIcons(genIconsFromData(waveform)));
}
}
@@ -207,16 +288,95 @@ public Runnable getRefreshFunction() {
}
private void requestData() {
- listData.clear();
+ synchronized (listData) {
+ listData.clear();
+ }
mapImpl.clearIcons();
client.getUniqueEventStationMetadataForStacks().filter(Objects::nonNull).doOnComplete(() -> {
tableView.sort();
refreshView();
}).subscribe(waveform -> {
- listData.add(waveform);
+ synchronized (listData) {
+ listData.add(waveform);
+ }
}, err -> log.error(err.getMessage(), err));
}
+ private void requestUpdates() {
+ List updates = new ArrayList();
+ List deletes = new ArrayList();
+ synchronized (dataUpdateList) {
+ updates.addAll(dataUpdateList);
+ dataUpdateList.clear();
+ deletes.addAll(dataDeleteList);
+ dataDeleteList.clear();
+ }
+
+ if (!deletes.isEmpty()) {
+ synchronized (listData) {
+ deletes.forEach(id -> {
+ synchronized (listData) {
+ int idx = -1;
+ for (int i = 0; i < listData.size(); i++) {
+ if (listData.get(i).getId().equals(id)) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx >= 0) {
+ listData.remove(idx);
+ }
+ }
+ });
+ }
+ }
+
+ client.getWaveformMetadataFromIds(updates).filter(Objects::nonNull).subscribe(waveform -> updatedData.add(waveform), err -> log.error(err.getMessage(), err));
+ }
+
+ private void updateData() {
+ List updates = new ArrayList<>();
+ synchronized (updatedData) {
+ updates.addAll(updatedData);
+ updatedData.clear();
+ }
+ if (!updates.isEmpty()) {
+ synchronized (listData) {
+ tableView.getSelectionModel().getSelectedItems().removeListener(tableChangeListener);
+ updates.forEach(waveform -> {
+ int idx = -1;
+ for (int i = 0; i < listData.size(); i++) {
+ if (listData.get(i).getId().equals(waveform.getId())) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx >= 0) {
+ listData.set(idx, waveform);
+ } else {
+ listData.add(waveform);
+ }
+ });
+ tableView.getSelectionModel().getSelectedItems().addListener(tableChangeListener);
+ }
+ if (tableView.isVisible()) {
+ refreshMap();
+ }
+ }
+ }
+
+ private void excludeWaveforms() {
+ client.setWaveformsActiveByIds(getSelectedWaveforms(), false).subscribe();
+ }
+
+ private void includeWaveforms() {
+ client.setWaveformsActiveByIds(getSelectedWaveforms(), true).subscribe();
+ }
+
+ private List getSelectedWaveforms() {
+ return getIds(tableView.getSelectionModel().getSelectedItems());
+ }
+
protected List genIconsFromData(Waveform waveform) {
List icons = new ArrayList<>();
if (waveform != null && waveform.getStream() != null && waveform.getEvent() != null) {
@@ -226,4 +386,21 @@ protected List genIconsFromData(Waveform waveform) {
return icons;
}
+ @Subscribe
+ private void listener(WaveformChangeEvent wce) {
+ List nonNull = wce.getIds().stream().filter(Objects::nonNull).collect(Collectors.toList());
+ synchronized (dataUpdateList) {
+ if (wce.isAddOrUpdate()) {
+ dataUpdateList.addAll(nonNull);
+ } else if (wce.isDelete()) {
+ dataDeleteList.addAll(nonNull);
+ }
+ }
+ requestUpdates();
+ }
+
+ @PreDestroy
+ private void cleanup() {
+ scheduled.shutdownNow();
+ }
}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/EnvelopeLoadingController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/EnvelopeLoadingController.java
index 56f2401f..b3aeca28 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/EnvelopeLoadingController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/EnvelopeLoadingController.java
@@ -20,7 +20,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import com.google.common.eventbus.EventBus;
@@ -29,21 +28,19 @@
import gov.llnl.gnem.apps.coda.common.gui.converters.api.FileToEnvelopeConverter;
import gov.llnl.gnem.apps.coda.common.gui.converters.sac.SacExporter;
import gov.llnl.gnem.apps.coda.common.gui.data.client.api.WaveformClient;
-import gov.llnl.gnem.apps.coda.common.gui.events.EnvelopeLoadCompleteEvent;
import gov.llnl.gnem.apps.coda.common.gui.util.ProgressEventProgressListener;
import gov.llnl.gnem.apps.coda.common.gui.util.ProgressMonitor;
import gov.llnl.gnem.apps.coda.common.model.messaging.Progress;
import gov.llnl.gnem.apps.coda.common.model.messaging.ProgressEvent;
@Component
-@ConfigurationProperties("waveform.client")
public class EnvelopeLoadingController extends AbstractSeismogramSaveLoadController {
private static final Logger log = LoggerFactory.getLogger(EnvelopeLoadingController.class);
@Autowired
public EnvelopeLoadingController(List fileConverters, WaveformClient client, EventBus bus, SacExporter sacExporter) {
- super(fileConverters, bus, log, sacExporter, () -> client.getAllStacks(), (id, waveforms) -> client.postWaveforms(id, waveforms));
+ super(fileConverters, bus, log, sacExporter, () -> client.getAllActiveStacks(), (id, waveforms) -> client.postWaveforms(id, waveforms));
}
@Override
@@ -52,7 +49,6 @@ public void loadFiles(List inputFiles) {
ProgressEvent progressEvent = new ProgressEvent(idCounter.getAndIncrement(), progress);
ProgressMonitor progressMonitor = new ProgressMonitor("Data Processing", new ProgressEventProgressListener(bus, progressEvent));
super.loadFiles(inputFiles, () -> {
- bus.post(new EnvelopeLoadCompleteEvent());
progress.setTotal(1l);
progress.setCurrent(1l);
bus.post(progressEvent);
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/PathController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/PathController.java
index 43086ef6..509bc0d5 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/PathController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/PathController.java
@@ -31,6 +31,7 @@
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
+import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -48,6 +49,7 @@
import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.SpectraClient;
import gov.llnl.gnem.apps.coda.calibration.gui.plotting.MapPlottingUtilities;
import gov.llnl.gnem.apps.coda.calibration.model.domain.SpectraMeasurement;
+import gov.llnl.gnem.apps.coda.common.gui.data.client.api.WaveformClient;
import gov.llnl.gnem.apps.coda.common.gui.events.WaveformSelectionEvent;
import gov.llnl.gnem.apps.coda.common.gui.util.EventStaFreqStringComparator;
import gov.llnl.gnem.apps.coda.common.gui.util.NumberFormatFactory;
@@ -62,10 +64,15 @@
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.embed.swing.SwingNode;
+import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
+import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
+import javafx.scene.control.MenuItem;
import javafx.scene.control.Tooltip;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.Pane;
import llnl.gnem.core.gui.plotting.JBasicPlot;
import llnl.gnem.core.gui.plotting.MouseOverPlotObject;
import llnl.gnem.core.gui.plotting.PaintMode;
@@ -107,7 +114,11 @@ public class PathController implements MapListeningController, RefreshableContro
@FXML
SwingNode sdPlotSwingNode;
+ @FXML
+ Pane path;
+
private SpectraClient spectraMeasurementClient;
+ private WaveformClient waveformClient;
private GeoMap mapImpl;
@@ -127,11 +138,15 @@ public class PathController implements MapListeningController, RefreshableContro
private final BiConsumer eventSelectionCallback;
private final BiConsumer stationSelectionCallback;
private final List selectedSymbols = new ArrayList<>();
+ private MenuItem exclude;
+ private MenuItem include;
+ private ContextMenu menu;
@Autowired
- public PathController(SpectraClient spectraMeasurementClient, EventBus bus, GeoMap mapImpl, MapPlottingUtilities mappingUtilities) {
+ public PathController(SpectraClient spectraMeasurementClient, WaveformClient waveformClient, EventBus bus, GeoMap mapImpl, MapPlottingUtilities mappingUtilities) {
super();
this.spectraMeasurementClient = spectraMeasurementClient;
+ this.waveformClient = waveformClient;
this.mapImpl = mapImpl;
this.mappingUtilities = mappingUtilities;
this.bus = bus;
@@ -214,7 +229,7 @@ public void update(Observable observable, Object obj) {
if (obj instanceof MouseOverPlotObject) {
MouseOverPlotObject pos = (MouseOverPlotObject) obj;
PlotObject po = pos.getPlotObject();
- if (po != null && po instanceof Symbol) {
+ if (po instanceof Symbol) {
Platform.runLater(() -> {
stationPlotTooltip.setText(((Symbol) po).getText());
Point p = MouseInfo.getPointerInfo().getLocation();
@@ -228,14 +243,9 @@ public void update(Observable observable, Object obj) {
if (obj instanceof PlotObjectClicked && ((PlotObjectClicked) obj).getMouseEvent().getID() == MouseEvent.MOUSE_RELEASED) {
PlotObjectClicked poc = (PlotObjectClicked) obj;
PlotObject po = poc.getPlotObject();
- if (po != null && po instanceof Symbol) {
- TreeSet sortedSet = new TreeSet(evStaComparator);
- sortedSet.addAll(stationSymbolMap.get(new Point2D.Double(((Symbol) po).getXcenter(), ((Symbol) po).getYcenter())));
- List ids = sortedSet.stream().sequential().map(w -> w.getId()).collect(Collectors.toList());
- if (ids != null) {
- selectSymbolsForWaveforms(sortedSet);
- selectWaveforms(ids.toArray(new Long[0]));
- }
+ if (po instanceof Symbol) {
+ List waveforms = stationSymbolMap.get(new Point2D.Double(((Symbol) po).getXcenter(), ((Symbol) po).getYcenter()));
+ handlePlotObjectClicked(poc, waveforms);
}
}
}
@@ -253,7 +263,7 @@ public void update(Observable observable, Object obj) {
if (obj instanceof MouseOverPlotObject) {
MouseOverPlotObject pos = (MouseOverPlotObject) obj;
PlotObject po = pos.getPlotObject();
- if (po != null && po instanceof Symbol) {
+ if (po instanceof Symbol) {
Platform.runLater(() -> {
sdPlotTooltip.setText(((Symbol) po).getText());
Point p = MouseInfo.getPointerInfo().getLocation();
@@ -267,14 +277,9 @@ public void update(Observable observable, Object obj) {
if (obj instanceof PlotObjectClicked && ((PlotObjectClicked) obj).getMouseEvent().getID() == MouseEvent.MOUSE_RELEASED) {
PlotObjectClicked poc = (PlotObjectClicked) obj;
PlotObject po = poc.getPlotObject();
- if (po != null && po instanceof Symbol) {
- TreeSet sortedSet = new TreeSet(evStaComparator);
- sortedSet.addAll(sdSymbolMap.get(new Point2D.Double(((Symbol) po).getXcenter(), ((Symbol) po).getYcenter())));
- List ids = sortedSet.stream().sequential().map(w -> w.getId()).collect(Collectors.toList());
- if (ids != null) {
- selectSymbolsForWaveforms(sortedSet);
- selectWaveforms(ids.toArray(new Long[0]));
- }
+ if (po instanceof Symbol) {
+ List waveforms = sdSymbolMap.get(new Point2D.Double(((Symbol) po).getXcenter(), ((Symbol) po).getYcenter()));
+ handlePlotObjectClicked(poc, waveforms);
}
}
}
@@ -301,9 +306,51 @@ public void update(Observable observable, Object obj) {
station1ComboBox.valueProperty().addListener(e -> refreshView());
station2ComboBox.valueProperty().addListener(e -> refreshView());
+
+ menu = new ContextMenu();
+ include = new MenuItem("Include Selected");
+ menu.getItems().add(include);
+ exclude = new MenuItem("Exclude Selected");
+ menu.getItems().add(exclude);
+
+ EventHandler menuHideHandler = (evt) -> {
+ if (MouseButton.SECONDARY != evt.getButton()) {
+ menu.hide();
+ }
+ };
+ path.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, menuHideHandler);
+ sdPlotSwingNode.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, menuHideHandler);
+ stationPlotSwingNode.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, menuHideHandler);
+ }
+
+ private void setSymbolsActive(List ws, Boolean active) {
+ SwingUtilities.invokeLater(() -> {
+ ws.stream().flatMap(w -> Optional.ofNullable(stationWaveformMap.get(w.getEvent().getEventId())).orElseGet(() -> new ArrayList<>()).stream()).forEach(sym -> {
+ if (active) {
+ sym.setFillColor(sym.getEdgeColor());
+ } else {
+ sym.setFillColor(Color.GRAY);
+ }
+ });
+ Platform.runLater(() -> {
+ stationPlot.repaint();
+ });
+ });
+ }
+
+ private void showContextMenu(List waveforms, MouseEvent t, BiConsumer, Boolean> activationFunc) {
+ Platform.runLater(() -> {
+ include.setOnAction(evt -> setActive(waveforms, true, activationFunc));
+ exclude.setOnAction(evt -> setActive(waveforms, false, activationFunc));
+ menu.show(path, t.getXOnScreen(), t.getYOnScreen());
+ });
+ }
+
+ private void setActive(List waveforms, boolean active, BiConsumer, Boolean> activationFunc) {
+ waveformClient.setWaveformsActiveByIds(waveforms.stream().map(w -> w.getId()).collect(Collectors.toList()), active).subscribe(s -> activationFunc.accept(waveforms, active));
}
- protected void selectSymbolsForWaveforms(Collection sortedSet) {
+ private void selectSymbolsForWaveforms(Collection sortedSet) {
if (!selectedSymbols.isEmpty()) {
deselectSymbols(selectedSymbols);
selectedSymbols.clear();
@@ -349,7 +396,7 @@ private void reloadData() {
frequencyBandComboBox.getItems().clear();
measurementsFreqBandMap.putAll(
- spectraMeasurementClient.getMeasuredSpectra()
+ spectraMeasurementClient.getMeasuredSpectraMetadata()
.filter(Objects::nonNull)
.filter(spectra -> spectra.getWaveform() != null)
.toStream()
@@ -501,7 +548,6 @@ private void plotSd() {
}
for (Entry, Double> distanceStaPair : distanceStaPairs.entrySet()) {
-
Pair staPair = distanceStaPair.getKey();
if (Double.isNaN(beforeStatsStaPairs.get(staPair).getStandardDeviation()) || beforeStatsStaPairs.get(staPair).getStandardDeviation() == 0.0) {
continue;
@@ -621,7 +667,7 @@ private void plotBeforeAfter() {
TriangleUp plotObj = new TriangleUp(firstMeasurement.getRawAtMeasurementTime(),
secondMeasurement.getRawAtMeasurementTime(),
5.0,
- Color.RED,
+ firstMeasurement.getWaveform().isActive() ? Color.RED : Color.GRAY,
Color.RED,
Color.RED,
firstStation.getStationName(),
@@ -633,7 +679,7 @@ private void plotBeforeAfter() {
TriangleDn plotObj2 = new TriangleDn(firstMeasurement.getPathCorrected(),
secondMeasurement.getPathCorrected(),
5.0,
- Color.BLUE,
+ firstMeasurement.getWaveform().isActive() ? Color.BLUE : Color.GRAY,
Color.BLUE,
Color.BLUE,
secondStation.getStationName(),
@@ -744,4 +790,21 @@ private void plotBeforeAfter() {
});
}
}
+
+ private void handlePlotObjectClicked(PlotObjectClicked poc, List waveforms) {
+ if (waveforms != null) {
+ if (SwingUtilities.isLeftMouseButton(poc.getMouseEvent())) {
+ TreeSet sortedSet = new TreeSet(evStaComparator);
+ sortedSet.addAll(waveforms);
+ List ids = sortedSet.stream().sequential().map(w -> w.getId()).collect(Collectors.toList());
+ selectSymbolsForWaveforms(sortedSet);
+ selectWaveforms(ids.toArray(new Long[0]));
+ Platform.runLater(() -> menu.hide());
+ } else if (SwingUtilities.isRightMouseButton(poc.getMouseEvent())) {
+ showContextMenu(waveforms, poc.getMouseEvent(), (ws, active) -> {
+ setSymbolsActive(ws, active);
+ });
+ }
+ }
+ }
}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/ShapeController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/ShapeController.java
index 0c285ac0..f115a3b5 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/ShapeController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/ShapeController.java
@@ -17,6 +17,7 @@
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -40,15 +41,18 @@
import gov.llnl.gnem.apps.coda.calibration.gui.plotting.MapPlottingUtilities;
import gov.llnl.gnem.apps.coda.calibration.model.domain.PeakVelocityMeasurement;
import gov.llnl.gnem.apps.coda.calibration.model.domain.ShapeMeasurement;
+import gov.llnl.gnem.apps.coda.common.gui.data.client.api.WaveformClient;
import gov.llnl.gnem.apps.coda.common.gui.events.WaveformSelectionEvent;
import gov.llnl.gnem.apps.coda.common.gui.util.EventStaFreqStringComparator;
import gov.llnl.gnem.apps.coda.common.gui.util.NumberFormatFactory;
import gov.llnl.gnem.apps.coda.common.mapping.api.GeoMap;
import gov.llnl.gnem.apps.coda.common.mapping.api.Icon;
import gov.llnl.gnem.apps.coda.common.model.domain.FrequencyBand;
+import gov.llnl.gnem.apps.coda.common.model.domain.Pair;
import gov.llnl.gnem.apps.coda.common.model.domain.SharedFrequencyBandParameters;
import gov.llnl.gnem.apps.coda.common.model.domain.Station;
import gov.llnl.gnem.apps.coda.common.model.domain.Waveform;
+import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.Event;
@@ -59,9 +63,14 @@
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.ComboBox;
+import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
+import javafx.scene.control.MenuItem;
+import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
+import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.StackPane;
+import javafx.scene.transform.Affine;
@Component
public class ShapeController implements MapListeningController, RefreshableController {
@@ -79,10 +88,13 @@ private enum SHAPE_DATA_TYPE {
private static final int XAXIS_MIN = 0;
private static final int XAXIS_MAX = 5000;
private static final double LINE_SEGMENTS = 250.0;
+ private static final double SCALE_IN = 1.5;
+ private static final double SCALE_OUT = 0.5;
private Map> velocityDistancePairsFreqMap = new HashMap<>();
private Map> shapeDistancePairsFreqMap = new HashMap<>();
private Map modelCurveMap = new TreeMap<>();
+ private Map, List>> waveformIdMapping = new HashMap<>();
private EventStaFreqStringComparator eventStaFreqComparator = new EventStaFreqStringComparator();
@FXML
@@ -106,6 +118,7 @@ private enum SHAPE_DATA_TYPE {
private ParameterClient paramClient;
private PeakVelocityClient velocityClient;
private ShapeMeasurementClient shapeClient;
+ private WaveformClient waveformClient;
private NumberFormat dfmt = NumberFormatFactory.twoDecimalOneLeadingZero();
private ObservableList> modelData = FXCollections.observableArrayList();
@@ -126,12 +139,17 @@ private enum SHAPE_DATA_TYPE {
private final BiConsumer eventSelectionCallback;
private final BiConsumer stationSelectionCallback;
private FrequencyBand selectedBand;
+ private MenuItem exclude;
+ private MenuItem include;
+ private ContextMenu menu;
@Autowired
- private ShapeController(ParameterClient paramClient, PeakVelocityClient velocityClient, ShapeMeasurementClient shapeClient, GeoMap map, MapPlottingUtilities iconFactory, EventBus bus) {
+ private ShapeController(ParameterClient paramClient, PeakVelocityClient velocityClient, ShapeMeasurementClient shapeClient, WaveformClient waveformClient, GeoMap map,
+ MapPlottingUtilities iconFactory, EventBus bus) {
this.paramClient = paramClient;
this.velocityClient = velocityClient;
this.shapeClient = shapeClient;
+ this.waveformClient = waveformClient;
this.bus = bus;
this.mapImpl = map;
this.iconFactory = iconFactory;
@@ -182,7 +200,6 @@ private void selectDataByCriteria(EventBus bus, Boolean selected, String key) {
@FXML
public void initialize() {
-
mainFitPlot.setAnimated(false);
yAxis.setAutoRanging(false);
@@ -220,8 +237,40 @@ public void initialize() {
mainFitPlot.setData(series);
mainFitPlot.setLegendVisible(false);
modelCurveSeries.getNode().setMouseTransparent(true);
+ modelCurveSeries.getNode().toFront();
+
selectedSeries.getNode().setMouseTransparent(true);
highlightedSeries.getNode().setMouseTransparent(true);
+
+ mainFitPlot.addEventHandler(MouseEvent.MOUSE_CLICKED, (evt) -> {
+ if (MouseButton.SECONDARY != evt.getButton()) {
+ menu.hide();
+ }
+ });
+
+ final Affine scaleTrans = new Affine();
+ mainFitPlot.getTransforms().add(scaleTrans);
+
+ mainFitPlot.setOnScroll(new EventHandler() {
+ @Override
+ public void handle(ScrollEvent event) {
+ if (event.getDeltaY() < 0) {
+ if (mainFitPlot.getScaleX() * SCALE_OUT < 1.0) {
+ scaleTrans.setToIdentity();
+ } else {
+ scaleTrans.appendScale(SCALE_OUT, SCALE_OUT, event.getX(), event.getY());
+ }
+ } else {
+ scaleTrans.appendScale(SCALE_IN, SCALE_IN, event.getX(), event.getY());
+ }
+ }
+ });
+
+ menu = new ContextMenu();
+ include = new MenuItem("Include Selected");
+ menu.getItems().add(include);
+ exclude = new MenuItem("Exclude Selected");
+ menu.getItems().add(exclude);
}
private ListCell getFBCell() {
@@ -289,7 +338,13 @@ private void plotGamma(final FrequencyBand selectedFrequency) {
Function> valueSupplier = createValueSupplier(shapeDistancePairsFreqMap);
Function mapFunc = ShapeMeasurement::getWaveform;
mapValues(selectedFrequency, valueSupplier, mapFunc);
- plot(selectedFrequency, valueSupplier, val -> new Data<>(val.getDistance(), val.getMeasuredGamma()), val -> showWaveformPopup(val.getWaveform()), curvePointProducer, mapFunc);
+ plot(
+ selectedFrequency,
+ valueSupplier,
+ val -> new Data<>(val.getDistance(), val.getMeasuredGamma()),
+ (data, val) -> clickEventHandler(data, val.getWaveform()),
+ curvePointProducer,
+ mapFunc);
}
}
@@ -302,7 +357,7 @@ private void plotBeta(final FrequencyBand selectedFrequency) {
Function> valueSupplier = createValueSupplier(shapeDistancePairsFreqMap);
Function mapFunc = ShapeMeasurement::getWaveform;
mapValues(selectedFrequency, valueSupplier, mapFunc);
- plot(selectedFrequency, valueSupplier, val -> new Data<>(val.getDistance(), val.getMeasuredBeta()), val -> showWaveformPopup(val.getWaveform()), curvePointProducer, mapFunc);
+ plot(selectedFrequency, valueSupplier, val -> new Data<>(val.getDistance(), val.getMeasuredBeta()), (data, val) -> clickEventHandler(data, val.getWaveform()), curvePointProducer, mapFunc);
}
}
@@ -315,7 +370,47 @@ private void plotVelocity(final FrequencyBand selectedFrequency) {
Function> valueSupplier = createValueSupplier(velocityDistancePairsFreqMap);
Function mapFunc = PeakVelocityMeasurement::getWaveform;
mapValues(selectedFrequency, valueSupplier, mapFunc);
- plot(selectedFrequency, valueSupplier, val -> new Data<>(val.getDistance(), val.getVelocity()), val -> showWaveformPopup(val.getWaveform()), curvePointProducer, mapFunc);
+ plot(selectedFrequency, valueSupplier, val -> new Data<>(val.getDistance(), val.getVelocity()), (data, val) -> clickEventHandler(data, val.getWaveform()), curvePointProducer, mapFunc);
+ }
+ }
+
+ private EventHandler clickEventHandler(Data data, Waveform waveform) {
+ return event -> {
+ if (event instanceof MouseEvent) {
+ MouseEvent evt = (MouseEvent) event;
+ if (MouseButton.PRIMARY == evt.getButton()) {
+ showWaveformPopup(waveform);
+ } else if (MouseButton.SECONDARY == evt.getButton()) {
+ showContextMenu(data, waveform, evt);
+ }
+ }
+ };
+ }
+
+ private void showContextMenu(Data data, Waveform waveform, MouseEvent t) {
+ include.setOnAction(evt -> includeWaveforms(data, waveform));
+ exclude.setOnAction(evt -> excludeWaveforms(data, waveform));
+ menu.show(mainFitPlot, t.getScreenX(), t.getScreenY());
+ }
+
+ private void excludeWaveforms(Data data, Waveform waveform) {
+ setActive(data, waveform, false);
+ }
+
+ private void includeWaveforms(Data data, Waveform waveform) {
+ setActive(data, waveform, true);
+ }
+
+ private void setActive(Data data, Waveform waveform, boolean active) {
+ if (waveformClient != null && waveform != null && waveform.getId() != null) {
+ waveformClient.setWaveformsActiveByIds(Collections.singletonList(waveform.getId()), active).subscribe(s -> {
+ Pair, List> pair = waveformIdMapping.get(waveform.getId());
+ if (pair != null) {
+ pair.getLeft().forEach(v -> v.getWaveform().setActive(active));
+ pair.getRight().forEach(v -> v.getWaveform().setActive(active));
+ Platform.runLater(() -> refreshView());
+ }
+ });
}
}
@@ -326,7 +421,7 @@ private void mapValues(final FrequencyBand selectedFrequency, Function Function> createValueSupplier(Map> valueMap) {
Function> valueSupplier;
if (valueMap != null) {
- valueSupplier = freq -> Optional.ofNullable(valueMap.get(freq)).orElse(new ArrayList<>(0));
+ valueSupplier = freq -> Optional.ofNullable(valueMap.get(freq)).orElseGet(() -> new ArrayList<>(0));
} else {
valueSupplier = freq -> new ArrayList<>(0);
}
@@ -343,7 +438,7 @@ private Function> createCurvePointProducer(final Fr
}
private void plot(final FrequencyBand selectedFrequency, Function> valueSupplier, Function> dataPointSupplier,
- Function> mouseClickedCallback, Function> curveProducer, Function mapFunc) {
+ BiFunction, T, EventHandler> mouseClickedCallback, Function> curveProducer, Function mapFunc) {
if (selectedFrequency != null) {
pointMap.clear();
modelData.clear();
@@ -360,21 +455,30 @@ private void plot(final FrequencyBand selectedFrequency, Function data = dataPointSupplier.apply(val);
pointData.add(data);
if (data.getXValue().doubleValue() > maxX.get()) {
- maxX.set(data.getXValue().intValue());
+ maxX.set(Integer.valueOf((int) (data.getXValue().doubleValue() * 1.1)));
}
if (data.getXValue().doubleValue() < minX.get()) {
minX.set(data.getXValue().intValue());
}
- if (data.getXValue().doubleValue() > maxY.get()) {
+ if (data.getYValue().doubleValue() > maxY.get()) {
maxY.set(data.getYValue().doubleValue());
}
if (data.getYValue().doubleValue() < minY.get()) {
minY.set(data.getYValue().doubleValue());
}
- data.getNode().addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedCallback.apply(val));
- data.getNode().toBack();
+ data.getNode().addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedCallback.apply(data, val));
+ data.extraValueProperty().addListener((obs, o, n) -> {
+ if (n instanceof Boolean && data != null && data.getNode() != null) {
+ if ((Boolean) n) {
+ data.getNode().setStyle("");
+ } else {
+ data.getNode().setStyle("-fx-background-color: white, gray;");
+ }
+ }
+ });
+ data.setExtraValue(mapFunc.apply(val).isActive());
Waveform w = mapFunc.apply(val);
boolean eventExists = w != null && w.getEvent() != null && w.getEvent().getEventId() != null;
boolean stationExists = w != null && w.getStream() != null && w.getStream().getStation() != null && w.getStream().getStation().getStationName() != null;
@@ -407,8 +511,10 @@ private void plot(final FrequencyBand selectedFrequency, Function data = curveProducer.apply(i);
modelData.add(data);
data.getNode().setMouseTransparent(true);
+ data.getNode().toFront();
}
}
+ modelCurveSeries.getNode().toFront();
}
}
@@ -426,38 +532,39 @@ private Collection mapMeasurements(List waveforms) {
}).collect(Collectors.toList());
}
- private EventHandler showWaveformPopup(Waveform waveform) {
- return event -> {
- highlightedData.clear();
- List> selection = pointMap.get(waveform.getEvent().getEventId() + waveform.getStream().getStation().getStationName());
- if (selection != null && selection.size() == 1) {
- highlightedData.add(new Data(selection.get(0).getXValue(), selection.get(0).getYValue()));
- highlightedData.forEach(x -> x.getNode().setMouseTransparent(true));
- }
- bus.post(new WaveformSelectionEvent(waveform.getId()));
- };
+ private void showWaveformPopup(Waveform waveform) {
+ highlightedData.clear();
+ List> selection = pointMap.get(waveform.getEvent().getEventId() + waveform.getStream().getStation().getStationName());
+ if (selection != null && selection.size() == 1) {
+ highlightedData.add(new Data(selection.get(0).getXValue(), selection.get(0).getYValue()));
+ highlightedData.forEach(x -> x.getNode().setMouseTransparent(true));
+ }
+ bus.post(new WaveformSelectionEvent(waveform.getId()));
}
private void reloadData() {
velocityDistancePairsFreqMap.clear();
shapeDistancePairsFreqMap.clear();
+ waveformIdMapping.clear();
modelCurveMap.clear();
frequencyBandCombo.getItems().clear();
paramClient.getSharedFrequencyBandParameters().subscribe(sfb -> modelCurveMap.put(new FrequencyBand(sfb.getLowFrequency(), sfb.getHighFrequency()), sfb));
velocityDistancePairsFreqMap.putAll(
- velocityClient.getMeasuredPeakVelocities()
+ velocityClient.getMeasuredPeakVelocitiesMetadata()
.toStream()
.filter(Objects::nonNull)
.filter(pvm -> pvm.getWaveform() != null)
+ .peek(pvm -> waveformIdMapping.computeIfAbsent(pvm.getWaveform().getId(), k -> getMapping(k)).getLeft().add(pvm))
.collect(Collectors.groupingBy(pvm -> new FrequencyBand(pvm.getWaveform().getLowFrequency(), pvm.getWaveform().getHighFrequency()))));
shapeDistancePairsFreqMap.putAll(
- shapeClient.getMeasuredShapes()
+ shapeClient.getMeasuredShapesMetadata()
.toStream()
.filter(Objects::nonNull)
.filter(shape -> shape.getWaveform() != null)
+ .peek(shape -> waveformIdMapping.computeIfAbsent(shape.getWaveform().getId(), k -> getMapping(k)).getRight().add(shape))
.collect(Collectors.groupingBy(shape -> new FrequencyBand(shape.getWaveform().getLowFrequency(), shape.getWaveform().getHighFrequency()))));
frequencyBandCombo.getItems().addAll(modelCurveMap.keySet());
@@ -466,6 +573,10 @@ private void reloadData() {
refreshView();
}
+ private Pair, List> getMapping(Long key) {
+ return new Pair, List>(new ArrayList(), new ArrayList());
+ }
+
@Override
public void refreshView() {
mapImpl.clearIcons();
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java
index e6c1ab1f..05096655 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/SiteController.java
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2018, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory
+* Copyright (c) 2019, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory
* CODE-743439.
* All rights reserved.
* This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool.
@@ -14,14 +14,19 @@
*/
package gov.llnl.gnem.apps.coda.calibration.gui.controllers;
+import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
+import java.lang.reflect.InvocationTargetException;
+import java.text.NumberFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
@@ -33,6 +38,9 @@
import javax.swing.SwingUtilities;
+import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -42,15 +50,17 @@
import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.SpectraClient;
import gov.llnl.gnem.apps.coda.calibration.gui.plotting.MapPlottingUtilities;
import gov.llnl.gnem.apps.coda.calibration.gui.plotting.SpectralPlot;
-import gov.llnl.gnem.apps.coda.calibration.model.domain.MeasuredMwParameters;
-import gov.llnl.gnem.apps.coda.calibration.model.domain.ReferenceMwParameters;
+import gov.llnl.gnem.apps.coda.calibration.model.domain.MeasuredMwDetails;
import gov.llnl.gnem.apps.coda.calibration.model.domain.Spectra;
import gov.llnl.gnem.apps.coda.calibration.model.domain.SpectraMeasurement;
+import gov.llnl.gnem.apps.coda.common.gui.data.client.api.WaveformClient;
import gov.llnl.gnem.apps.coda.common.gui.events.WaveformSelectionEvent;
import gov.llnl.gnem.apps.coda.common.gui.plotting.LabeledPlotPoint;
import gov.llnl.gnem.apps.coda.common.gui.plotting.PlotPoint;
import gov.llnl.gnem.apps.coda.common.gui.plotting.SymbolStyleMapFactory;
+import gov.llnl.gnem.apps.coda.common.gui.util.CellBindingUtils;
import gov.llnl.gnem.apps.coda.common.gui.util.MaybeNumericStringComparator;
+import gov.llnl.gnem.apps.coda.common.gui.util.NumberFormatFactory;
import gov.llnl.gnem.apps.coda.common.mapping.api.GeoMap;
import gov.llnl.gnem.apps.coda.common.mapping.api.Icon;
import gov.llnl.gnem.apps.coda.common.model.domain.Station;
@@ -61,22 +71,62 @@
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.embed.swing.SwingNode;
+import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.image.ImageView;
+import javafx.scene.input.MouseButton;
+import llnl.gnem.core.gui.plotting.HorizPinEdge;
+import llnl.gnem.core.gui.plotting.PaintMode;
+import llnl.gnem.core.gui.plotting.PenStyle;
import llnl.gnem.core.gui.plotting.PlotObjectClicked;
+import llnl.gnem.core.gui.plotting.SymbolLegend;
+import llnl.gnem.core.gui.plotting.SymbolLegend.SymbolTextPair;
+import llnl.gnem.core.gui.plotting.VertPinEdge;
+import llnl.gnem.core.gui.plotting.color.ColorMap;
+import llnl.gnem.core.gui.plotting.color.ViridisColorMap;
+import llnl.gnem.core.gui.plotting.jmultiaxisplot.JMultiAxisPlot;
+import llnl.gnem.core.gui.plotting.jmultiaxisplot.JSubplot;
+import llnl.gnem.core.gui.plotting.plotobject.Circle;
+import llnl.gnem.core.gui.plotting.plotobject.Line;
import llnl.gnem.core.gui.plotting.plotobject.PlotObject;
import llnl.gnem.core.gui.plotting.plotobject.Symbol;
+import llnl.gnem.core.gui.plotting.plotobject.SymbolDef;
import llnl.gnem.core.gui.plotting.plotobject.SymbolFactory;
+import llnl.gnem.core.gui.plotting.plotobject.SymbolStyle;
+import reactor.core.scheduler.Schedulers;
@Component
public class SiteController implements MapListeningController, RefreshableController {
+ private static final Logger log = LoggerFactory.getLogger(SiteController.class);
+
private static final String X_AXIS_LABEL = "center freq";
+ private static final int MAX_LEGEND_COLORS = 8;
+
+ @FXML
+ private SwingNode mwPlotSwingNode;
+ private JMultiAxisPlot mwPlot;
+ private JSubplot mwPlotFigure;
+ private Line mwZeroLine;
+
+ @FXML
+ private SwingNode stressPlotSwingNode;
+ private JMultiAxisPlot stressPlot;
+ private JSubplot stressPlotFigure;
+ private Line stressZeroLine;
+
+ @FXML
+ private SwingNode sdPlotSwingNode;
+ private JMultiAxisPlot sdPlot;
+ private JSubplot sdPlotFigure;
+
@FXML
private SwingNode rawPlotSwingNode;
private SpectralPlot rawPlot;
@@ -93,31 +143,28 @@ public class SiteController implements MapListeningController, RefreshableContro
private ComboBox evidCombo;
@FXML
- private TableView refEventTable;
-
- @FXML
- private TableView measuredEventTable;
+ private TableView eventTable;
@FXML
private TableView iconTable;
@FXML
- private TableColumn evidCol;
+ private TableColumn evidCol;
@FXML
- private TableColumn mwCol;
+ private TableColumn mwCol;
@FXML
- private TableColumn stressDropCol;
+ private TableColumn stressCol;
@FXML
- private TableColumn measuredEvidCol;
+ private TableColumn measuredMwCol;
@FXML
- private TableColumn measuredMwCol;
+ private TableColumn measuredStressCol;
@FXML
- private TableColumn measuredStressDropCol;
+ private TableColumn dataCountCol;
@FXML
private TableColumn iconCol;
@@ -130,8 +177,9 @@ public class SiteController implements MapListeningController, RefreshableContro
private ObservableList evids = FXCollections.observableArrayList();
private ReferenceEventClient referenceEventClient;
- private ObservableList referenceMwParameters = FXCollections.observableArrayList();
- private ObservableList measuredMwParameters = FXCollections.observableArrayList();
+ private ObservableList mwParameters = FXCollections.observableArrayList();
+
+ private WaveformClient waveformClient;
private ObservableList stationSymbols = FXCollections.observableArrayList();
private final BiConsumer eventSelectionCallback;
@@ -154,21 +202,31 @@ public class SiteController implements MapListeningController, RefreshableContro
private MapPlottingUtilities iconFactory;
+ private MenuItem exclude;
+ private MenuItem include;
+ private ContextMenu menu;
+
+ private final NumberFormat dfmt4 = NumberFormatFactory.fourDecimalOneLeadingZero();
+
+ private ColorMap colorMap = new ViridisColorMap();
+
@Autowired
- private SiteController(SpectraClient spectraClient, ReferenceEventClient referenceEventClient, SymbolStyleMapFactory styleFactory, GeoMap map, MapPlottingUtilities iconFactory, EventBus bus) {
+ private SiteController(SpectraClient spectraClient, ReferenceEventClient referenceEventClient, WaveformClient waveformClient, SymbolStyleMapFactory styleFactory, GeoMap map,
+ MapPlottingUtilities iconFactory, EventBus bus) {
this.spectraClient = spectraClient;
this.referenceEventClient = referenceEventClient;
+ this.waveformClient = waveformClient;
this.symbolStyleMapFactory = styleFactory;
this.mapImpl = map;
this.bus = bus;
this.iconFactory = iconFactory;
eventSelectionCallback = (selected, eventId) -> {
- selectDataByCriteria(bus, selected, eventId);
+ selectDataByCriteria(selected, eventId);
};
stationSelectionCallback = (selected, stationId) -> {
- selectDataByCriteria(bus, selected, stationId);
+ selectDataByCriteria(selected, stationId);
};
}
@@ -177,42 +235,21 @@ public void initialize() {
evidCombo.setItems(evids);
SwingUtilities.invokeLater(() -> {
+
rawPlot = new SpectralPlot();
rawPlot.addPlotObjectObserver(new Observer() {
-
@Override
public void update(Observable observable, Object obj) {
- if (obj instanceof PlotObjectClicked && ((PlotObjectClicked) obj).getMouseEvent().getID() == MouseEvent.MOUSE_RELEASED) {
- PlotObjectClicked poc = (PlotObjectClicked) obj;
- PlotObject po = poc.getPlotObject();
- if (po != null && po instanceof Symbol) {
- selectPoints(plotPointMap.get(((Symbol) po).getText()));
- SpectraMeasurement spectra = rawSymbolMap.get(new Point2D.Double(((Symbol) po).getXcenter(), ((Symbol) po).getYcenter()));
- if (spectra != null) {
- showWaveformPopup(spectra.getWaveform());
- }
- }
- }
+ handlePlotObjectClicked(obj, sym -> rawSymbolMap.get(getPoint2D(sym)));
}
});
rawPlotSwingNode.setContent(rawPlot);
pathPlot = new SpectralPlot();
pathPlot.addPlotObjectObserver(new Observer() {
-
@Override
public void update(Observable observable, Object obj) {
- if (obj instanceof PlotObjectClicked && ((PlotObjectClicked) obj).getMouseEvent().getID() == MouseEvent.MOUSE_RELEASED) {
- PlotObjectClicked poc = (PlotObjectClicked) obj;
- PlotObject po = poc.getPlotObject();
- if (po != null && po instanceof Symbol) {
- selectPoints(plotPointMap.get(((Symbol) po).getText()));
- SpectraMeasurement spectra = pathSymbolMap.get(new Point2D.Double(((Symbol) po).getXcenter(), ((Symbol) po).getYcenter()));
- if (spectra != null) {
- showWaveformPopup(spectra.getWaveform());
- }
- }
- }
+ handlePlotObjectClicked(obj, sym -> pathSymbolMap.get(getPoint2D(sym)));
}
});
@@ -220,20 +257,9 @@ public void update(Observable observable, Object obj) {
sitePlot = new SpectralPlot();
sitePlot.addPlotObjectObserver(new Observer() {
-
@Override
public void update(Observable observable, Object obj) {
- if (obj instanceof PlotObjectClicked && ((PlotObjectClicked) obj).getMouseEvent().getID() == MouseEvent.MOUSE_RELEASED) {
- PlotObjectClicked poc = (PlotObjectClicked) obj;
- PlotObject po = poc.getPlotObject();
- if (po != null && po instanceof Symbol) {
- selectPoints(plotPointMap.get(((Symbol) po).getText()));
- SpectraMeasurement spectra = siteSymbolMap.get(new Point2D.Double(((Symbol) po).getXcenter(), ((Symbol) po).getYcenter()));
- if (spectra != null) {
- showWaveformPopup(spectra.getWaveform());
- }
- }
- }
+ handlePlotObjectClicked(obj, sym -> siteSymbolMap.get(getPoint2D(sym)));
}
});
sitePlotSwingNode.setContent(sitePlot);
@@ -252,6 +278,53 @@ public void update(Observable observable, Object obj) {
sitePlot.setLabels("Site Corrected", X_AXIS_LABEL, "log10(amplitude)");
sitePlot.setYaxisVisibility(true);
+
+ mwPlot = new JMultiAxisPlot();
+ mwPlotFigure = mwPlot.addSubplot();
+
+ mwPlot.getTitle().setText("Mw comparison");
+ mwPlot.getXaxis().setLabelText("Measured");
+ mwPlot.setYaxisVisibility(true);
+ mwPlotSwingNode.setContent(mwPlot);
+
+ mwPlotFigure.getYaxis().setLabelOffset(2d * mwPlot.getXaxis().getLabelOffset());
+ mwPlotFigure.setAxisLimits(0.0, 10.0, 0.0, 10.0);
+ mwPlotFigure.getYaxis().setLabelText("Reference");
+
+ stressPlot = new JMultiAxisPlot();
+ stressPlotFigure = stressPlot.addSubplot();
+
+ stressPlot.getTitle().setText("Stress comparison");
+ stressPlot.getXaxis().setLabelText("Measured");
+ stressPlot.setYaxisVisibility(true);
+ stressPlotSwingNode.setContent(stressPlot);
+
+ stressPlotFigure.getYaxis().setLabelOffset(2d * stressPlot.getXaxis().getLabelOffset());
+ stressPlotFigure.setAxisLimits(0.0, 10.0, 0.0, 10.0);
+ stressPlotFigure.getYaxis().setLabelText("Reference");
+
+ sdPlot = new JMultiAxisPlot();
+ sdPlotFigure = sdPlot.addSubplot();
+
+ sdPlot.getTitle().setText("Site correction overview");
+ sdPlot.getXaxis().setLabelText("Frequency");
+ sdPlot.setYaxisVisibility(true);
+ sdPlotSwingNode.setContent(sdPlot);
+
+ sdPlotFigure.getYaxis().setLabelOffset(2d * sdPlot.getXaxis().getLabelOffset());
+ sdPlotFigure.setAxisLimits(0.0, 10.0, 0.0, 2.0);
+ sdPlotFigure.getYaxis().setLabelText("Standard Deviation");
+
+ int points = 50;
+ double dx = 20.0 / (points - 1);
+ float[] xy = new float[points];
+ for (int i = 0; i < points; i++) {
+ xy[i] = (float) (-5.0 + (dx * i));
+ }
+ mwZeroLine = new Line(xy, xy, Color.LIGHT_GRAY, PaintMode.COPY, PenStyle.DASH, 2);
+ stressZeroLine = new Line(xy, xy, Color.LIGHT_GRAY, PaintMode.COPY, PenStyle.DASH, 2);
+ mwPlotFigure.AddPlotObject(mwZeroLine);
+ stressPlotFigure.AddPlotObject(stressZeroLine);
});
evidCombo.valueProperty().addListener((observable, oldValue, newValue) -> {
@@ -260,23 +333,16 @@ public void update(Observable observable, Object obj) {
}
});
- evidCol.setCellValueFactory(x -> Bindings.createStringBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(ReferenceMwParameters::getEventId).orElseGet(String::new)));
+ CellBindingUtils.attachTextCellFactoriesString(evidCol, MeasuredMwDetails::getEventId);
evidCol.comparatorProperty().set(new MaybeNumericStringComparator());
- mwCol.setCellValueFactory(x -> Bindings.createDoubleBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(ReferenceMwParameters::getRefMw).orElseGet(() -> 0.0)).asObject());
-
- stressDropCol.setCellValueFactory(
- x -> Bindings.createDoubleBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(ReferenceMwParameters::getStressDropInMpa).orElseGet(() -> 0.0)).asObject());
+ CellBindingUtils.attachTextCellFactories(mwCol, MeasuredMwDetails::getRefMw, dfmt4);
+ CellBindingUtils.attachTextCellFactories(stressCol, MeasuredMwDetails::getRefApparentStressInMpa, dfmt4);
+ CellBindingUtils.attachTextCellFactories(measuredMwCol, MeasuredMwDetails::getMw, dfmt4);
+ CellBindingUtils.attachTextCellFactories(measuredStressCol, MeasuredMwDetails::getApparentStressInMpa, dfmt4);
- measuredEvidCol.setCellValueFactory(
- x -> Bindings.createStringBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(MeasuredMwParameters::getEventId).orElseGet(String::new)));
- measuredEvidCol.comparatorProperty().set(new MaybeNumericStringComparator());
-
- measuredMwCol.setCellValueFactory(
- x -> Bindings.createDoubleBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(MeasuredMwParameters::getMw).orElseGet(() -> 0.0)).asObject());
-
- measuredStressDropCol.setCellValueFactory(
- x -> Bindings.createDoubleBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(MeasuredMwParameters::getStressDropInMpa).orElseGet(() -> 0.0)).asObject());
+ dataCountCol.setCellValueFactory(
+ x -> Bindings.createIntegerBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(MeasuredMwDetails::getDataCount).orElseGet(() -> 0)).asObject());
iconCol.setCellValueFactory(x -> Bindings.createObjectBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(pp -> {
ImageView imView = new ImageView(SwingFXUtils.toFXImage(
@@ -289,12 +355,30 @@ public void update(Observable observable, Object obj) {
stationCol.setCellValueFactory(x -> Bindings.createStringBinding(() -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(LabeledPlotPoint::getLabel).orElseGet(String::new)));
- refEventTable.setItems(referenceMwParameters);
- measuredEventTable.setItems(measuredMwParameters);
+ eventTable.setItems(mwParameters);
iconTable.setItems(stationSymbols);
iconCol.prefWidthProperty().bind(iconTable.widthProperty().multiply(0.3));
stationCol.prefWidthProperty().bind(iconTable.widthProperty().multiply(0.7));
+
+ menu = new ContextMenu();
+ include = new MenuItem("Include Selected");
+ menu.getItems().add(include);
+ exclude = new MenuItem("Exclude Selected");
+ menu.getItems().add(exclude);
+
+ EventHandler menuHideHandler = (evt) -> {
+ if (MouseButton.SECONDARY != evt.getButton()) {
+ menu.hide();
+ }
+ };
+ rawPlotSwingNode.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, menuHideHandler);
+ pathPlotSwingNode.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, menuHideHandler);
+ sitePlotSwingNode.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, menuHideHandler);
+ }
+
+ protected Object getPoint2D(Symbol sym) {
+ return new Point2D.Double(sym.getXcenter(), sym.getYcenter());
}
private void showWaveformPopup(Waveform waveform) {
@@ -365,23 +449,40 @@ private Map mapSpectraToPoint(List toPlotPoints(List spectralMeasurements, Function func) {
- List list = spectralMeasurements.stream().filter(spectra -> !func.apply(spectra).equals(0.0)).map(spectra -> {
- String key = spectra.getWaveform().getStream().getStation().getStationName();
- PlotPoint pp = symbolStyleMap.get(key);
- PlotPoint point = new LabeledPlotPoint(key,
- new PlotPoint(Math.log10(centerFreq(spectra.getWaveform().getLowFrequency(), spectra.getWaveform().getHighFrequency())),
- func.apply(spectra),
- pp.getStyle(),
- pp.getColor()));
- if (hasEventAndStation(spectra)) {
- plotPointMap.computeIfAbsent(spectra.getWaveform().getEvent().getEventId(), k -> new ArrayList<>()).add(point);
- plotPointMap.computeIfAbsent(spectra.getWaveform().getStream().getStation().getStationName(), k -> new ArrayList<>()).add(point);
- }
- return point;
- }).collect(Collectors.toList());
+ List list = spectralMeasurements.stream()
+ .filter(spectra -> !func.apply(spectra).equals(0.0))
+ .filter(
+ spectra -> spectra != null
+ && spectra.getWaveform() != null
+ && spectra.getWaveform().getStream() != null
+ && spectra.getWaveform().getStream().getStation() != null)
+ .map(spectra -> {
+ String key = spectra.getWaveform().getStream().getStation().getStationName();
+ PlotPoint pp = getPlotPoint(key, spectra.getWaveform().isActive());
+ PlotPoint point = new LabeledPlotPoint(key,
+ new PlotPoint(Math.log10(
+ centerFreq(spectra.getWaveform().getLowFrequency(), spectra.getWaveform().getHighFrequency())),
+ func.apply(spectra),
+ pp.getStyle(),
+ pp.getColor()));
+ if (hasEventAndStation(spectra)) {
+ plotPointMap.computeIfAbsent(spectra.getWaveform().getEvent().getEventId(), k -> new ArrayList<>()).add(point);
+ plotPointMap.computeIfAbsent(spectra.getWaveform().getStream().getStation().getStationName(), k -> new ArrayList<>()).add(point);
+ }
+ return point;
+ })
+ .collect(Collectors.toList());
return list;
}
+ private PlotPoint getPlotPoint(String key, boolean active) {
+ PlotPoint pp = new PlotPoint(symbolStyleMap.get(key));
+ if (!active) {
+ pp.setColor(Color.GRAY);
+ }
+ return pp;
+ }
+
private boolean hasEventAndStation(SpectraMeasurement spectra) {
return spectra != null
&& spectra.getWaveform() != null
@@ -399,33 +500,198 @@ private double centerFreq(Double lowFrequency, Double highFrequency) {
private void reloadData() {
clearSpectraPlots();
- referenceMwParameters.clear();
- measuredMwParameters.clear();
- referenceEventClient.getReferenceEvents().filter(ref -> ref.getId() != null).subscribe(ref -> referenceMwParameters.add(ref));
- referenceEventClient.getMeasuredEvents().filter(meas -> meas.getId() != null).subscribe(meas -> measuredMwParameters.add(meas));
+ mwParameters.clear();
+ try {
+ SwingUtilities.invokeAndWait(() -> {
+ mwPlotFigure.Clear();
+ stressPlotFigure.Clear();
+ sdPlotFigure.Clear();
+ mwPlotFigure.AddPlotObject(mwZeroLine);
+ stressPlotFigure.AddPlotObject(stressZeroLine);
+ List evs = referenceEventClient.getMeasuredEventDetails()
+ .filter(ev -> ev.getEventId() != null)
+ .collect(Collectors.toList())
+ .subscribeOn(Schedulers.elastic())
+ .block(Duration.ofSeconds(10l));
+
+ double minMw = 10.0;
+ double maxMw = 0.0;
+ double minStress = 1.0;
+ double maxStress = 0.0;
+ for (MeasuredMwDetails ev : evs) {
+ mwParameters.add(ev);
+ if (ev.getMw() != null && ev.getMw() != 0.0 && ev.getRefMw() != null && ev.getRefMw() != 0.0) {
+ double mw = ev.getMw();
+ double ref = ev.getRefMw();
+ if (mw < minMw) {
+ minMw = mw;
+ }
+ if (mw > maxMw) {
+ maxMw = mw;
+ }
+ if (ref < minMw) {
+ minMw = ref;
+ }
+ if (ref > maxMw) {
+ maxMw = ref;
+ }
+
+ double stress = ev.getApparentStressInMpa();
+ double refStress = ev.getRefApparentStressInMpa();
+ if (stress < minStress) {
+ minStress = stress;
+ }
+ if (stress > maxStress) {
+ maxStress = stress;
+ }
+ if (refStress < minStress) {
+ minStress = refStress;
+ }
+ if (refStress > maxStress) {
+ maxStress = refStress;
+ }
+
+ Circle mwSym = new Circle(mw, ref, 2.0, Color.RED, Color.RED, Color.RED, ev.getEventId(), true, false, 6.0);
+ mwPlotFigure.AddPlotObject(mwSym);
- spectralMeasurements.clear();
- stationSymbols.clear();
+ Circle stressSym = new Circle(stress, refStress, 2.0, Color.RED, Color.RED, Color.RED, ev.getEventId(), true, false, 6.0);
+ stressPlotFigure.AddPlotObject(stressSym);
+ }
+ }
+
+ maxMw = maxMw + .1;
+ minMw = minMw > maxMw ? minMw = maxMw - .1 : minMw - .1;
+
+ mwPlotFigure.setAxisLimits(minMw, maxMw, minMw, maxMw);
+
+ maxStress = maxStress + .1;
+ minStress = minStress > maxStress ? minStress = maxStress - .1 : minStress - .1;
+
+ stressPlotFigure.setAxisLimits(minStress, maxStress, minStress, maxStress);
+ });
+
+ spectralMeasurements.clear();
+ stationSymbols.clear();
+
+ evids.clear();
+ evids.add("All");
+
+ spectralMeasurements.addAll(
+ spectraClient.getMeasuredSpectraMetadata()
+ .filter(Objects::nonNull)
+ .filter(spectra -> spectra.getWaveform() != null && spectra.getWaveform().getEvent() != null && spectra.getWaveform().getStream() != null)
+ .toStream()
+ .collect(Collectors.toList()));
+
+ symbolStyleMap = symbolStyleMapFactory.build(spectralMeasurements, new Function() {
+ @Override
+ public String apply(SpectraMeasurement t) {
+ return t.getWaveform().getStream().getStation().getStationName();
+ }
+ });
+ stationSymbols.addAll(symbolStyleMap.entrySet().stream().map(e -> new LabeledPlotPoint(e.getKey(), e.getValue())).collect(Collectors.toList()));
+
+ evids.addAll(spectralMeasurements.stream().map(spec -> spec.getWaveform().getEvent().getEventId()).distinct().sorted(new MaybeNumericStringComparator()).collect(Collectors.toList()));
+ eventTable.sort();
+
+ SwingUtilities.invokeAndWait(() -> {
+ Map> evidStats = new HashMap<>();
+
+ double minSite = 1E2;
+ double maxSite = -1E2;
+ double minFreq = 1E2;
+ double maxFreq = -1E2;
+ int minStations = 2;
+ int maxStations = 3;
+
+ for (SpectraMeasurement meas : spectralMeasurements) {
+ String evid = meas.getWaveform().getEvent().getEventId();
+ Double freq = centerFreq(meas.getWaveform());
+ evidStats.computeIfAbsent(evid, key -> new HashMap<>()).computeIfAbsent(freq, (key) -> new SummaryStatistics()).addValue(meas.getPathAndSiteCorrected());
+ }
+
+ for (Map freqStats : evidStats.values()) {
+ for (Entry entry : freqStats.entrySet()) {
+ double site = entry.getValue().getStandardDeviation();
+ if (entry.getValue() != null && entry.getValue().getN() > 1) {
+ if (maxStations < entry.getValue().getN()) {
+ maxStations = (int) entry.getValue().getN();
+ }
+ if (site < minSite) {
+ minSite = site;
+ }
+ if (site > maxSite) {
+ maxSite = site;
+ }
+ if (entry.getKey() < minFreq) {
+ minFreq = entry.getKey();
+ }
+ if (entry.getKey() > maxFreq) {
+ maxFreq = entry.getKey();
+ }
+ }
+ }
+ }
+
+ colorMap.setRange(minStations, maxStations);
+
+ for (Map freqStats : evidStats.values()) {
+ for (Entry entry : freqStats.entrySet()) {
+ double site = entry.getValue().getStandardDeviation();
+ if (entry.getValue() != null && entry.getValue().getN() > 1) {
+ Color color = colorMap.getColor(entry.getValue().getN());
+ Circle sdSym = new Circle(entry.getKey(), site, 2.0, color, color, color, "", true, false, 6.0);
+ sdPlotFigure.AddPlotObject(sdSym);
+ }
+ }
+ }
+
+ maxSite = maxSite + .1;
+ minSite = minSite > maxSite ? minSite = maxSite - .1 : minSite - .1;
+
+ maxFreq = maxFreq + 5.0;
+ minFreq = minFreq > maxFreq ? minFreq = maxFreq - .1 : minFreq - 1.0;
- evids.clear();
- evids.add("All");
+ sdPlotFigure.setAxisLimits(minFreq, maxFreq, minSite, maxSite);
+ sdPlotFigure.AddPlotObject(createColorLegend(minStations, maxStations));
+ });
- spectralMeasurements.addAll(
- spectraClient.getMeasuredSpectra()
- .filter(Objects::nonNull)
- .filter(spectra -> spectra.getWaveform() != null && spectra.getWaveform().getEvent() != null && spectra.getWaveform().getStream() != null)
- .toStream()
- .collect(Collectors.toList()));
+ mwPlot.repaint();
+ stressPlot.repaint();
+ sdPlot.repaint();
+ } catch (InvocationTargetException ex) {
+ //nop
+ } catch (InterruptedException ex) {
+ log.warn("Swing interrupt during re-plotting of site controller", ex);
+ Thread.currentThread().interrupt();
+ }
+ }
- symbolStyleMap = symbolStyleMapFactory.build(spectralMeasurements, new Function() {
- @Override
- public String apply(SpectraMeasurement t) {
- return t.getWaveform().getStream().getStation().getStationName();
+ private PlotObject createColorLegend(int minVal, int maxVal) {
+ int range = maxVal - minVal;
+ int legendEntries = range;
+ if (legendEntries > MAX_LEGEND_COLORS) {
+ legendEntries = MAX_LEGEND_COLORS;
+ }
+ List legendSymbols = new ArrayList<>(range);
+
+ Color color = colorMap.getColor(minVal);
+ legendSymbols.add(new SymbolTextPair(Integer.toString(minVal), new SymbolDef(SymbolStyle.CIRCLE, 1.0, color, color)));
+ if (legendEntries > 2) {
+ int i = minVal + 1;
+ while (i < legendEntries + minVal) {
+ color = colorMap.getColor(i);
+ legendSymbols.add(new SymbolTextPair(Integer.toString(i), new SymbolDef(SymbolStyle.CIRCLE, 1.0, color, color)));
+ i = i + (range / (legendEntries - 1));
}
- });
- stationSymbols.addAll(symbolStyleMap.entrySet().stream().map(e -> new LabeledPlotPoint(e.getKey(), e.getValue())).collect(Collectors.toList()));
+ }
+ color = colorMap.getColor(maxVal);
+ legendSymbols.add(new SymbolTextPair(maxVal + "+", new SymbolDef(SymbolStyle.CIRCLE, 1.0, color, color)));
+ return new SymbolLegend(legendSymbols, sdPlot.getTitle().getFontName(), 8.0, HorizPinEdge.RIGHT, VertPinEdge.TOP, 1, 1);
+ }
- evids.addAll(spectralMeasurements.stream().map(spec -> spec.getWaveform().getEvent().getEventId()).distinct().sorted(new MaybeNumericStringComparator()).collect(Collectors.toList()));
+ private Double centerFreq(Waveform waveform) {
+ return ((waveform.getHighFrequency() - waveform.getLowFrequency()) / 2.0) + waveform.getLowFrequency();
}
@Override
@@ -444,7 +710,7 @@ public Runnable getRefreshFunction() {
return () -> reloadData();
}
- private void selectDataByCriteria(EventBus bus, Boolean selected, String key) {
+ private void selectDataByCriteria(Boolean selected, String key) {
List points = plotPointMap.get(key);
if (selected) {
selectPoints(points);
@@ -515,4 +781,58 @@ private void deselectPoint(PlotPoint point) {
sitePlot.deselectPoint(xyPoint);
}
}
+
+ protected void setSymbolsActive(List objs, Boolean active) {
+ SwingUtilities.invokeLater(() -> {
+ objs.forEach(sym -> {
+ if (active) {
+ sym.setFillColor(sym.getEdgeColor());
+ sym.setEdgeColor(Color.BLACK);
+ } else {
+ sym.setEdgeColor(sym.getFillColor());
+ sym.setFillColor(Color.GRAY);
+ }
+ });
+ Platform.runLater(() -> {
+ rawPlot.repaint();
+ pathPlot.repaint();
+ sitePlot.repaint();
+ });
+ });
+ }
+
+ private void showContextMenu(List waveforms, List plotObjects, MouseEvent t, BiConsumer, Boolean> activationFunc) {
+ Platform.runLater(() -> {
+ include.setOnAction(evt -> setActive(waveforms, plotObjects, true, activationFunc));
+ exclude.setOnAction(evt -> setActive(waveforms, plotObjects, false, activationFunc));
+ menu.show(sitePlotSwingNode, t.getXOnScreen(), t.getYOnScreen());
+ });
+ }
+
+ private void setActive(List waveforms, List plotObjects, boolean active, BiConsumer, Boolean> activationFunc) {
+ waveformClient.setWaveformsActiveByIds(waveforms.stream().map(w -> w.getId()).collect(Collectors.toList()), active).subscribe(s -> activationFunc.accept(plotObjects, active));
+ }
+
+ private void handlePlotObjectClicked(Object obj, Function measurementFunc) {
+ if (obj instanceof PlotObjectClicked && ((PlotObjectClicked) obj).getMouseEvent().getID() == MouseEvent.MOUSE_RELEASED) {
+ PlotObjectClicked poc = (PlotObjectClicked) obj;
+ PlotObject po = poc.getPlotObject();
+ if (po instanceof Symbol) {
+ SpectraMeasurement spectra = measurementFunc.apply((Symbol) po);
+ if (spectra != null && spectra.getWaveform() != null) {
+ if (SwingUtilities.isLeftMouseButton(poc.getMouseEvent())) {
+ selectPoints(plotPointMap.get(((Symbol) po).getText()));
+ if (spectra != null) {
+ showWaveformPopup(spectra.getWaveform());
+ }
+ Platform.runLater(() -> menu.hide());
+ } else if (SwingUtilities.isRightMouseButton(poc.getMouseEvent())) {
+ showContextMenu(Collections.singletonList(spectra.getWaveform()), Collections.singletonList((Symbol) po), poc.getMouseEvent(), (objs, active) -> {
+ setSymbolsActive(objs, active);
+ });
+ }
+ }
+ }
+ }
+ }
}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/ParametersController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/ParametersController.java
index a22d2a67..cadc4901 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/ParametersController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/ParametersController.java
@@ -22,6 +22,7 @@
import gov.llnl.gnem.apps.coda.calibration.gui.controllers.RefreshableController;
import gov.llnl.gnem.apps.coda.calibration.gui.events.ParametersLoadedEvent;
+import gov.llnl.gnem.apps.coda.calibration.model.messaging.GvDataChangeEvent;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.layout.StackPane;
@@ -40,15 +41,23 @@ public class ParametersController implements RefreshableController {
@FXML
private SiteBandController siteBandController;
+
+ @FXML
+ private VelocityConfigurationController velocityConfigController;
private EventBus bus;
@Autowired
public ParametersController(EventBus bus) {
this.bus = bus;
- bus.register(this);
+ this.bus.register(this);
}
+ @Subscribe
+ private void listener(GvDataChangeEvent event) {
+ velocityConfigController.requestData();
+ }
+
@Subscribe
private void listener(ParametersLoadedEvent event) {
reloadData();
@@ -63,6 +72,7 @@ private void reloadData() {
sharedBandController.requestData();
modelController.requestData();
siteBandController.requestData();
+ velocityConfigController.requestData();
}
@Override
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java
index 8c2ac03f..ed4d9bb8 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SharedBandController.java
@@ -186,7 +186,7 @@ private void clearTable() {
@FXML
private void removeBands() {
- List sfb = new ArrayList<>();
+ List sfb = new ArrayList<>(codaSharedTableView.getSelectionModel().getSelectedIndices().size());
codaSharedTableView.getSelectionModel().getSelectedIndices().forEach(i -> sfb.add(sharedFbData.get(i)));
if (!sfb.isEmpty()) {
sfb.forEach(x -> client.removeSharedFrequencyBandParameter(x).subscribe());
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SiteBandController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SiteBandController.java
index e04d02c0..eb39fbdb 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SiteBandController.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/SiteBandController.java
@@ -25,7 +25,7 @@
import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.ParameterClient;
import gov.llnl.gnem.apps.coda.calibration.model.domain.SiteFrequencyBandParameters;
-import gov.llnl.gnem.apps.coda.common.gui.util.MaybeNumericStringComparator;
+import gov.llnl.gnem.apps.coda.common.gui.util.CellBindingUtils;
import gov.llnl.gnem.apps.coda.common.gui.util.NumberFormatFactory;
import gov.llnl.gnem.apps.coda.common.model.domain.Station;
import javafx.beans.binding.Bindings;
@@ -86,30 +86,9 @@ public void initialize() {
.filter(Objects::nonNull)
.orElseGet(String::new)));
- siteLowFreqCol.setCellValueFactory(
- x -> Bindings.createStringBinding(
- () -> Optional.ofNullable(x)
- .map(CellDataFeatures::getValue)
- .map(SiteFrequencyBandParameters::getLowFrequency)
- .filter(Objects::nonNull)
- .map(dfmt2::format)
- .orElseGet(String::new)));
- siteLowFreqCol.comparatorProperty().set(new MaybeNumericStringComparator());
-
- siteHighFreqCol.setCellValueFactory(
- x -> Bindings.createStringBinding(
- () -> Optional.ofNullable(x)
- .map(CellDataFeatures::getValue)
- .map(SiteFrequencyBandParameters::getHighFrequency)
- .filter(Objects::nonNull)
- .map(dfmt2::format)
- .orElseGet(String::new)));
- siteHighFreqCol.comparatorProperty().set(new MaybeNumericStringComparator());
-
- siteCorrectionCol.setCellValueFactory(
- x -> Bindings.createStringBinding(
- () -> Optional.ofNullable(x).map(CellDataFeatures::getValue).map(SiteFrequencyBandParameters::getSiteTerm).filter(Objects::nonNull).map(dfmt2::format).orElseGet(String::new)));
-
+ CellBindingUtils.attachTextCellFactories(siteLowFreqCol, SiteFrequencyBandParameters::getLowFrequency, dfmt2);
+ CellBindingUtils.attachTextCellFactories(siteHighFreqCol, SiteFrequencyBandParameters::getHighFrequency, dfmt2);
+ CellBindingUtils.attachTextCellFactories(siteCorrectionCol, SiteFrequencyBandParameters::getSiteTerm, dfmt2);
codaSiteTableView.setItems(siteFbData);
}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/VelocityConfigurationController.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/VelocityConfigurationController.java
new file mode 100644
index 00000000..40879bb0
--- /dev/null
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/controllers/parameters/VelocityConfigurationController.java
@@ -0,0 +1,105 @@
+/*
+* Copyright (c) 2019, Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory
+* CODE-743439.
+* All rights reserved.
+* This file is part of CCT. For details, see https://github.com/LLNL/coda-calibration-tool.
+*
+* Licensed under the Apache License, Version 2.0 (the “Licensee”); you may not use this file except in compliance with the License. You may obtain a copy of the License at:
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and limitations under the license.
+*
+* This work was performed under the auspices of the U.S. Department of Energy
+* by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344.
+*/
+package gov.llnl.gnem.apps.coda.calibration.gui.controllers.parameters;
+
+import java.text.NumberFormat;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.ParameterClient;
+import gov.llnl.gnem.apps.coda.calibration.model.domain.VelocityConfiguration;
+import gov.llnl.gnem.apps.coda.common.gui.util.CellBindingUtils;
+import gov.llnl.gnem.apps.coda.common.gui.util.NumberFormatFactory;
+import javafx.application.Platform;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+
+@Component
+public class VelocityConfigurationController {
+
+ private static final Logger log = LoggerFactory.getLogger(VelocityConfigurationController.class);
+
+ private final NumberFormat dfmt2 = NumberFormatFactory.twoDecimalOneLeadingZero();
+
+ @FXML
+ private TableView velocityConfTableView;
+
+ @FXML
+ TableColumn distanceThresholdCol;
+
+ @FXML
+ TableColumn gt1Col;
+
+ @FXML
+ TableColumn gt2Col;
+
+ @FXML
+ TableColumn lt1Col;
+
+ @FXML
+ TableColumn lt2Col;
+
+ @FXML
+ TableColumn phaseSpeedCol;
+
+ private ObservableList velData = FXCollections.observableArrayList();
+
+ private ParameterClient client;
+
+ @Autowired
+ public VelocityConfigurationController(ParameterClient client) {
+ this.client = client;
+ }
+
+ @FXML
+ private void reloadData(ActionEvent e) {
+ requestData();
+ }
+
+ @FXML
+ public void initialize() {
+ CellBindingUtils.attachTextCellFactories(distanceThresholdCol, VelocityConfiguration::getDistanceThresholdInKm, dfmt2);
+ CellBindingUtils.attachTextCellFactories(gt1Col, VelocityConfiguration::getGroupVelocity1InKmsGtDistance, dfmt2);
+ CellBindingUtils.attachTextCellFactories(gt2Col, VelocityConfiguration::getGroupVelocity2InKmsGtDistance, dfmt2);
+ CellBindingUtils.attachTextCellFactories(lt1Col, VelocityConfiguration::getGroupVelocity1InKmsLtDistance, dfmt2);
+ CellBindingUtils.attachTextCellFactories(lt2Col, VelocityConfiguration::getGroupVelocity2InKmsLtDistance, dfmt2);
+ CellBindingUtils.attachTextCellFactories(phaseSpeedCol, VelocityConfiguration::getPhaseSpeedInKms, dfmt2);
+ velocityConfTableView.setItems(velData);
+ requestData();
+ }
+
+
+ protected void requestData() {
+ velData.clear();
+ client.getVelocityConfiguration()
+ .filter(Objects::nonNull)
+ .filter(value -> null != value.getId())
+ .doOnTerminate(() -> velocityConfTableView.sort())
+ .subscribe(value -> velData.add(value), err -> log.trace(err.getMessage(), err));
+
+ Platform.runLater(() -> {
+ Optional.ofNullable(velocityConfTableView).ifPresent(v -> v.refresh());
+ });
+ }
+}
diff --git a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java
index 29b85f50..a998f116 100644
--- a/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java
+++ b/calibration-gui/src/main/java/gov/llnl/gnem/apps/coda/calibration/gui/converters/param/CodaJsonParamLoader.java
@@ -22,6 +22,7 @@
import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.SCHEMA_VALUE;
import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.TYPE_FIELD;
import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.TYPE_VALUE;
+import static gov.llnl.gnem.apps.coda.calibration.gui.data.client.api.CalibrationJsonConstants.VELOCITY_CONFIGURATION;
import java.io.File;
import java.io.IOException;
@@ -43,6 +44,7 @@
import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersFI;
import gov.llnl.gnem.apps.coda.calibration.model.domain.MdacParametersPS;
import gov.llnl.gnem.apps.coda.calibration.model.domain.ReferenceMwParameters;
+import gov.llnl.gnem.apps.coda.calibration.model.domain.VelocityConfiguration;
import gov.llnl.gnem.apps.coda.calibration.model.domain.mixins.SharedFrequencyBandParametersFileMixin;
import gov.llnl.gnem.apps.coda.common.model.domain.SharedFrequencyBandParameters;
import gov.llnl.gnem.apps.coda.common.model.messaging.Result;
@@ -91,6 +93,7 @@ public List> convertJsonParamFile(File file) {
results.addAll(convertJsonFields(node, MDAC_PS_FIELD, x -> mdacPsFromJsonNode(x)));
results.addAll(convertJsonFields(node, MDAC_FI_FIELD, x -> mdacFiFromJsonNode(x)));
results.addAll(convertJsonFields(node, REFERENCE_EVENTS_FIELD, x -> refEventsFromJsonNode(x)));
+ results.addAll(convertJsonFields(node, VELOCITY_CONFIGURATION, x -> velocityConfigurationFromJsonNode(x)));
}
} catch (IOException e) {
return Collections.singletonList(exceptionalResult(new LightweightIllegalStateException(String.format("Error parsing (%s): %s", file.getName(), e.getMessage()), e)));
@@ -114,6 +117,17 @@ protected List> convertJsonFields(JsonNode node, String field, Fu
return results;
}
+ protected Result