From ae97c0be68a0f658f684380e5c33b99ec7763cec Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 19 Mar 2018 16:57:07 +0300 Subject: [PATCH] Analyzers for Tristan --- numass-control/cryotemp/build.gradle | 24 +- .../numass/control/cryotemp/PKT8Channel.kt | 15 +- .../inr/numass/control/cryotemp/PKT8Device.kt | 30 +- .../numass/control/cryotemp/PKT8Display.kt | 45 +-- .../control/cryotemp/PKT8VirtualPort.kt | 19 +- .../inr/numass/control/msp/MspDevice.kt | 2 +- .../control/NumassControlApplication.kt | 10 +- .../inr/numass/control/NumassControlUtils.kt | 25 +- .../java/inr/numass/data/SpectrumAdapter.java | 112 -------- .../java/inr/numass/data/api/MetaBlock.java | 46 --- .../java/inr/numass/data/api/NumassBlock.java | 36 --- .../java/inr/numass/data/api/NumassEvent.java | 66 ----- .../java/inr/numass/data/api/NumassFrame.java | 50 ---- .../java/inr/numass/data/api/NumassPoint.java | 94 ------- .../java/inr/numass/data/api/NumassSet.java | 101 ------- .../inr/numass/data/api/SignalProcessor.java | 11 - .../java/inr/numass/data/api/SimpleBlock.java | 43 --- .../numass/data/api/SimpleNumassPoint.java | 41 --- .../inr/numass/data/legacy/NumassDatFile.java | 265 ------------------ .../data/legacy/NumassFileEnvelope.java | 45 --- .../kotlin/inr/numass/data/SpectrumAdapter.kt | 102 +++++++ .../numass/data/analyzers/AbstractAnalyzer.kt | 4 +- .../numass/data/analyzers/NumassAnalyzer.kt | 6 +- .../inr/numass/data/analyzers/TimeAnalyzer.kt | 2 +- .../kotlin/inr/numass/data/api/MetaBlock.kt | 38 +++ .../kotlin/inr/numass/data/api/NumassBlock.kt | 49 ++++ .../kotlin/inr/numass/data/api/NumassEvent.kt | 38 +++ .../kotlin/inr/numass/data/api/NumassFrame.kt | 27 ++ .../kotlin/inr/numass/data/api/NumassPoint.kt | 85 ++++++ .../kotlin/inr/numass/data/api/NumassSet.kt | 93 ++++++ .../inr/numass/data/api/SignalProcessor.kt | 11 + .../kotlin/inr/numass/data/api/SimpleBlock.kt | 19 ++ .../inr/numass/data/api/SimpleNumassPoint.kt | 31 ++ .../inr/numass/data/legacy/NumassDatFile.kt | 244 ++++++++++++++++ .../numass/data/legacy/NumassFileEnvelope.kt | 43 +++ .../numass/data/storage/NumassDataLoader.kt | 2 +- .../numass/data/storage/ProtoNumassPoint.kt | 51 ++-- .../inr/numass/scripts/times/Histogram.groovy | 2 +- .../numass/actions/MonitorCorrectAction.java | 2 +- .../inr/numass/utils/NMEventGenerator.java | 4 +- .../inr/numass/utils/PileUpSimulator.java | 4 +- .../kotlin/inr/numass/scripts/Correlation.kt | 2 +- .../numass/scripts/tristan/AnalyzeTristan.kt | 34 +++ 43 files changed, 932 insertions(+), 1041 deletions(-) delete mode 100644 numass-core/src/main/java/inr/numass/data/SpectrumAdapter.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/MetaBlock.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/NumassBlock.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/NumassEvent.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/NumassFrame.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/NumassPoint.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/NumassSet.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/SignalProcessor.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/SimpleBlock.java delete mode 100644 numass-core/src/main/java/inr/numass/data/api/SimpleNumassPoint.java delete mode 100644 numass-core/src/main/java/inr/numass/data/legacy/NumassDatFile.java delete mode 100644 numass-core/src/main/java/inr/numass/data/legacy/NumassFileEnvelope.java create mode 100644 numass-core/src/main/kotlin/inr/numass/data/SpectrumAdapter.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/NumassFrame.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/NumassPoint.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/SignalProcessor.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/SimpleNumassPoint.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/legacy/NumassFileEnvelope.kt create mode 100644 numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt diff --git a/numass-control/cryotemp/build.gradle b/numass-control/cryotemp/build.gradle index f6f110c7..e90e580d 100644 --- a/numass-control/cryotemp/build.gradle +++ b/numass-control/cryotemp/build.gradle @@ -12,7 +12,6 @@ version = "0.2.0"; dependencies { compile project(':numass-control') - compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" } task testDevice(dependsOn: classes, type: JavaExec) { @@ -22,28 +21,7 @@ task testDevice(dependsOn: classes, type: JavaExec) { description "Start application in debug mode with default virtual port" group "test" } -buildscript { - ext.kotlin_version = '1.1.60' - repositories { - mavenCentral() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} -repositories { - mavenCentral() -} -compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} -compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} + //task testRun(dependsOn: classes, type: JavaExec) { // main mainClass diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt index d8876927..07ee24e7 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt @@ -33,13 +33,9 @@ internal fun createChannel(meta: Meta): PKT8Channel { when (transformationType) { "default", "hyperbolic" -> { val coefs = meta.getValue("coefs").listValue() - val r0 = meta.getDouble("r0", 1000.0)!! + val r0 = meta.getDouble("r0", 1000.0) return PKT8Channel(meta) { r -> - if (coefs == null) { - -1.0 - } else { - coefs.indices.sumByDouble { coefs[it].doubleValue() * Math.pow(r0 / r, it.toDouble()) } - } + coefs?.indices?.sumByDouble { coefs[it].doubleValue() * Math.pow(r0 / r, it.toDouble()) } ?: -1.0 } } else -> throw RuntimeException("Unknown transformation type") @@ -50,13 +46,6 @@ internal fun createChannel(meta: Meta): PKT8Channel { } } -data class PKT8Result(val channel: String, val rawValue: Double, val temperature: Double) { - - val rawString: String = String.format("%.2f", rawValue) - - val temperatureString: String = String.format("%.2f", temperature) -} - /** * Created by darksnake on 28-Sep-16. */ diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt index db055af9..aa195d17 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt @@ -39,6 +39,7 @@ import hep.dataforge.utils.DateTimeUtils import inr.numass.control.DeviceView import inr.numass.control.StorageHelper import java.time.Duration +import java.time.Instant import java.util.* @@ -52,7 +53,7 @@ import java.util.* RoleDef(name = Roles.VIEW_ROLE) ) @ValueDef(name = "port", def = "virtual", info = "The name of the port for this PKT8") -@StateDef(ValueDef(name = "storing")) +@StateDef(value = ValueDef(name = "storing", info = "Define if this device is currently writes to storage"), writable = true) @DeviceView(PKT8Display::class) class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) { /** @@ -103,9 +104,9 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) { //read channel configuration if (meta.hasMeta("channel")) { - for (node in getMeta().getMetaList("channel")) { + for (node in meta.getMetaList("channel")) { val designation = node.getString("designation", "default") - this.channels.put(designation, createChannel(node)) + this.channels[designation] = createChannel(node) } } else { //set default channel configuration @@ -229,13 +230,18 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) { } private fun notifyChannelResult(designation: String, rawValue: Double) { + updateLogicalState("raw.$designation", rawValue) val channel = channels[designation] - if (channel != null) { - collector.put(channel.name, channel.getTemperature(rawValue)) - } else { - result(PKT8Result(designation, rawValue, -1.0)) + val temperature = channel?.let { + val temp = it.getTemperature(rawValue) + updateLogicalState("temp.$designation", temp) + collector.put(it.name, temp) + temp + } + forEachConnection(PKT8ValueListener::class.java) { + it.report(PKT8Reading(channel?.name ?: designation, rawValue, temperature)) } } @@ -313,5 +319,15 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) { const val ABUF = "abuf" private val CHANNEL_DESIGNATIONS = arrayOf("a", "b", "c", "d", "e", "f", "g", "h") } +} +data class PKT8Reading(val channel: String, val rawValue: Double, val temperature: Double?) { + + val rawString: String = String.format("%.2f", rawValue) + + val temperatureString: String = String.format("%.2f", temperature) +} + +interface PKT8ValueListener { + fun report(reading: PKT8Reading, time: Instant = Instant.now()) } \ No newline at end of file diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt index f37a0db8..43f60755 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt @@ -1,8 +1,6 @@ package inr.numass.control.cryotemp import hep.dataforge.control.devices.Sensor -import hep.dataforge.control.measurements.Measurement -import hep.dataforge.control.measurements.MeasurementListener import hep.dataforge.description.Descriptors import hep.dataforge.fx.bindWindow import hep.dataforge.fx.dfIconView @@ -15,7 +13,6 @@ import hep.dataforge.plots.PlotUtils import hep.dataforge.plots.data.TimePlot import hep.dataforge.plots.jfreechart.JFreeChartFrame import inr.numass.control.DeviceDisplay -import javafx.application.Platform import javafx.beans.binding.ListBinding import javafx.beans.property.SimpleObjectProperty import javafx.collections.FXCollections @@ -33,11 +30,11 @@ import java.time.Instant /** * Created by darksnake on 30-May-17. */ -class PKT8Display : DeviceDisplay(), MeasurementListener { +class PKT8Display : DeviceDisplay(), PKT8ValueListener { override fun buildView(device: PKT8Device) = CryoView() - internal val table = FXCollections.observableHashMap() + internal val table = FXCollections.observableHashMap() val lastUpdateProperty = SimpleObjectProperty("NEVER") @@ -47,16 +44,24 @@ class PKT8Display : DeviceDisplay(), MeasurementListener { } } - override fun onMeasurementFailed(measurement: Measurement<*>, exception: Throwable) { +// override fun onMeasurementFailed(measurement: Measurement<*>, exception: Throwable) { +// +// } +// +// override fun onMeasurementResult(measurement: Measurement<*>, result: Any, time: Instant) { +// if (result is PKT8Result) { +// Platform.runLater { +// lastUpdateProperty.set(time.toString()) +// table[result.channel] = result; +// } +// } +// } +// - } - - override fun onMeasurementResult(measurement: Measurement<*>, result: Any, time: Instant) { - if (result is PKT8Result) { - Platform.runLater { - lastUpdateProperty.set(time.toString()) - table.put(result.channel, result); - } + override fun report(reading: PKT8Reading, time: Instant) { + runLater { + lastUpdateProperty.set(time.toString()) + table[reading.channel] = reading; } } @@ -104,24 +109,24 @@ class PKT8Display : DeviceDisplay(), MeasurementListener { } } center { - tableview { - items = object : ListBinding() { + tableview { + items = object : ListBinding() { init { bind(table) } - override fun computeValue(): ObservableList { + override fun computeValue(): ObservableList { return FXCollections.observableArrayList(table.values).apply { sortBy { it.channel } } } } - column("Sensor", PKT8Result::channel); - column("Resistance", PKT8Result::rawValue).cellFormat { + column("Sensor", PKT8Reading::channel); + column("Resistance", PKT8Reading::rawValue).cellFormat { text = String.format("%.2f", it) } - column("Temperature", PKT8Result::temperature).cellFormat { + column("Temperature", PKT8Reading::temperature).cellFormat { text = String.format("%.2f", it) } } diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8VirtualPort.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8VirtualPort.kt index cc706557..27041cd3 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8VirtualPort.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8VirtualPort.kt @@ -18,26 +18,29 @@ import java.util.function.Supplier /** * @author Alexander Nozik */ -class PKT8VirtualPort(portName: String, meta: Meta) : VirtualPort(meta), Metoid { +class PKT8VirtualPort(private val portName: String, meta: Meta) : VirtualPort(meta), Metoid { private val generator = Random() - init { - super.configureValue("id", portName) - } +// init { +// super.configureValue("id", portName) +// } + + override fun getName(): String = portName + @Synchronized override fun evaluateRequest(request: String) { when (request) { "s" -> { val letters = arrayOf("a", "b", "c", "d", "e", "f", "g", "h") for (letter in letters) { - val channelMeta = MetaUtils.findNodeByValue(getMeta(), "channel", "letter", Value.of(letter)).orElse(Meta.empty()) + val channelMeta = MetaUtils.findNodeByValue(meta, "channel", "letter", Value.of(letter)).orElse(Meta.empty()) val average: Double val sigma: Double if (channelMeta != null) { - average = channelMeta.getDouble("av", 1200.0)!! - sigma = channelMeta.getDouble("sigma", 50.0)!! + average = channelMeta.getDouble("av", 1200.0) + sigma = channelMeta.getDouble("sigma", 50.0) } else { average = 1200.0 sigma = 50.0 @@ -56,7 +59,7 @@ class PKT8VirtualPort(portName: String, meta: Meta) : VirtualPort(meta), Metoid } "p" -> { cancelByTag("measurement") - this.receivePhrase("Stopped") + planResponse("Stopped", Duration.ofMillis(50)) } } } diff --git a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt index b4807f25..a0a59bae 100644 --- a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt +++ b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt @@ -61,7 +61,7 @@ import java.util.function.Consumer StateDef(ValueDef(name = "filamentStatus", info = "Filament status")) ) @DeviceView(MspDisplay::class) -class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) { +class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) { private var measurementDelegate: Consumer? = null diff --git a/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt b/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt index 124ff981..eaf33bdd 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt @@ -5,13 +5,13 @@ import hep.dataforge.control.connections.Roles import hep.dataforge.control.devices.Device import hep.dataforge.control.devices.DeviceFactory import hep.dataforge.exceptions.ControlException +import hep.dataforge.kodex.optional import hep.dataforge.meta.Meta import javafx.scene.Scene import javafx.stage.Stage import org.slf4j.LoggerFactory import tornadofx.* import java.util.* -import java.util.function.Predicate /** * Created by darksnake on 14-May-17. @@ -25,6 +25,7 @@ abstract class NumassControlApplication : App() { rootLogger.level = Level.INFO device = setupDevice() + val controller = device.getDisplay() device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE) val scene = Scene(controller.view?.root ?: controller.getBoardView()) @@ -47,12 +48,11 @@ abstract class NumassControlApplication : App() { protected abstract fun acceptDevice(meta: Meta): Boolean private fun setupDevice(): D { - val config = getConfig(this) - .orElseGet { readResourceMeta("/config/devices.xml") } + val config = getConfig(this).optional.orElseGet { readResourceMeta("/config/devices.xml") } val ctx = setupContext(config) - val deviceConfig = findDeviceMeta(config, Predicate { this.acceptDevice(it) }) - .orElseThrow { RuntimeException("Device configuration not found") } + val deviceConfig = findDeviceMeta(config) { this.acceptDevice(it) } + ?: throw RuntimeException("Device configuration not found") try { diff --git a/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt b/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt index bb082d83..193af017 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt @@ -8,6 +8,7 @@ import hep.dataforge.exceptions.StorageException import hep.dataforge.fx.dfIcon import hep.dataforge.io.MetaFileReader import hep.dataforge.io.XMLMetaReader +import hep.dataforge.kodex.nullable import hep.dataforge.meta.Meta import hep.dataforge.storage.commons.StorageConnection import hep.dataforge.storage.commons.StorageManager @@ -19,8 +20,6 @@ import java.io.IOException import java.nio.file.Files import java.nio.file.Paths import java.text.ParseException -import java.util.* -import java.util.function.Predicate /** * Created by darksnake on 08-May-17. @@ -70,10 +69,10 @@ fun readResourceMeta(path: String): Meta { } -fun getConfig(app: Application): Optional { +fun getConfig(app: Application): Meta? { val debugConfig = app.parameters.named["config.resource"] if (debugConfig != null) { - return Optional.ofNullable(readResourceMeta(debugConfig)) + return readResourceMeta(debugConfig) } var configFileName: String? = app.parameters.named["config"] @@ -84,25 +83,17 @@ fun getConfig(app: Application): Optional { } val configFile = Paths.get(configFileName) - if (Files.exists(configFile)) { - try { - val config = MetaFileReader.read(configFile) - return Optional.of(config) - } catch (e: IOException) { - throw RuntimeException(e) - } catch (e: ParseException) { - throw RuntimeException(e) - } - + return if (Files.exists(configFile)) { + MetaFileReader.read(configFile) } else { logger.warn("Configuration file not found") - return Optional.empty() + null } } -fun findDeviceMeta(config: Meta, criterion: Predicate): Optional { - return config.getMetaList("device").stream().filter(criterion).findFirst().map { it -> it } +fun findDeviceMeta(config: Meta, criterion: (Meta) -> Boolean): Meta? { + return config.getMetaList("device").stream().filter(criterion).findFirst().nullable } fun setupContext(meta: Meta): Context { diff --git a/numass-core/src/main/java/inr/numass/data/SpectrumAdapter.java b/numass-core/src/main/java/inr/numass/data/SpectrumAdapter.java deleted file mode 100644 index 7c45b4ab..00000000 --- a/numass-core/src/main/java/inr/numass/data/SpectrumAdapter.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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. - */ -package inr.numass.data; - -import hep.dataforge.meta.Meta; -import hep.dataforge.meta.MetaBuilder; -import hep.dataforge.tables.BasicAdapter; -import hep.dataforge.tables.ValueMap; -import hep.dataforge.tables.ValuesAdapter; -import hep.dataforge.values.Value; -import hep.dataforge.values.Values; - -import java.util.Optional; -import java.util.stream.Stream; - -import static hep.dataforge.tables.Adapters.*; - -/** - * @author Darksnake - */ -public class SpectrumAdapter extends BasicAdapter { - - private static final String POINT_LENGTH_NAME = "time"; - - public SpectrumAdapter(Meta meta) { - super(meta); - } - - public SpectrumAdapter(String xName, String yName, String yErrName, String measurementTime) { - super(new MetaBuilder(ValuesAdapter.ADAPTER_KEY) - .setValue(X_VALUE_KEY, xName) - .setValue(Y_VALUE_KEY, yName) - .setValue(Y_ERROR_KEY, yErrName) - .setValue(POINT_LENGTH_NAME, measurementTime) - .build() - ); - } - - public SpectrumAdapter(String xName, String yName, String measurementTime) { - super(new MetaBuilder(ValuesAdapter.ADAPTER_KEY) - .setValue(X_VALUE_KEY, xName) - .setValue(Y_VALUE_KEY, yName) - .setValue(POINT_LENGTH_NAME, measurementTime) - .build() - ); - } - - public double getTime(Values point) { - return this.optComponent(point, POINT_LENGTH_NAME).map(Value::doubleValue).orElse(1d); - } - - public Values buildSpectrumDataPoint(double x, long count, double t) { - return ValueMap.of(new String[]{getComponentName(X_VALUE_KEY), getComponentName(Y_VALUE_KEY), - getComponentName(POINT_LENGTH_NAME)}, - x, count, t); - } - - public Values buildSpectrumDataPoint(double x, long count, double countErr, double t) { - return ValueMap.of(new String[]{getComponentName(X_VALUE_KEY), getComponentName(Y_VALUE_KEY), - getComponentName(Y_ERROR_KEY), getComponentName(POINT_LENGTH_NAME)}, - x, count, countErr, t); - } - - - @Override - public Optional optComponent(Values values, String component) { - switch (component) { - case "count": - return super.optComponent(values, Y_VALUE_KEY); - case Y_VALUE_KEY: - return super.optComponent(values, Y_VALUE_KEY) - .map(it -> it.doubleValue() / getTime(values)) - .map(Value::of); - case Y_ERROR_KEY: - Optional err = super.optComponent(values, Y_ERROR_KEY); - if (err.isPresent()) { - return Optional.of(Value.of(err.get().doubleValue() / getTime(values))); - } else { - double y = getComponent(values, Y_VALUE_KEY).doubleValue(); - if (y < 0) { - return Optional.empty(); - } else if (y == 0) { - //avoid infinite weights - return Optional.of(Value.of(1d / getTime(values))); - } else { - return Optional.of(Value.of(Math.sqrt(y) / getTime(values))); - } - } - - default: - return super.optComponent(values, component); - } - } - - @Override - public Stream listComponents() { - return Stream.concat(super.listComponents(), Stream.of(X_VALUE_KEY, Y_VALUE_KEY, POINT_LENGTH_NAME)).distinct(); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/api/MetaBlock.java b/numass-core/src/main/java/inr/numass/data/api/MetaBlock.java deleted file mode 100644 index 1c809246..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/MetaBlock.java +++ /dev/null @@ -1,46 +0,0 @@ -package inr.numass.data.api; - -import java.time.Duration; -import java.time.Instant; -import java.util.*; -import java.util.stream.Stream; - -/** - * A block constructed from a set of other blocks. Internal blocks are not necessary subsequent. Blocks are automatically sorted. - * Created by darksnake on 16.07.2017. - */ -public class MetaBlock implements NumassBlock { - private SortedSet blocks = new TreeSet<>(Comparator.comparing(NumassBlock::getStartTime)); - - public MetaBlock(NumassBlock... blocks) { - this.blocks.addAll(Arrays.asList(blocks)); - } - - public MetaBlock(Collection blocks) { - this.blocks.addAll(blocks); - } - - @Override - public Instant getStartTime() { - return blocks.first().getStartTime(); - } - - @Override - public Duration getLength() { - return Duration.ofNanos(blocks.stream().mapToLong(block -> block.getLength().toNanos()).sum()); - } - - @Override - public Stream getEvents() { - return blocks.stream() - .sorted(Comparator.comparing(NumassBlock::getStartTime)) - .flatMap(NumassBlock::getEvents); - } - - @Override - public Stream getFrames() { - return blocks.stream() - .sorted(Comparator.comparing(NumassBlock::getStartTime)) - .flatMap(NumassBlock::getFrames); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/api/NumassBlock.java b/numass-core/src/main/java/inr/numass/data/api/NumassBlock.java deleted file mode 100644 index eafc97d6..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/NumassBlock.java +++ /dev/null @@ -1,36 +0,0 @@ -package inr.numass.data.api; - -import java.time.Duration; -import java.time.Instant; -import java.util.stream.Stream; - -/** - * A single continuous measurement block. The block can contain both isolated events and signal frames - *

- * Created by darksnake on 06-Jul-17. - */ -public interface NumassBlock { - /** - * The absolute start time of the block - * @return - */ - Instant getStartTime(); - - /** - * The length of the block - * @return - */ - Duration getLength(); - - /** - * Stream of isolated events. Could be empty - * @return - */ - Stream getEvents(); - - /** - * Stream of frames. Could be empty - * @return - */ - Stream getFrames(); -} diff --git a/numass-core/src/main/java/inr/numass/data/api/NumassEvent.java b/numass-core/src/main/java/inr/numass/data/api/NumassEvent.java deleted file mode 100644 index eb48edcf..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/NumassEvent.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 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. - */ -package inr.numass.data.api; - -import java.io.Serializable; -import java.time.Instant; - -/** - * A single numass event with given amplitude and time. - * - * @author Darksnake - */ -public class NumassEvent implements Serializable { - // channel - private final short chanel; - //The time of the block start - private final Instant blockTime; - //time in nanoseconds relative to block start - private final long timeOffset; - - public NumassEvent(short chanel, Instant blockTime, long offset) { - this.chanel = chanel; - this.blockTime = blockTime; - this.timeOffset = offset; - } - - public NumassEvent(short chanel, long offset) { - this(chanel, Instant.EPOCH, offset); - } - - /** - * @return the chanel - */ - public short getChanel() { - return chanel; - } - - /** - * time in nanoseconds relative to block start - * @return the time - */ - public long getTimeOffset() { - return timeOffset; - } - - public Instant getBlockTime() { - return blockTime; - } - - public Instant getTime() { - return blockTime.plusNanos(timeOffset); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/api/NumassFrame.java b/numass-core/src/main/java/inr/numass/data/api/NumassFrame.java deleted file mode 100644 index 0d7c61a8..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/NumassFrame.java +++ /dev/null @@ -1,50 +0,0 @@ -package inr.numass.data.api; - -import java.nio.ShortBuffer; -import java.time.Duration; -import java.time.Instant; - -/** - * The continuous frame of digital detector data - * Created by darksnake on 06-Jul-17. - */ -public class NumassFrame { - - /** - * The absolute start time of the frame - */ - private final Instant startTime; - - /** - * The buffered signal shape in ticks - */ - private final ShortBuffer signal; - - /** - * The time interval per tick - */ - private final Duration tickSize; - - - public NumassFrame(Instant startTime, Duration tickSize, ShortBuffer signal) { - this.startTime = startTime; - this.signal = signal; - this.tickSize = tickSize; - } - - public Instant getTime() { - return startTime; - } - - public ShortBuffer getSignal() { - return signal; - } - - public Duration getTickSize() { - return tickSize; - } - - public Duration getLength() { - return tickSize.multipliedBy(signal.capacity()); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/api/NumassPoint.java b/numass-core/src/main/java/inr/numass/data/api/NumassPoint.java deleted file mode 100644 index c9129a00..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/NumassPoint.java +++ /dev/null @@ -1,94 +0,0 @@ -package inr.numass.data.api; - -import hep.dataforge.meta.Metoid; -import hep.dataforge.values.Value; - -import java.time.Duration; -import java.time.Instant; -import java.util.stream.Stream; - -/** - * Created by darksnake on 06-Jul-17. - */ -public interface NumassPoint extends Metoid, NumassBlock { - - String START_TIME_KEY = "start"; - String LENGTH_KEY = "length"; - String HV_KEY = "voltage"; - String INDEX_KEY = "index"; - - - Stream getBlocks(); - - /** - * Get the voltage setting for the point - * - * @return - */ - default double getVoltage() { - return getMeta().getDouble(HV_KEY, 0); - } - - /** - * Get the index for this point in the set - * @return - */ - default int getIndex() { - return getMeta().getInt(INDEX_KEY, -1); - } - - /** - * Get the first block if it exists. Throw runtime exception otherwise. - * - * @return - */ - default NumassBlock getFirstBlock() { - return getBlocks().findFirst().orElseThrow(() -> new RuntimeException("The point is empty")); - } - - /** - * Get the starting time from meta or from first block - * - * @return - */ - @Override - default Instant getStartTime() { - return getMeta().optValue(START_TIME_KEY).map(Value::timeValue).orElseGet(() -> getFirstBlock().getStartTime()); - } - - /** - * Get the length key of meta or calculate length as a sum of block lengths. The latter could be a bit slow - * - * @return - */ - @Override - default Duration getLength() { - return Duration.ofNanos( - getMeta().optValue(LENGTH_KEY).map(Value::longValue) - .orElseGet(() -> getBlocks().mapToLong(it -> it.getLength().toNanos()).sum()) - ); - } - - /** - * Get all events it all blocks as a single sequence - *

- * Some performance analysis of different stream concatenation approaches is given here: https://www.techempower.com/blog/2016/10/19/efficient-multiple-stream-concatenation-in-java/ - *

- * - * @return - */ - @Override - default Stream getEvents() { - return getBlocks().flatMap(NumassBlock::getEvents); - } - - /** - * Get all frames in all blocks as a single sequence - * - * @return - */ - @Override - default Stream getFrames() { - return getBlocks().flatMap(NumassBlock::getFrames); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/api/NumassSet.java b/numass-core/src/main/java/inr/numass/data/api/NumassSet.java deleted file mode 100644 index 49771ec4..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/NumassSet.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package inr.numass.data.api; - -import hep.dataforge.meta.Metoid; -import hep.dataforge.names.Named; -import hep.dataforge.providers.Provider; -import hep.dataforge.providers.Provides; -import hep.dataforge.providers.ProvidesNames; -import hep.dataforge.tables.Table; -import hep.dataforge.values.Value; -import org.jetbrains.annotations.NotNull; - -import java.time.Instant; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * A single set of numass points previously called file. - * - * @author Alexander Nozik - */ -public interface NumassSet extends Named, Metoid, Iterable, Provider { - String DESCRIPTION_KEY = "info"; - String NUMASS_POINT_PROVIDER_KEY = "point"; - - Stream getPoints(); - -// default String getDescription() { -// return getMeta().getString(DESCRIPTION_KEY, ""); -// } - - @NotNull - @Override - default Iterator iterator() { - return getPoints().iterator(); - } - - /** - * Get the first point if it exists. Throw runtime exception otherwise. - * - * @return - */ - default NumassPoint getFirstPoint() { - return getPoints().findFirst().orElseThrow(() -> new RuntimeException("The set is empty")); - } - - /** - * Get the starting time from meta or from first point - * - * @return - */ - default Instant getStartTime() { - return getMeta().optValue(NumassPoint.START_TIME_KEY).map(Value::timeValue).orElseGet(() -> getFirstPoint().getStartTime()); - } - - /** - * Find first point with given voltage - * - * @param voltage - * @return - */ - default Optional optPoint(double voltage) { - return getPoints().filter(it -> it.getVoltage() == voltage).findFirst(); - } - - /** - * List all points with given voltage - * - * @param voltage - * @return - */ - default List getPoints(double voltage) { - return getPoints().filter(it -> it.getVoltage() == voltage).collect(Collectors.toList()); - } - - @Provides(NUMASS_POINT_PROVIDER_KEY) - default Optional optPoint(String voltage) { - return optPoint(Double.parseDouble(voltage)); - } - - @Override - default String defaultTarget() { - return NUMASS_POINT_PROVIDER_KEY; - } - - @ProvidesNames(NUMASS_POINT_PROVIDER_KEY) - default Stream listPoints() { - return getPoints().map(it -> Double.toString(it.getVoltage())); - } - - default Optional getHvData() { - return Optional.empty(); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/api/SignalProcessor.java b/numass-core/src/main/java/inr/numass/data/api/SignalProcessor.java deleted file mode 100644 index 8f2d212c..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/SignalProcessor.java +++ /dev/null @@ -1,11 +0,0 @@ -package inr.numass.data.api; - -import java.util.stream.Stream; - -/** - * An ancestor to numass frame analyzers - * Created by darksnake on 07.07.2017. - */ -public interface SignalProcessor { - Stream analyze(NumassFrame frame); -} diff --git a/numass-core/src/main/java/inr/numass/data/api/SimpleBlock.java b/numass-core/src/main/java/inr/numass/data/api/SimpleBlock.java deleted file mode 100644 index a38ec952..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/SimpleBlock.java +++ /dev/null @@ -1,43 +0,0 @@ -package inr.numass.data.api; - -import java.io.Serializable; -import java.time.Duration; -import java.time.Instant; -import java.util.List; -import java.util.stream.Stream; - -/** - * A simple in-memory implementation of block of events. No frames are allowed - * Created by darksnake on 08.07.2017. - */ -public class SimpleBlock implements NumassBlock, Serializable { - private final Instant startTime; - private final Duration length; - private final List events; - - public SimpleBlock(Instant startTime, Duration length, List events) { - this.startTime = startTime; - this.length = length; - this.events = events; - } - - @Override - public Instant getStartTime() { - return startTime; - } - - @Override - public Duration getLength() { - return length; - } - - @Override - public Stream getEvents() { - return events.stream(); - } - - @Override - public Stream getFrames() { - return Stream.empty(); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/api/SimpleNumassPoint.java b/numass-core/src/main/java/inr/numass/data/api/SimpleNumassPoint.java deleted file mode 100644 index 3a6b52ec..00000000 --- a/numass-core/src/main/java/inr/numass/data/api/SimpleNumassPoint.java +++ /dev/null @@ -1,41 +0,0 @@ -package inr.numass.data.api; - -import hep.dataforge.meta.Meta; -import hep.dataforge.meta.MetaBuilder; -import hep.dataforge.meta.MetaHolder; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Stream; - -/** - * A simple static implementation of NumassPoint - * Created by darksnake on 08.07.2017. - */ -public class SimpleNumassPoint extends MetaHolder implements NumassPoint { - private final List blocks; - - /** - * Input blocks must be sorted - * @param voltage - * @param blocks - */ - public SimpleNumassPoint(double voltage, Collection blocks) { - super(new MetaBuilder("point").setValue(HV_KEY, voltage)); - this.blocks = new ArrayList<>(blocks); - this.blocks.sort(Comparator.comparing(NumassBlock::getStartTime)); - } - - public SimpleNumassPoint(Meta meta, Collection blocks) { - super(meta); - this.blocks = new ArrayList<>(blocks); - this.blocks.sort(Comparator.comparing(NumassBlock::getStartTime)); - } - - @Override - public Stream getBlocks() { - return blocks.stream(); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/legacy/NumassDatFile.java b/numass-core/src/main/java/inr/numass/data/legacy/NumassDatFile.java deleted file mode 100644 index ca933a02..00000000 --- a/numass-core/src/main/java/inr/numass/data/legacy/NumassDatFile.java +++ /dev/null @@ -1,265 +0,0 @@ -package inr.numass.data.legacy; - -import hep.dataforge.meta.Meta; -import hep.dataforge.meta.MetaBuilder; -import inr.numass.data.api.*; -import org.apache.commons.io.FilenameUtils; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.Duration; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Scanner; -import java.util.stream.Stream; - -import static inr.numass.data.api.NumassPoint.HV_KEY; -import static java.nio.file.StandardOpenOption.READ; - -/** - * Created by darksnake on 08.07.2017. - */ -public class NumassDatFile implements NumassSet { - private final String name; - private final Path path; - private final Meta meta; - - public NumassDatFile(Path path, Meta meta) throws IOException { - this(FilenameUtils.getBaseName(path.getFileName().toString()),path,meta); - } - - public NumassDatFile(String name, Path path, Meta meta) throws IOException { - this.name = name; - this.path = path; - String head = readHead(path);//2048 - this.meta = new MetaBuilder(meta) - .setValue("info", head) - .setValue(NumassPoint.START_TIME_KEY, readDate(head)) - .build(); - } - - @Override - public Meta getMeta() { - return meta; - } - - @Override - public String getName() { - return name; - } - - private double getHVdev() { - return getMeta().getDouble("dat.hvDev", 2.468555393226049); - } - - private boolean hasUset() { - return getMeta().getBoolean("dat.uSet", true); - } - - private static String readHead(Path path) throws IOException { - try (SeekableByteChannel channel = Files.newByteChannel(path, READ)) { - channel.position(0); - ByteBuffer buffer = ByteBuffer.allocate(2048); - channel.read(buffer); - return new String(buffer.array()).replaceAll("\u0000", ""); - } - } - - /** - * Read the block at current position - * - * @param channel - * @param length - * @return - * @throws IOException - */ - private ByteBuffer readBlock(SeekableByteChannel channel, int length) throws IOException { - ByteBuffer res = ByteBuffer.allocate(length); - channel.read(res); - res.order(ByteOrder.LITTLE_ENDIAN); - res.flip(); - return res; - } - - /** - * Read the point at current position - * - * @param channel - * @return - * @throws IOException - */ - private synchronized NumassPoint readPoint(SeekableByteChannel channel) throws - IOException { - - ByteBuffer rx = readBlock(channel, 32); - - int voltage = rx.getInt(); - - short length = rx.getShort();//(short) (rx[6] + 256 * rx[7]); - boolean phoneFlag = rx.get(19) != 0;//(rx[19] != 0); - - - double timeDiv; - switch (length) { - case 5: - case 10: - timeDiv = 2e7; - break; - case 15: - case 20: - timeDiv = 1e7; - break; - case 50: - timeDiv = 5e6; - break; - case 100: - timeDiv = 2.5e6; - break; - case 200: - timeDiv = 1.25e6; - break; - default: - throw new IOException("Unknown time divider in input data"); - } - - if (phoneFlag) { - timeDiv /= 20.0; - length *= 20; - } - - List events = new ArrayList<>(); - int lab = readBlock(channel, 1).get(); - - while (lab == 0xBF) { - ByteBuffer buffer = readBlock(channel, 5); - lab = buffer.get(4); - } - - do { - events.add(readEvent(channel, lab, timeDiv)); - lab = readBlock(channel, 1).get(); - } while (lab != 0xAF); - - //point end - ByteBuffer ending = readBlock(channel, 64); - - int hours = ending.get(37); - int minutes = ending.get(38); - - LocalDateTime start = LocalDateTime.from(getStartTime()); - LocalDateTime absoluteTime = start.withHour(hours).withMinute(minutes); - - //проверяем, не проскочили ли мы полночь - if (absoluteTime.isBefore(start)) { - absoluteTime = absoluteTime.plusDays(1); - } - - - int uRead = ending.getInt(39); - - double uSet; - if (!this.hasUset()) { - uSet = uRead / 10d / getHVdev(); - } else { - uSet = voltage / 10d; - } - - NumassBlock block = new SimpleBlock(absoluteTime.toInstant(ZoneOffset.UTC), Duration.ofSeconds(length), events); - - Meta pointMeta = new MetaBuilder("point") - .setValue(HV_KEY, uSet) - .setValue("uRead", uRead / 10 / getHVdev()) - .setValue("source", "legacy"); - - - return new SimpleNumassPoint(pointMeta, Collections.singletonList(block)); - } - - @Override - public Stream getPoints() { - try (SeekableByteChannel channel = Files.newByteChannel(path, READ)) { - - //int lab = readBlock(channel,1).get(); - int lab; - List points = new ArrayList<>(); - do { - //TODO check point start - points.add(readPoint(channel)); - lab = readBlock(channel, 1).get(); - } while (lab != 0xff); - return points.stream(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - - } - - private LocalDateTime readDate(String head) throws IOException { - // Должны считать 14 символов - Scanner sc = new Scanner(head); - sc.nextLine(); - String dateStr = sc.nextLine().trim(); - //DD.MM.YY HH:MM - //12:35:16 19-11-2013 - DateTimeFormatter format = DateTimeFormatter.ofPattern("HH:mm:ss dd-MM-yyyy"); - - return LocalDateTime.parse(dateStr, format); - } - - private NumassEvent readEvent(SeekableByteChannel channel, int b, double timeDiv) throws IOException { - short chanel; - long time; - - int hb = (b & 0x0f); - int lab = (b & 0xf0); - - switch (lab) { - case 0x10: - chanel = readChanel(channel, hb); - time = readTime(channel); - break; - case 0x20: - chanel = 0; - time = readTime(channel); - break; - case 0x40: - time = 0; - chanel = readChanel(channel, hb); - break; - case 0x80: - time = 0; - chanel = 0; - break; - default: - throw new IOException("Event head expected"); - } - - return new NumassEvent(chanel, (long) (time / timeDiv)); - } - - private short readChanel(SeekableByteChannel channel, int hb) throws IOException { - assert hb < 127; - ByteBuffer buffer = readBlock(channel, 1); - return (short) (buffer.get() + 256 * hb); - } - - private long readTime(SeekableByteChannel channel) throws IOException { - ByteBuffer rx = readBlock(channel, 4); - return rx.getLong();//rx[0] + 256 * rx[1] + 65536 * rx[2] + 256 * 65536 * rx[3]; - } - -// private void skip(int length) throws IOException { -// long n = stream.skip(length); -// if (n != length) { -// stream.skip(length - n); -// } -// } -} diff --git a/numass-core/src/main/java/inr/numass/data/legacy/NumassFileEnvelope.java b/numass-core/src/main/java/inr/numass/data/legacy/NumassFileEnvelope.java deleted file mode 100644 index a985c7c0..00000000 --- a/numass-core/src/main/java/inr/numass/data/legacy/NumassFileEnvelope.java +++ /dev/null @@ -1,45 +0,0 @@ -package inr.numass.data.legacy; - -import hep.dataforge.io.envelopes.EnvelopeTag; -import hep.dataforge.storage.filestorage.FileEnvelope; -import inr.numass.NumassEnvelopeType; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Path; - -import static java.nio.file.StandardOpenOption.READ; - -public class NumassFileEnvelope extends FileEnvelope { - - public static byte[] LEGACY_START_SEQUENCE = {'#','!'}; - public static byte[] LEGACY_END_SEQUENCE = {'!','#','\r','\n'}; - - public static FileEnvelope open(Path path, boolean readOnly) { -// if (!Files.exists(path)) { -// throw new RuntimeException("File envelope does not exist"); -// } - - try (FileChannel channel = FileChannel.open(path,READ)) { - MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, 2); - if (buffer.compareTo(ByteBuffer.wrap(LEGACY_START_SEQUENCE)) == 0) { - return new NumassFileEnvelope(path, readOnly); - } else { - return FileEnvelope.Companion.open(path, readOnly); - } - } catch (IOException e) { - throw new RuntimeException("Failed to open file envelope", e); - } - } - - private NumassFileEnvelope(Path path, boolean readOnly) { - super(path, readOnly); - } - - @Override - protected EnvelopeTag buildTag() { - return new NumassEnvelopeType.LegacyTag(); - } -} diff --git a/numass-core/src/main/kotlin/inr/numass/data/SpectrumAdapter.kt b/numass-core/src/main/kotlin/inr/numass/data/SpectrumAdapter.kt new file mode 100644 index 00000000..522c1d73 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/SpectrumAdapter.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ +package inr.numass.data + +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaBuilder +import hep.dataforge.tables.Adapters.* +import hep.dataforge.tables.BasicAdapter +import hep.dataforge.tables.ValueMap +import hep.dataforge.tables.ValuesAdapter +import hep.dataforge.values.Value +import hep.dataforge.values.Values +import java.util.* +import java.util.stream.Stream + +/** + * @author Darksnake + */ +class SpectrumAdapter : BasicAdapter { + + constructor(meta: Meta) : super(meta) {} + + constructor(xName: String, yName: String, yErrName: String, measurementTime: String) : super(MetaBuilder(ValuesAdapter.ADAPTER_KEY) + .setValue(X_VALUE_KEY, xName) + .setValue(Y_VALUE_KEY, yName) + .setValue(Y_ERROR_KEY, yErrName) + .setValue(POINT_LENGTH_NAME, measurementTime) + .build() + ) { + } + + constructor(xName: String, yName: String, measurementTime: String) : super(MetaBuilder(ValuesAdapter.ADAPTER_KEY) + .setValue(X_VALUE_KEY, xName) + .setValue(Y_VALUE_KEY, yName) + .setValue(POINT_LENGTH_NAME, measurementTime) + .build() + ) { + } + + fun getTime(point: Values): Double { + return this.optComponent(point, POINT_LENGTH_NAME).map { it.doubleValue() }.orElse(1.0) + } + + fun buildSpectrumDataPoint(x: Double, count: Long, t: Double): Values { + return ValueMap.of(arrayOf(getComponentName(X_VALUE_KEY), getComponentName(Y_VALUE_KEY), getComponentName(POINT_LENGTH_NAME)), + x, count, t) + } + + fun buildSpectrumDataPoint(x: Double, count: Long, countErr: Double, t: Double): Values { + return ValueMap.of(arrayOf(getComponentName(X_VALUE_KEY), getComponentName(Y_VALUE_KEY), getComponentName(Y_ERROR_KEY), getComponentName(POINT_LENGTH_NAME)), + x, count, countErr, t) + } + + + override fun optComponent(values: Values, component: String): Optional { + when (component) { + "count" -> return super.optComponent(values, Y_VALUE_KEY) + Y_VALUE_KEY -> return super.optComponent(values, Y_VALUE_KEY) + .map { it -> it.doubleValue() / getTime(values) } + .map { Value.of(it) } + Y_ERROR_KEY -> { + val err = super.optComponent(values, Y_ERROR_KEY) + return if (err.isPresent) { + Optional.of(Value.of(err.get().doubleValue() / getTime(values))) + } else { + val y = getComponent(values, Y_VALUE_KEY).doubleValue() + if (y < 0) { + Optional.empty() + } else if (y == 0.0) { + //avoid infinite weights + Optional.of(Value.of(1.0 / getTime(values))) + } else { + Optional.of(Value.of(Math.sqrt(y) / getTime(values))) + } + } + } + + else -> return super.optComponent(values, component) + } + } + + override fun listComponents(): Stream { + return Stream.concat(super.listComponents(), Stream.of(X_VALUE_KEY, Y_VALUE_KEY, POINT_LENGTH_NAME)).distinct() + } + + companion object { + private const val POINT_LENGTH_NAME = "time" + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt index b5e71c84..c2931380 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt @@ -24,7 +24,7 @@ import hep.dataforge.tables.TableFormat import hep.dataforge.tables.TableFormatBuilder import inr.numass.data.api.NumassBlock import inr.numass.data.api.NumassEvent -import inr.numass.data.api.NumassPoint.HV_KEY +import inr.numass.data.api.NumassPoint.Companion.HV_KEY import inr.numass.data.api.NumassSet import inr.numass.data.api.SignalProcessor import java.lang.IllegalArgumentException @@ -48,7 +48,7 @@ abstract class AbstractAnalyzer @JvmOverloads constructor(private val processor: val loChannel = meta.getInt("window.lo", 0) val upChannel = meta.getInt("window.up", Integer.MAX_VALUE) var res = getAllEvents(block).filter { event -> - event.chanel.toInt() in loChannel..(upChannel - 1) + event.amp.toInt() in loChannel..(upChannel - 1) } if (meta.getBoolean("sort", false)) { res = res.sorted(Comparator.comparing { it.timeOffset }) diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt index 176c4aef..38772afd 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt @@ -24,7 +24,7 @@ import hep.dataforge.values.Values import inr.numass.data.api.NumassBlock import inr.numass.data.api.NumassEvent import inr.numass.data.api.NumassPoint -import inr.numass.data.api.NumassPoint.HV_KEY +import inr.numass.data.api.NumassPoint.Companion.HV_KEY import inr.numass.data.api.NumassSet import java.util.* import java.util.concurrent.atomic.AtomicLong @@ -56,7 +56,7 @@ interface NumassAnalyzer { */ fun analyzePoint(point: NumassPoint, config: Meta = Meta.empty()): Values { val map = HashMap(analyze(point, config).asMap()) - map.put(HV_KEY, Value.of(point.voltage)) + map[HV_KEY] = Value.of(point.voltage) return ValueMap(map) } @@ -161,7 +161,7 @@ fun getAmplitudeSpectrum(events: Sequence, length: Double, config: //optimized for fastest computation val spectrum: MutableMap = HashMap() events.forEach { event -> - val channel = event.chanel.toInt() + val channel = event.amp.toInt() spectrum.getOrPut(channel) { AtomicLong(0) }.incrementAndGet() diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt index afb9f574..2af3d4a3 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt @@ -29,7 +29,7 @@ import hep.dataforge.values.Values import inr.numass.data.api.NumassBlock import inr.numass.data.api.NumassEvent import inr.numass.data.api.NumassPoint -import inr.numass.data.api.NumassPoint.HV_KEY +import inr.numass.data.api.NumassPoint.Companion.HV_KEY import inr.numass.data.api.SignalProcessor import java.util.* import java.util.concurrent.atomic.AtomicLong diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt b/numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt new file mode 100644 index 00000000..53ca2f99 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt @@ -0,0 +1,38 @@ +package inr.numass.data.api + +import java.time.Duration +import java.time.Instant +import java.util.* +import java.util.stream.Stream + +/** + * A block constructed from a set of other blocks. Internal blocks are not necessary subsequent. Blocks are automatically sorted. + * Created by darksnake on 16.07.2017. + */ +class MetaBlock : NumassBlock { + private val blocks = TreeSet(Comparator.comparing{ it.startTime }) + + override val startTime: Instant + get() = blocks.first().startTime + + override val length: Duration + get() = Duration.ofNanos(blocks.stream().mapToLong { block -> block.length.toNanos() }.sum()) + + override val events: Stream + get() = blocks.stream() + .sorted(Comparator.comparing{ it.startTime }) + .flatMap{ it.events } + + override val frames: Stream + get() = blocks.stream() + .sorted(Comparator.comparing{ it.startTime }) + .flatMap{ it.frames } + + constructor(vararg blocks: NumassBlock) { + this.blocks.addAll(Arrays.asList(*blocks)) + } + + constructor(blocks: Collection) { + this.blocks.addAll(blocks) + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt new file mode 100644 index 00000000..ad822822 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt @@ -0,0 +1,49 @@ +package inr.numass.data.api + +import java.time.Duration +import java.time.Instant +import java.util.stream.Stream + + +typealias NumassChannel = Int + + + +/** + * A single continuous measurement block. The block can contain both isolated events and signal frames + * + * + * Created by darksnake on 06-Jul-17. + */ +interface NumassBlock { + + /** + * A channel + */ + val channel: NumassChannel + get() = DEFAULT_CHANNEL + + /** + * The absolute start time of the block + */ + val startTime: Instant + + /** + * The length of the block + */ + val length: Duration + + /** + * Stream of isolated events. Could be empty + */ + val events: Stream + + /** + * Stream of frames. Could be empty + */ + val frames: Stream + + companion object { + val DEFAULT_CHANNEL: NumassChannel = -1 + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt new file mode 100644 index 00000000..d5851918 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ +package inr.numass.data.api + +import java.io.Serializable +import java.time.Instant + +/** + * A single numass event with given amplitude and time. + * + * @author Darksnake + * @property amp the amplitude of the event + * @property blockTime + * @property timeOffset time in nanoseconds relative to block start + * + */ +class NumassEvent(val amp: Short, val timeOffset: Long, val block: NumassBlock? = null) : Serializable { + + val channel: NumassChannel? + get() = block?.channel + + val time: Instant + get() = (block?.startTime ?: Instant.EPOCH).plusNanos(timeOffset) + +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassFrame.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassFrame.kt new file mode 100644 index 00000000..e77abd5a --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/NumassFrame.kt @@ -0,0 +1,27 @@ +package inr.numass.data.api + +import java.nio.ShortBuffer +import java.time.Duration +import java.time.Instant + +/** + * The continuous frame of digital detector data + * Created by darksnake on 06-Jul-17. + */ +class NumassFrame( + /** + * The absolute start time of the frame + */ + val time: Instant, + /** + * The time interval per tick + */ + val tickSize: Duration, + /** + * The buffered signal shape in ticks + */ + val signal: ShortBuffer) { + + val length: Duration + get() = tickSize.multipliedBy(signal.capacity().toLong()) +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassPoint.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassPoint.kt new file mode 100644 index 00000000..ebcba2d8 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/NumassPoint.kt @@ -0,0 +1,85 @@ +package inr.numass.data.api + +import hep.dataforge.meta.Metoid +import java.time.Duration +import java.time.Instant +import java.util.stream.Stream + +/** + * Created by darksnake on 06-Jul-17. + */ +interface NumassPoint : Metoid, NumassBlock { + + + val blocks: Stream + + /** + * Get the voltage setting for the point + * + * @return + */ + val voltage: Double + get() = meta.getDouble(HV_KEY, 0.0) + + /** + * Get the index for this point in the set + * @return + */ + val index: Int + get() = meta.getInt(INDEX_KEY, -1) + + /** + * Get the first block if it exists. Throw runtime exception otherwise. + * + * @return + */ + val firstBlock: NumassBlock + get() = blocks.findFirst().orElseThrow { RuntimeException("The point is empty") } + + /** + * Get the starting time from meta or from first block + * + * @return + */ + override val startTime: Instant + get() = meta.optValue(START_TIME_KEY).map{ it.timeValue() }.orElseGet { firstBlock.startTime } + + /** + * Get the length key of meta or calculate length as a sum of block lengths. The latter could be a bit slow + * + * @return + */ + override val length: Duration + get() = Duration.ofNanos( + meta.optValue(LENGTH_KEY).map{ it.longValue() } + .orElseGet { blocks.mapToLong { it -> it.length.toNanos() }.sum() } + ) + + /** + * Get all events it all blocks as a single sequence + * + * + * Some performance analysis of different stream concatenation approaches is given here: https://www.techempower.com/blog/2016/10/19/efficient-multiple-stream-concatenation-in-java/ + * + * + * @return + */ + override val events: Stream + get() = blocks.flatMap{ it.events } + + /** + * Get all frames in all blocks as a single sequence + * + * @return + */ + override val frames: Stream + get() = blocks.flatMap{ it.frames } + + companion object { + + const val START_TIME_KEY = "start" + const val LENGTH_KEY = "length" + const val HV_KEY = "voltage" + const val INDEX_KEY = "index" + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt new file mode 100644 index 00000000..c126141f --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt @@ -0,0 +1,93 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package inr.numass.data.api + +import hep.dataforge.kodex.toList +import hep.dataforge.meta.Metoid +import hep.dataforge.names.Named +import hep.dataforge.providers.Provider +import hep.dataforge.providers.Provides +import hep.dataforge.providers.ProvidesNames +import hep.dataforge.tables.Table +import java.time.Instant +import java.util.* +import java.util.stream.Stream + +/** + * A single set of numass points previously called file. + * + * @author [Alexander Nozik](mailto:altavir@gmail.com) + */ +interface NumassSet : Named, Metoid, Iterable, Provider { + + val points: Stream + + /** + * Get the first point if it exists. Throw runtime exception otherwise. + * + * @return + */ + val firstPoint: NumassPoint + get() = points.findFirst().orElseThrow { RuntimeException("The set is empty") } + + /** + * Get the starting time from meta or from first point + * + * @return + */ + val startTime: Instant + get() = meta.optValue(NumassPoint.START_TIME_KEY).map{ it.timeValue() }.orElseGet { firstPoint.startTime } + + val hvData: Optional
+ get() = Optional.empty() + + // default String getDescription() { + // return getMeta().getString(DESCRIPTION_KEY, ""); + // } + + override fun iterator(): Iterator { + return points.iterator() + } + + /** + * Find first point with given voltage + * + * @param voltage + * @return + */ + fun optPoint(voltage: Double): Optional { + return points.filter { it -> it.voltage == voltage }.findFirst() + } + + /** + * List all points with given voltage + * + * @param voltage + * @return + */ + fun getPoints(voltage: Double): List { + return points.filter { it -> it.voltage == voltage }.toList() + } + + @Provides(NUMASS_POINT_PROVIDER_KEY) + fun optPoint(voltage: String): Optional { + return optPoint(java.lang.Double.parseDouble(voltage)) + } + + override fun defaultTarget(): String { + return NUMASS_POINT_PROVIDER_KEY + } + + @ProvidesNames(NUMASS_POINT_PROVIDER_KEY) + fun listPoints(): Stream { + return points.map { it -> java.lang.Double.toString(it.voltage) } + } + + companion object { + const val DESCRIPTION_KEY = "info" + const val NUMASS_POINT_PROVIDER_KEY = "point" + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/SignalProcessor.kt b/numass-core/src/main/kotlin/inr/numass/data/api/SignalProcessor.kt new file mode 100644 index 00000000..22c30e01 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/SignalProcessor.kt @@ -0,0 +1,11 @@ +package inr.numass.data.api + +import java.util.stream.Stream + +/** + * An ancestor to numass frame analyzers + * Created by darksnake on 07.07.2017. + */ +interface SignalProcessor { + fun analyze(frame: NumassFrame): Stream +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt b/numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt new file mode 100644 index 00000000..7a9f25d6 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt @@ -0,0 +1,19 @@ +package inr.numass.data.api + +import java.io.Serializable +import java.time.Duration +import java.time.Instant +import java.util.stream.Stream + +/** + * A simple in-memory implementation of block of events. No frames are allowed + * Created by darksnake on 08.07.2017. + */ +class SimpleBlock(override val startTime: Instant, override val length: Duration, private val eventList: List) : NumassBlock, Serializable { + + override val frames: Stream = Stream.empty() + + override val events: Stream + get() = eventList.stream() + +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/SimpleNumassPoint.kt b/numass-core/src/main/kotlin/inr/numass/data/api/SimpleNumassPoint.kt new file mode 100644 index 00000000..c1f36f96 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/api/SimpleNumassPoint.kt @@ -0,0 +1,31 @@ +package inr.numass.data.api + +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaBuilder +import hep.dataforge.meta.MetaHolder + +import java.util.stream.Stream + +/** + * A simple static implementation of NumassPoint + * Created by darksnake on 08.07.2017. + */ +class SimpleNumassPoint : MetaHolder, NumassPoint { + private val blockList: List + + /** + * Input blocks must be sorted + * @param voltage + * @param blocks + */ + constructor(voltage: Double, blocks: Collection) : super(MetaBuilder("point").setValue(NumassPoint.HV_KEY, voltage)) { + this.blockList = blocks.sortedBy { it.startTime } + } + + constructor(meta: Meta, blocks: Collection) : super(meta) { + this.blockList = blocks.sortedBy { it.startTime } + } + + override val blocks: Stream + get() = blockList.stream() +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt b/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt new file mode 100644 index 00000000..6072ae42 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt @@ -0,0 +1,244 @@ +package inr.numass.data.legacy + +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaBuilder +import inr.numass.data.api.* +import inr.numass.data.api.NumassPoint.Companion.HV_KEY +import org.apache.commons.io.FilenameUtils +import java.io.IOException +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.nio.channels.SeekableByteChannel +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardOpenOption.READ +import java.time.Duration +import java.time.LocalDateTime +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter +import java.util.* +import java.util.stream.Stream + +/** + * Created by darksnake on 08.07.2017. + */ +class NumassDatFile @Throws(IOException::class) +constructor(private val name: String, private val path: Path, meta: Meta) : NumassSet { + private val meta: Meta + + private val hVdev: Double + get() = getMeta().getDouble("dat.hvDev", 2.468555393226049) + + override//int lab = readBlock(channel,1).get(); + //TODO check point start + val points: Stream + get() = try { + Files.newByteChannel(path, READ).use { channel -> + var lab: Int + val points = ArrayList() + do { + points.add(readPoint(channel)) + lab = readBlock(channel, 1).get().toInt() + } while (lab != 0xff) + return points.stream() + } + } catch (ex: IOException) { + throw RuntimeException(ex) + } + + @Throws(IOException::class) + constructor(path: Path, meta: Meta) : this(FilenameUtils.getBaseName(path.fileName.toString()), path, meta) { + } + + init { + val head = readHead(path)//2048 + this.meta = MetaBuilder(meta) + .setValue("info", head) + .setValue(NumassPoint.START_TIME_KEY, readDate(head)) + .build() + } + + override fun getMeta(): Meta { + return meta + } + + override fun getName(): String { + return name + } + + private fun hasUset(): Boolean { + return getMeta().getBoolean("dat.uSet", true) + } + + @Throws(IOException::class) + private fun readHead(path: Path): String { + Files.newByteChannel(path, READ).use { channel -> + channel.position(0) + val buffer = ByteBuffer.allocate(2048) + channel.read(buffer) + return String(buffer.array()).replace("\u0000".toRegex(), "") + } + } + + /** + * Read the block at current position + * + * @param channel + * @param length + * @return + * @throws IOException + */ + @Throws(IOException::class) + private fun readBlock(channel: SeekableByteChannel, length: Int): ByteBuffer { + val res = ByteBuffer.allocate(length) + channel.read(res) + res.order(ByteOrder.LITTLE_ENDIAN) + res.flip() + return res + } + + /** + * Read the point at current position + * + * @param channel + * @return + * @throws IOException + */ + @Synchronized + @Throws(IOException::class) + private fun readPoint(channel: SeekableByteChannel): NumassPoint { + + val rx = readBlock(channel, 32) + + val voltage = rx.int + + var length = rx.short//(short) (rx[6] + 256 * rx[7]); + val phoneFlag = rx.get(19).toInt() != 0//(rx[19] != 0); + + + var timeDiv: Double = when (length.toInt()) { + 5, 10 -> 2e7 + 15, 20 -> 1e7 + 50 -> 5e6 + 100 -> 2.5e6 + 200 -> 1.25e6 + else -> throw IOException("Unknown time divider in input data") + } + + if (phoneFlag) { + timeDiv /= 20.0 + length = (length*20).toShort() + } + + val events = ArrayList() + var lab = readBlock(channel, 1).get().toInt() + + while (lab == 0xBF) { + val buffer = readBlock(channel, 5) + lab = buffer.get(4).toInt() + } + + do { + events.add(readEvent(channel, lab, timeDiv)) + lab = readBlock(channel, 1).get().toInt() + } while (lab != 0xAF) + + //point end + val ending = readBlock(channel, 64) + + val hours = ending.get(37).toInt() + val minutes = ending.get(38).toInt() + + val start = LocalDateTime.from(startTime) + var absoluteTime = start.withHour(hours).withMinute(minutes) + + //проверяем, не проскочили ли мы полночь + if (absoluteTime.isBefore(start)) { + absoluteTime = absoluteTime.plusDays(1) + } + + + val uRead = ending.getInt(39) + + val uSet: Double + if (!this.hasUset()) { + uSet = uRead.toDouble() / 10.0 / hVdev + } else { + uSet = voltage / 10.0 + } + + val block = SimpleBlock(absoluteTime.toInstant(ZoneOffset.UTC), Duration.ofSeconds(length.toLong()), events) + + val pointMeta = MetaBuilder("point") + .setValue(HV_KEY, uSet) + .setValue("uRead", uRead.toDouble() / 10.0 / hVdev) + .setValue("source", "legacy") + + + return SimpleNumassPoint(pointMeta, listOf(block)) + } + + @Throws(IOException::class) + private fun readDate(head: String): LocalDateTime { + // Должны считать 14 символов + val sc = Scanner(head) + sc.nextLine() + val dateStr = sc.nextLine().trim { it <= ' ' } + //DD.MM.YY HH:MM + //12:35:16 19-11-2013 + val format = DateTimeFormatter.ofPattern("HH:mm:ss dd-MM-yyyy") + + return LocalDateTime.parse(dateStr, format) + } + + @Throws(IOException::class) + private fun readEvent(channel: SeekableByteChannel, b: Int, timeDiv: Double): NumassEvent { + val chanel: Short + val time: Long + + val hb = b and 0x0f + val lab = b and 0xf0 + + when (lab) { + 0x10 -> { + chanel = readChanel(channel, hb) + time = readTime(channel) + } + 0x20 -> { + chanel = 0 + time = readTime(channel) + } + 0x40 -> { + time = 0 + chanel = readChanel(channel, hb) + } + 0x80 -> { + time = 0 + chanel = 0 + } + else -> throw IOException("Event head expected") + } + + return NumassEvent(chanel, (time / timeDiv).toLong()) + } + + @Throws(IOException::class) + private fun readChanel(channel: SeekableByteChannel, hb: Int): Short { + assert(hb < 127) + val buffer = readBlock(channel, 1) + return (buffer.get() + 256 * hb).toShort() + } + + @Throws(IOException::class) + private fun readTime(channel: SeekableByteChannel): Long { + val rx = readBlock(channel, 4) + return rx.long//rx[0] + 256 * rx[1] + 65536 * rx[2] + 256 * 65536 * rx[3]; + } + + // private void skip(int length) throws IOException { + // long n = stream.skip(length); + // if (n != length) { + // stream.skip(length - n); + // } + // } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassFileEnvelope.kt b/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassFileEnvelope.kt new file mode 100644 index 00000000..5d735378 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassFileEnvelope.kt @@ -0,0 +1,43 @@ +package inr.numass.data.legacy + +import hep.dataforge.io.envelopes.EnvelopeTag +import hep.dataforge.storage.filestorage.FileEnvelope +import inr.numass.NumassEnvelopeType +import java.io.IOException +import java.nio.ByteBuffer +import java.nio.channels.FileChannel +import java.nio.file.Path +import java.nio.file.StandardOpenOption.READ + +class NumassFileEnvelope private constructor(path: Path, readOnly: Boolean) : FileEnvelope(path, readOnly) { + + override fun buildTag(): EnvelopeTag { + return NumassEnvelopeType.LegacyTag() + } + + companion object { + + val LEGACY_START_SEQUENCE = byteArrayOf('#'.toByte(), '!'.toByte()) + val LEGACY_END_SEQUENCE = byteArrayOf('!'.toByte(), '#'.toByte(), '\r'.toByte(), '\n'.toByte()) + + fun open(path: Path, readOnly: Boolean): FileEnvelope { + // if (!Files.exists(path)) { + // throw new RuntimeException("File envelope does not exist"); + // } + + try { + FileChannel.open(path, READ).use { channel -> + val buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, 2) + return if (buffer.compareTo(ByteBuffer.wrap(LEGACY_START_SEQUENCE)) == 0) { + NumassFileEnvelope(path, readOnly) + } else { + FileEnvelope.open(path, readOnly) + } + } + } catch (e: IOException) { + throw RuntimeException("Failed to open file envelope", e) + } + + } + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt b/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt index 0c98c92b..b279f083 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt @@ -112,7 +112,7 @@ class NumassDataLoader( } override fun getStartTime(): Instant { - return meta.optValue("start_time").map { it.timeValue() }.orElseGet { super.getStartTime() } + return meta.optValue("start_time").map { it.timeValue() }.orElseGet { super.startTime } } override val isOpen: Boolean diff --git a/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt b/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt index c98c4b78..c4429f0e 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt @@ -1,5 +1,7 @@ package inr.numass.data.storage +import hep.dataforge.context.Context +import hep.dataforge.context.Global import hep.dataforge.io.envelopes.Envelope import hep.dataforge.meta.Meta import inr.numass.data.NumassProto @@ -30,14 +32,14 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint { throw RuntimeException("Failed to read point via protobuf") } - override fun getBlocks(): Stream { - return point.channelsList.stream() + override val blocks: Stream + get() = point.channelsList.stream() .flatMap { channel -> channel.blocksList.stream() .map { block -> ProtoBlock(channel.num.toInt(), block, meta) } .sorted(Comparator.comparing { it.startTime }) } - } + override fun getMeta(): Meta { return envelope.meta @@ -48,6 +50,10 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint { return ProtoNumassPoint(NumassFileEnvelope.open(path, true)) } + fun readFile(path: String, context: Context = Global): ProtoNumassPoint { + return readFile(context.io.getFile(path).absolutePath) + } + fun ofEpochNanos(nanos: Long): Instant { val seconds = Math.floorDiv(nanos, 1e9.toInt().toLong()) val reminder = (nanos % 1e9).toInt() @@ -56,32 +62,31 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint { } } -class ProtoBlock(val channel: Int, private val block: NumassProto.Point.Channel.Block, private val meta: Meta) : NumassBlock { +class ProtoBlock(override val channel: Int, private val block: NumassProto.Point.Channel.Block, private val meta: Meta) : NumassBlock { - override fun getStartTime(): Instant { - return ProtoNumassPoint.ofEpochNanos(block.time) - } + override val startTime: Instant + get() = ProtoNumassPoint.ofEpochNanos(block.time) - override fun getLength(): Duration { - return Duration.ofNanos((meta.getDouble("params.b_size") / meta.getDouble("params.sample_freq") * 1e9).toLong()) - } + override val length: Duration + get() = Duration.ofNanos((meta.getDouble("params.b_size") / meta.getDouble("params.sample_freq") * 1e9).toLong()) - override fun getEvents(): Stream { - val blockTime = startTime - if (block.hasEvents()) { + + override val events: Stream + get() = if (block.hasEvents()) { val events = block.events - return IntStream.range(0, events.timesCount).mapToObj { i -> NumassEvent(events.getAmplitudes(i).toShort(), blockTime, events.getTimes(i)) } + IntStream.range(0, events.timesCount).mapToObj { i -> NumassEvent(events.getAmplitudes(i).toShort(), events.getTimes(i), this) } } else { - return Stream.empty() + Stream.empty() } - } - override fun getFrames(): Stream { - val tickSize = Duration.ofNanos((1e9 / meta.getInt("params.sample_freq")).toLong()) - return block.framesList.stream().map { frame -> - val time = startTime.plusNanos(frame.time) - val data = frame.data.asReadOnlyByteBuffer() - NumassFrame(time, tickSize, data.asShortBuffer()) + + override val frames: Stream + get() { + val tickSize = Duration.ofNanos((1e9 / meta.getInt("params.sample_freq")).toLong()) + return block.framesList.stream().map { frame -> + val time = startTime.plusNanos(frame.time) + val data = frame.data.asReadOnlyByteBuffer() + NumassFrame(time, tickSize, data.asShortBuffer()) + } } - } } \ No newline at end of file diff --git a/numass-main/src/main/groovy/inr/numass/scripts/times/Histogram.groovy b/numass-main/src/main/groovy/inr/numass/scripts/times/Histogram.groovy index 9ad30d8a..26cdbdee 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/times/Histogram.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/times/Histogram.groovy @@ -28,7 +28,7 @@ new GrindShell(ctx).eval { def table = new SimpleHistogram([0d, 0d] as Double[], [2d, 100d] as Double[]) .fill(new TimeAnalyzer().getEventsWithDelay(point, Meta.empty()).map { - [it.value / 1000, it.key.chanel] as Double[] + [it.value / 1000, it.key.amp] as Double[] }).asTable() ColumnedDataWriter.writeTable(System.out, table, "hist") diff --git a/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java b/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java index 15ef9024..f1e07259 100644 --- a/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java +++ b/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java @@ -200,7 +200,7 @@ public class MonitorCorrectAction extends OneToOneAction { } private boolean isMonitorPoint(double monitor, Values point) { - return point.getValue(NumassPoint.HV_KEY).doubleValue() == monitor; + return point.getValue(NumassPoint.Companion.getHV_KEY()).doubleValue() == monitor; } private Instant getTime(Values point) { diff --git a/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java b/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java index 7bca6b31..b61ff31a 100644 --- a/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java +++ b/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java @@ -67,8 +67,8 @@ public class NMEventGenerator { // public void loadSpectrum(RawNMPoint point, int minChanel, int maxChanel) { // List shorts = new ArrayList<>(); // point.getEvents().stream() -// .filter((event) -> ((event.getChanel() > minChanel) && (event.getChanel() < maxChanel))) -// .forEach((event) -> shorts.add(event.getChanel())); +// .filter((event) -> ((event.getAmp() > minChanel) && (event.getAmp() < maxChanel))) +// .forEach((event) -> shorts.add(event.getAmp())); // double[] doubles = new double[shorts.size()]; // // for (int i = 0; i < shorts.size(); i++) { diff --git a/numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java b/numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java index 410d9e5c..09c59fb7 100644 --- a/numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java +++ b/numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java @@ -120,7 +120,7 @@ public class PileUpSimulator { //not counting double pileups if (generated.size() > 1) { double delay = (next.getTimeOffset() - lastRegisteredTime) / us; //time between events in microseconds - if (nextEventRegistered(next.getChanel(), delay)) { + if (nextEventRegistered(next.getAmp(), delay)) { //just register new event registered.add(next); lastRegisteredTime = next.getTimeOffset(); @@ -131,7 +131,7 @@ public class PileUpSimulator { doublePileup.incrementAndGet(); } else { //pileup event - short newChannel = pileupChannel(delay, next.getChanel(), next.getChanel()); + short newChannel = pileupChannel(delay, next.getAmp(), next.getAmp()); NumassEvent newEvent = new NumassEvent(newChannel, next.getBlockTime(), next.getTimeOffset()); //replace already registered event by event with new channel registered.remove(registered.size() - 1); diff --git a/numass-main/src/main/kotlin/inr/numass/scripts/Correlation.kt b/numass-main/src/main/kotlin/inr/numass/scripts/Correlation.kt index e4a81277..1cdc509d 100644 --- a/numass-main/src/main/kotlin/inr/numass/scripts/Correlation.kt +++ b/numass-main/src/main/kotlin/inr/numass/scripts/Correlation.kt @@ -32,7 +32,7 @@ private fun correlation(sequence: Stream): Double { val amplitudes: MutableList = ArrayList() val times: MutableList = ArrayList() sequence.forEach { - amplitudes.add(it.chanel.toDouble()) + amplitudes.add(it.amp.toDouble()) times.add(it.timeOffset.toDouble()) } diff --git a/numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt b/numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt new file mode 100644 index 00000000..352715de --- /dev/null +++ b/numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt @@ -0,0 +1,34 @@ +package inr.numass.scripts.tristan + +import hep.dataforge.meta.Meta +import hep.dataforge.tables.Table +import hep.dataforge.values.Values +import inr.numass.data.analyzers.NumassAnalyzer +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.NumassEvent +import inr.numass.data.api.NumassSet +import inr.numass.data.storage.ProtoNumassPoint +import java.util.stream.Stream + +fun main(args: Array) { + val analyzer = object : NumassAnalyzer{ + override fun analyze(block: NumassBlock, config: Meta): Values { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getEvents(block: NumassBlock, meta: Meta): Stream { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun analyzeSet(set: NumassSet, config: Meta): Table { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + } + + + val file = ProtoNumassPoint.readFile("D:\\Work\\Numass\\data\\TRISTAN_11_2017\\df\\gun_16_19.df ") + val events = Sequence { file.events.iterator() }.sortedBy { it.time } + + +} \ No newline at end of file