numass-framework/numass-viewer/src/main/kotlin/inr/numass/viewer/NumassLoaderView.kt

372 lines
15 KiB
Kotlin
Raw Normal View History

2017-04-15 22:15:53 +03:00
package inr.numass.viewer
import hep.dataforge.context.Context
import hep.dataforge.context.Global
2017-04-26 19:09:55 +03:00
import hep.dataforge.data.Data
2017-04-15 22:15:53 +03:00
import hep.dataforge.fx.work.WorkManager
import hep.dataforge.io.ColumnedDataWriter
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.plots.XYPlotFrame
import hep.dataforge.plots.data.PlotDataUtils
import hep.dataforge.plots.data.PlottableData
import hep.dataforge.plots.data.PlottableGroup
import hep.dataforge.plots.data.TimePlottable
import hep.dataforge.plots.fx.FXPlotFrame
import hep.dataforge.plots.fx.PlotContainer
import hep.dataforge.plots.jfreechart.JFreeChartFrame
import hep.dataforge.storage.commons.JSONMetaWriter
import hep.dataforge.tables.*
import inr.numass.data.NumassData
import inr.numass.data.NumassDataUtils
import inr.numass.data.NumassPoint
import javafx.application.Platform
import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.geometry.Insets
import javafx.geometry.Orientation
import javafx.scene.control.*
import javafx.scene.layout.AnchorPane
2017-04-29 20:40:40 +03:00
import javafx.scene.layout.BorderPane
2017-04-15 22:15:53 +03:00
import javafx.stage.FileChooser
import javafx.util.converter.NumberStringConverter
import org.controlsfx.control.RangeSlider
import org.controlsfx.validation.ValidationSupport
import org.controlsfx.validation.Validator
import org.slf4j.LoggerFactory
import tornadofx.*
import java.io.IOException
import java.util.logging.Level
import java.util.stream.Collectors
/**
* Numass loader view
*
* Created by darksnake on 14-Apr-17.
*/
class NumassLoaderView : View() {
override val root: AnchorPane by fxml("/fxml/NumassLoaderView.fxml")
lateinit var main: MainView
2017-04-29 20:40:40 +03:00
private val detectorPlotPane: BorderPane by fxid();
2017-04-15 22:15:53 +03:00
private val tabPane: TabPane by fxid();
private val infoTextBox: TextArea by fxid();
2017-04-29 20:40:40 +03:00
private val spectrumPlotPane: BorderPane by fxid();
2017-04-15 22:15:53 +03:00
private val lowChannelField: TextField by fxid();
private val upChannelField: TextField by fxid();
private val channelSlider: RangeSlider by fxid();
private val dTimeField: TextField by fxid();
2017-04-29 20:40:40 +03:00
private val hvPane: BorderPane by fxid();
2017-04-15 22:15:53 +03:00
private val spectrumExportButton: Button by fxid();
2017-04-29 20:40:40 +03:00
private val detectorPlot: PlotContainer = PlotContainer.centerIn(detectorPlotPane)
private val spectrumPlot: PlotContainer = PlotContainer.centerIn(spectrumPlotPane)
private val hvPlot: PlotContainer = PlotContainer.centerIn(hvPane)
2017-04-15 22:15:53 +03:00
private val detectorBinningSelector: ChoiceBox<Int> = ChoiceBox(FXCollections.observableArrayList(1, 2, 5, 10, 20, 50))
private val detectorNormalizeSwitch: CheckBox = CheckBox("Normailize")
private val detectorDataExportButton: Button = Button("Export")
2017-04-29 20:40:40 +03:00
//plots data
var data: NumassData? = null
val spectrumData = PlottableData("spectrum")
val hvPlotData = PlottableGroup<TimePlottable>()
private var points = FXCollections.observableArrayList<NumassPoint>()
2017-04-15 22:15:53 +03:00
init {
//setup detector pane plot and sidebar
val l = Label("Bin size:")
l.padding = Insets(5.0)
detectorBinningSelector.maxWidth = java.lang.Double.MAX_VALUE
detectorBinningSelector.selectionModel.clearAndSelect(4)
detectorNormalizeSwitch.isSelected = true
detectorNormalizeSwitch.padding = Insets(5.0)
detectorPlot.addToSideBar(0, l, detectorBinningSelector, detectorNormalizeSwitch, Separator(Orientation.HORIZONTAL))
detectorDataExportButton.maxWidth = java.lang.Double.MAX_VALUE
detectorDataExportButton.onAction = EventHandler { this.onExportButtonClick(it) }
detectorPlot.addToSideBar(detectorDataExportButton)
detectorPlot.setSideBarPosition(0.7)
//setup spectrum pane
2017-04-29 20:40:40 +03:00
spectrumExportButton.onAction = EventHandler { this.onSpectrumExportClick(it) }
2017-04-15 22:15:53 +03:00
val spectrumPlotMeta = MetaBuilder("plot")
.setValue("xAxis.axisTitle", "U")
.setValue("xAxis.axisUnits", "V")
.setValue("yAxis.axisTitle", "count rate")
.setValue("yAxis.axisUnits", "Hz")
.setValue("legend.show", false)
spectrumPlot.plot = JFreeChartFrame(spectrumPlotMeta)
lowChannelField.textProperty().bindBidirectional(channelSlider.lowValueProperty(), NumberStringConverter())
upChannelField.textProperty().bindBidirectional(channelSlider.highValueProperty(), NumberStringConverter())
channelSlider.highValue = 1900.0
channelSlider.lowValue = 300.0
val rangeChangeListener = { _: ObservableValue<out Number>, _: Number, _: Number -> setupSpectrumPane(points) }
dTimeField.textProperty().addListener { _: ObservableValue<out String>, _: String, _: String -> setupSpectrumPane(points) }
channelSlider.lowValueProperty().addListener(rangeChangeListener)
channelSlider.highValueProperty().addListener(rangeChangeListener)
val validationSupport = ValidationSupport()
val isNumber = { t: String ->
try {
java.lang.Double.parseDouble(t)
true
} catch (ex: Exception) {
false
}
}
validationSupport.registerValidator(dTimeField, Validator.createPredicateValidator(isNumber, "Must be number"))
//setup HV plot
val hvPlotMeta = MetaBuilder("plot")
.setValue("xAxis.axisTitle", "time")
.setValue("xAxis.type", "time")
.setValue("yAxis.axisTitle", "HV")
hvPlot.plot = JFreeChartFrame(hvPlotMeta)
}
fun getContext(): Context {
return Global.getDefaultContext();
}
fun getWorkManager(): WorkManager {
return getContext().getFeature(WorkManager::class.java);
}
fun loadData(data: NumassData?) {
2017-04-16 23:19:06 +03:00
synchronized(this) {
this.data = data
if (data != null) {
getWorkManager().startWork("viewer.numass.load") { work ->
work.title = "Load numass data (" + data.name + ")"
points.setAll(data.nmPoints)
Platform.runLater {
//setup detector data
setupDetectorPane(points)
//setup spectrum plot
setupSpectrumPane(points)
}
2017-04-15 22:15:53 +03:00
}
2017-04-16 23:19:06 +03:00
//setup hv plot
val hvData = data.hvData
if (hvData != null) {
setupHVPane(hvData)
}
setupInfo(data)
2017-04-15 22:15:53 +03:00
2017-04-16 23:19:06 +03:00
} else {
log.severe("The data model is null")
}
// tabPane.selectionModel.select(1)
2017-04-15 22:15:53 +03:00
}
}
2017-04-26 19:09:55 +03:00
private fun setupHVPane(hvData: Data<Table>) {
runAsync {
hvData.get()
} ui {
2017-04-29 20:40:40 +03:00
for (pl in hvPlotData) {
2017-04-26 19:09:55 +03:00
pl.clear()
}
for (dp in it) {
val block = dp.getString("block", "default")
if (!hvPlotData.has(block)) {
hvPlotData.add(TimePlottable(block))
2017-04-15 22:15:53 +03:00
}
2017-04-26 19:09:55 +03:00
hvPlotData.get(block).put(dp.getValue("timestamp").timeValue(), dp.getValue("value"))
2017-04-15 22:15:53 +03:00
}
2017-04-26 19:09:55 +03:00
hvPlot.plot.addAll(hvPlotData)
2017-04-15 22:15:53 +03:00
}
}
/**
* setup detector pane
* @param points
*/
private fun setupDetectorPane(points: List<NumassPoint>) {
val normalize = detectorNormalizeSwitch.isSelected
val binning = detectorBinningSelector.value
updateDetectorPane(points, binning, normalize)
detectorBinningSelector.selectionModel.selectedItemProperty()
.addListener { observable: ObservableValue<out Int>, oldValue: Int, newValue: Int ->
val norm = detectorNormalizeSwitch.isSelected
updateDetectorPane(points, newValue, norm)
}
detectorNormalizeSwitch.selectedProperty().addListener { observable: ObservableValue<out Boolean>, oldValue: Boolean, newValue: Boolean ->
val bin = detectorBinningSelector.value
updateDetectorPane(points, bin, newValue)
}
detectorDataExportButton.isDisable = false
}
private fun setupInfo(loader: NumassData) {
val info = loader.meta()
infoTextBox.text = JSONMetaWriter().writeString(info).replace("\\r", "\r\t").replace("\\n", "\n\t")
}
private fun setupSpectrumPane(points: List<NumassPoint>) {
spectrumPlot.plot.add(spectrumData)
val lowChannel = channelSlider.lowValue.toInt()
val highChannel = channelSlider.highValue.toInt()
if (points.isEmpty()) {
spectrumData.clear()
} else {
spectrumData.fillData(points.stream()
.map { point: NumassPoint -> getSpectrumPoint(point, lowChannel, highChannel, dTime) }
.collect(Collectors.toList<DataPoint>()))
}
}
private val dTime: Double
get() {
try {
return java.lang.Double.parseDouble(dTimeField.text) * 1e-6
} catch (ex: NumberFormatException) {
return 0.0
}
}
private fun getSpectrumPoint(point: NumassPoint, lowChannel: Int, upChannel: Int, dTime: Double): DataPoint {
val u = point.voltage
return MapPoint(arrayOf(XYAdapter.X_VALUE_KEY, XYAdapter.Y_VALUE_KEY, XYAdapter.Y_ERROR_KEY), u,
NumassDataUtils.countRateWithDeadTime(point, lowChannel, upChannel, dTime),
NumassDataUtils.countRateWithDeadTimeErr(point, lowChannel, upChannel, dTime))
}
/**
* update detector pane with new data
*/
private fun updateDetectorPane(points: List<NumassPoint>, binning: Int, normalize: Boolean) {
val detectorPlotFrame: FXPlotFrame
2017-04-15 23:05:43 +03:00
if (detectorPlot.plot == null) {
2017-04-15 22:15:53 +03:00
val frameMeta = MetaBuilder("frame")
.setValue("title", "Detector response plot")
.setNode(MetaBuilder("xAxis")
.setValue("axisTitle", "ADC")
.setValue("axisUnits", "channels")
.build())
.setNode(MetaBuilder("yAxis")
.setValue("axisTitle", "count rate")
.setValue("axisUnits", "Hz")
.build())
.setNode(MetaBuilder("legend")
.setValue("show", false))
.build()
detectorPlotFrame = JFreeChartFrame(frameMeta)
} else {
detectorPlotFrame = detectorPlot.plot
}
2017-04-29 20:40:40 +03:00
val work = getWorkManager().getWork("viewer.numass.load.detector")
2017-04-15 22:15:53 +03:00
2017-04-29 20:40:40 +03:00
val plottableConfig = MetaBuilder("plot")
.setValue("connectionType", "step")
.setValue("thickness", 2)
.setValue("showLine", true)
.setValue("showSymbol", false)
.setValue("showErrors", false)
.setValue("JFreeChart.cache", true)
.build()
2017-04-16 23:19:06 +03:00
2017-04-29 20:40:40 +03:00
work.maxProgress = points.size.toDouble()
work.progress = 0.0
2017-04-16 23:19:06 +03:00
2017-04-29 20:40:40 +03:00
runAsync {
points.map { point ->
val seriesName = String.format("%d: %.2f", points.indexOf(point), point.voltage)
val datum = PlottableData.plot(seriesName, XYAdapter("chanel", "count"), point.getData(binning, normalize))
datum.configure(plottableConfig)
work.increaseProgress(1.0)
datum;
}
} ui {
detectorPlotFrame.setAll(it)
2017-04-15 22:15:53 +03:00
}
2017-04-29 20:40:40 +03:00
detectorPlot.plot = detectorPlotFrame
work.setProgressToMax()
2017-04-15 22:15:53 +03:00
}
private fun onSpectrumExportClick(event: ActionEvent) {
if (points.isNotEmpty()) {
val fileChooser = FileChooser()
fileChooser.title = "Choose text export destination"
fileChooser.initialFileName = data!!.name + "_spectrum.onComplete"
val destination = fileChooser.showSaveDialog(spectrumPlotPane.scene.window)
if (destination != null) {
val names = arrayOf("Uset", "Uread", "Length", "Total", "Window", "CR", "CRerr", "Timestamp")
val loChannel = channelSlider.lowValue.toInt()
val upChannel = channelSlider.highValue.toInt()
val dTime = dTime
val spectrumDataSet = ListTable.Builder(*names)
for (point in points) {
spectrumDataSet.row(
point.voltage,
point.voltage,
point.length,
point.totalCount,
point.getCountInWindow(loChannel, upChannel),
NumassDataUtils.countRateWithDeadTime(point, loChannel, upChannel, dTime),
NumassDataUtils.countRateWithDeadTimeErr(point, loChannel, upChannel, dTime),
point.startTime
)
}
try {
val comment = String.format("Numass data viewer spectrum data export for %s%n"
+ "Window: (%d, %d)%n"
+ "Dead time per event: %g%n",
data!!.name, loChannel, upChannel, dTime)
ColumnedDataWriter
.writeTable(destination, spectrumDataSet.build(), comment, false)
} catch (ex: IOException) {
log.log(Level.SEVERE, "Destination file not found", ex)
}
}
}
}
private fun onExportButtonClick(event: ActionEvent) {
val fileChooser = FileChooser()
fileChooser.title = "Choose text export destination"
fileChooser.initialFileName = data!!.name + "_detector.out"
val destination = fileChooser.showSaveDialog(detectorPlotPane.scene.window)
if (destination != null) {
val detectorData = PlotDataUtils.collectXYDataFromPlot(detectorPlot.plot as XYPlotFrame, true)
try {
ColumnedDataWriter.writeTable(
destination,
detectorData,
"Numass data viewer detector data export for " + data!!.name,
false
)
} catch (ex: IOException) {
LoggerFactory.getLogger(javaClass).error("Destination file not found", ex)
}
}
}
}