Analyzers for Tristan
This commit is contained in:
parent
cf3268244e
commit
ae97c0be68
@ -12,7 +12,6 @@ version = "0.2.0";
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':numass-control')
|
compile project(':numass-control')
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task testDevice(dependsOn: classes, type: JavaExec) {
|
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"
|
description "Start application in debug mode with default virtual port"
|
||||||
group "test"
|
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) {
|
//task testRun(dependsOn: classes, type: JavaExec) {
|
||||||
// main mainClass
|
// main mainClass
|
||||||
|
@ -33,13 +33,9 @@ internal fun createChannel(meta: Meta): PKT8Channel {
|
|||||||
when (transformationType) {
|
when (transformationType) {
|
||||||
"default", "hyperbolic" -> {
|
"default", "hyperbolic" -> {
|
||||||
val coefs = meta.getValue("coefs").listValue()
|
val coefs = meta.getValue("coefs").listValue()
|
||||||
val r0 = meta.getDouble("r0", 1000.0)!!
|
val r0 = meta.getDouble("r0", 1000.0)
|
||||||
return PKT8Channel(meta) { r ->
|
return PKT8Channel(meta) { r ->
|
||||||
if (coefs == null) {
|
coefs?.indices?.sumByDouble { coefs[it].doubleValue() * Math.pow(r0 / r, it.toDouble()) } ?: -1.0
|
||||||
-1.0
|
|
||||||
} else {
|
|
||||||
coefs.indices.sumByDouble { coefs[it].doubleValue() * Math.pow(r0 / r, it.toDouble()) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> throw RuntimeException("Unknown transformation type")
|
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.
|
* Created by darksnake on 28-Sep-16.
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +39,7 @@ import hep.dataforge.utils.DateTimeUtils
|
|||||||
import inr.numass.control.DeviceView
|
import inr.numass.control.DeviceView
|
||||||
import inr.numass.control.StorageHelper
|
import inr.numass.control.StorageHelper
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ import java.util.*
|
|||||||
RoleDef(name = Roles.VIEW_ROLE)
|
RoleDef(name = Roles.VIEW_ROLE)
|
||||||
)
|
)
|
||||||
@ValueDef(name = "port", def = "virtual", info = "The name of the port for this PKT8")
|
@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)
|
@DeviceView(PKT8Display::class)
|
||||||
class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
|
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
|
//read channel configuration
|
||||||
if (meta.hasMeta("channel")) {
|
if (meta.hasMeta("channel")) {
|
||||||
for (node in getMeta().getMetaList("channel")) {
|
for (node in meta.getMetaList("channel")) {
|
||||||
val designation = node.getString("designation", "default")
|
val designation = node.getString("designation", "default")
|
||||||
this.channels.put(designation, createChannel(node))
|
this.channels[designation] = createChannel(node)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//set default channel configuration
|
//set default channel configuration
|
||||||
@ -229,13 +230,18 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyChannelResult(designation: String, rawValue: Double) {
|
private fun notifyChannelResult(designation: String, rawValue: Double) {
|
||||||
|
updateLogicalState("raw.$designation", rawValue)
|
||||||
|
|
||||||
val channel = channels[designation]
|
val channel = channels[designation]
|
||||||
|
|
||||||
if (channel != null) {
|
val temperature = channel?.let {
|
||||||
collector.put(channel.name, channel.getTemperature(rawValue))
|
val temp = it.getTemperature(rawValue)
|
||||||
} else {
|
updateLogicalState("temp.$designation", temp)
|
||||||
result(PKT8Result(designation, rawValue, -1.0))
|
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"
|
const val ABUF = "abuf"
|
||||||
private val CHANNEL_DESIGNATIONS = arrayOf("a", "b", "c", "d", "e", "f", "g", "h")
|
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())
|
||||||
}
|
}
|
@ -1,8 +1,6 @@
|
|||||||
package inr.numass.control.cryotemp
|
package inr.numass.control.cryotemp
|
||||||
|
|
||||||
import hep.dataforge.control.devices.Sensor
|
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.description.Descriptors
|
||||||
import hep.dataforge.fx.bindWindow
|
import hep.dataforge.fx.bindWindow
|
||||||
import hep.dataforge.fx.dfIconView
|
import hep.dataforge.fx.dfIconView
|
||||||
@ -15,7 +13,6 @@ import hep.dataforge.plots.PlotUtils
|
|||||||
import hep.dataforge.plots.data.TimePlot
|
import hep.dataforge.plots.data.TimePlot
|
||||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||||
import inr.numass.control.DeviceDisplay
|
import inr.numass.control.DeviceDisplay
|
||||||
import javafx.application.Platform
|
|
||||||
import javafx.beans.binding.ListBinding
|
import javafx.beans.binding.ListBinding
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.collections.FXCollections
|
import javafx.collections.FXCollections
|
||||||
@ -33,11 +30,11 @@ import java.time.Instant
|
|||||||
/**
|
/**
|
||||||
* Created by darksnake on 30-May-17.
|
* Created by darksnake on 30-May-17.
|
||||||
*/
|
*/
|
||||||
class PKT8Display : DeviceDisplay<PKT8Device>(), MeasurementListener {
|
class PKT8Display : DeviceDisplay<PKT8Device>(), PKT8ValueListener {
|
||||||
|
|
||||||
override fun buildView(device: PKT8Device) = CryoView()
|
override fun buildView(device: PKT8Device) = CryoView()
|
||||||
|
|
||||||
internal val table = FXCollections.observableHashMap<String, PKT8Result>()
|
internal val table = FXCollections.observableHashMap<String, PKT8Reading>()
|
||||||
val lastUpdateProperty = SimpleObjectProperty<String>("NEVER")
|
val lastUpdateProperty = SimpleObjectProperty<String>("NEVER")
|
||||||
|
|
||||||
|
|
||||||
@ -47,16 +44,24 @@ class PKT8Display : DeviceDisplay<PKT8Device>(), 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 report(reading: PKT8Reading, time: Instant) {
|
||||||
|
runLater {
|
||||||
override fun onMeasurementResult(measurement: Measurement<*>, result: Any, time: Instant) {
|
lastUpdateProperty.set(time.toString())
|
||||||
if (result is PKT8Result) {
|
table[reading.channel] = reading;
|
||||||
Platform.runLater {
|
|
||||||
lastUpdateProperty.set(time.toString())
|
|
||||||
table.put(result.channel, result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,24 +109,24 @@ class PKT8Display : DeviceDisplay<PKT8Device>(), MeasurementListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
center {
|
center {
|
||||||
tableview<PKT8Result> {
|
tableview<PKT8Reading> {
|
||||||
items = object : ListBinding<PKT8Result>() {
|
items = object : ListBinding<PKT8Reading>() {
|
||||||
init {
|
init {
|
||||||
bind(table)
|
bind(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun computeValue(): ObservableList<PKT8Result> {
|
override fun computeValue(): ObservableList<PKT8Reading> {
|
||||||
return FXCollections.observableArrayList(table.values).apply {
|
return FXCollections.observableArrayList(table.values).apply {
|
||||||
sortBy { it.channel }
|
sortBy { it.channel }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
column("Sensor", PKT8Result::channel);
|
column("Sensor", PKT8Reading::channel);
|
||||||
column("Resistance", PKT8Result::rawValue).cellFormat {
|
column("Resistance", PKT8Reading::rawValue).cellFormat {
|
||||||
text = String.format("%.2f", it)
|
text = String.format("%.2f", it)
|
||||||
}
|
}
|
||||||
column("Temperature", PKT8Result::temperature).cellFormat {
|
column("Temperature", PKT8Reading::temperature).cellFormat {
|
||||||
text = String.format("%.2f", it)
|
text = String.format("%.2f", it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,26 +18,29 @@ import java.util.function.Supplier
|
|||||||
/**
|
/**
|
||||||
* @author Alexander Nozik
|
* @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()
|
private val generator = Random()
|
||||||
|
|
||||||
init {
|
// init {
|
||||||
super.configureValue("id", portName)
|
// super.configureValue("id", portName)
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
override fun getName(): String = portName
|
||||||
|
|
||||||
|
|
||||||
@Synchronized override fun evaluateRequest(request: String) {
|
@Synchronized override fun evaluateRequest(request: String) {
|
||||||
when (request) {
|
when (request) {
|
||||||
"s" -> {
|
"s" -> {
|
||||||
val letters = arrayOf("a", "b", "c", "d", "e", "f", "g", "h")
|
val letters = arrayOf("a", "b", "c", "d", "e", "f", "g", "h")
|
||||||
for (letter in letters) {
|
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 average: Double
|
||||||
val sigma: Double
|
val sigma: Double
|
||||||
if (channelMeta != null) {
|
if (channelMeta != null) {
|
||||||
average = channelMeta.getDouble("av", 1200.0)!!
|
average = channelMeta.getDouble("av", 1200.0)
|
||||||
sigma = channelMeta.getDouble("sigma", 50.0)!!
|
sigma = channelMeta.getDouble("sigma", 50.0)
|
||||||
} else {
|
} else {
|
||||||
average = 1200.0
|
average = 1200.0
|
||||||
sigma = 50.0
|
sigma = 50.0
|
||||||
@ -56,7 +59,7 @@ class PKT8VirtualPort(portName: String, meta: Meta) : VirtualPort(meta), Metoid
|
|||||||
}
|
}
|
||||||
"p" -> {
|
"p" -> {
|
||||||
cancelByTag("measurement")
|
cancelByTag("measurement")
|
||||||
this.receivePhrase("Stopped")
|
planResponse("Stopped", Duration.ofMillis(50))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ import java.util.function.Consumer
|
|||||||
StateDef(ValueDef(name = "filamentStatus", info = "Filament status"))
|
StateDef(ValueDef(name = "filamentStatus", info = "Filament status"))
|
||||||
)
|
)
|
||||||
@DeviceView(MspDisplay::class)
|
@DeviceView(MspDisplay::class)
|
||||||
class MspDevice(context: Context, meta: Meta) : PortSensor<Values>(context, meta) {
|
class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
|
||||||
|
|
||||||
private var measurementDelegate: Consumer<MspResponse>? = null
|
private var measurementDelegate: Consumer<MspResponse>? = null
|
||||||
|
|
||||||
|
@ -5,13 +5,13 @@ import hep.dataforge.control.connections.Roles
|
|||||||
import hep.dataforge.control.devices.Device
|
import hep.dataforge.control.devices.Device
|
||||||
import hep.dataforge.control.devices.DeviceFactory
|
import hep.dataforge.control.devices.DeviceFactory
|
||||||
import hep.dataforge.exceptions.ControlException
|
import hep.dataforge.exceptions.ControlException
|
||||||
|
import hep.dataforge.kodex.optional
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import javafx.scene.Scene
|
import javafx.scene.Scene
|
||||||
import javafx.stage.Stage
|
import javafx.stage.Stage
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.function.Predicate
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by darksnake on 14-May-17.
|
* Created by darksnake on 14-May-17.
|
||||||
@ -25,6 +25,7 @@ abstract class NumassControlApplication<in D : Device> : App() {
|
|||||||
rootLogger.level = Level.INFO
|
rootLogger.level = Level.INFO
|
||||||
|
|
||||||
device = setupDevice()
|
device = setupDevice()
|
||||||
|
|
||||||
val controller = device.getDisplay()
|
val controller = device.getDisplay()
|
||||||
device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE)
|
device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE)
|
||||||
val scene = Scene(controller.view?.root ?: controller.getBoardView())
|
val scene = Scene(controller.view?.root ?: controller.getBoardView())
|
||||||
@ -47,12 +48,11 @@ abstract class NumassControlApplication<in D : Device> : App() {
|
|||||||
protected abstract fun acceptDevice(meta: Meta): Boolean
|
protected abstract fun acceptDevice(meta: Meta): Boolean
|
||||||
|
|
||||||
private fun setupDevice(): D {
|
private fun setupDevice(): D {
|
||||||
val config = getConfig(this)
|
val config = getConfig(this).optional.orElseGet { readResourceMeta("/config/devices.xml") }
|
||||||
.orElseGet { readResourceMeta("/config/devices.xml") }
|
|
||||||
|
|
||||||
val ctx = setupContext(config)
|
val ctx = setupContext(config)
|
||||||
val deviceConfig = findDeviceMeta(config, Predicate<Meta> { this.acceptDevice(it) })
|
val deviceConfig = findDeviceMeta(config) { this.acceptDevice(it) }
|
||||||
.orElseThrow { RuntimeException("Device configuration not found") }
|
?: throw RuntimeException("Device configuration not found")
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -8,6 +8,7 @@ import hep.dataforge.exceptions.StorageException
|
|||||||
import hep.dataforge.fx.dfIcon
|
import hep.dataforge.fx.dfIcon
|
||||||
import hep.dataforge.io.MetaFileReader
|
import hep.dataforge.io.MetaFileReader
|
||||||
import hep.dataforge.io.XMLMetaReader
|
import hep.dataforge.io.XMLMetaReader
|
||||||
|
import hep.dataforge.kodex.nullable
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.storage.commons.StorageConnection
|
import hep.dataforge.storage.commons.StorageConnection
|
||||||
import hep.dataforge.storage.commons.StorageManager
|
import hep.dataforge.storage.commons.StorageManager
|
||||||
@ -19,8 +20,6 @@ import java.io.IOException
|
|||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.util.*
|
|
||||||
import java.util.function.Predicate
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by darksnake on 08-May-17.
|
* Created by darksnake on 08-May-17.
|
||||||
@ -70,10 +69,10 @@ fun readResourceMeta(path: String): Meta {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getConfig(app: Application): Optional<Meta> {
|
fun getConfig(app: Application): Meta? {
|
||||||
val debugConfig = app.parameters.named["config.resource"]
|
val debugConfig = app.parameters.named["config.resource"]
|
||||||
if (debugConfig != null) {
|
if (debugConfig != null) {
|
||||||
return Optional.ofNullable(readResourceMeta(debugConfig))
|
return readResourceMeta(debugConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
var configFileName: String? = app.parameters.named["config"]
|
var configFileName: String? = app.parameters.named["config"]
|
||||||
@ -84,25 +83,17 @@ fun getConfig(app: Application): Optional<Meta> {
|
|||||||
}
|
}
|
||||||
val configFile = Paths.get(configFileName)
|
val configFile = Paths.get(configFileName)
|
||||||
|
|
||||||
if (Files.exists(configFile)) {
|
return if (Files.exists(configFile)) {
|
||||||
try {
|
MetaFileReader.read(configFile)
|
||||||
val config = MetaFileReader.read(configFile)
|
|
||||||
return Optional.of(config)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Configuration file not found")
|
logger.warn("Configuration file not found")
|
||||||
return Optional.empty<Meta>()
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun findDeviceMeta(config: Meta, criterion: Predicate<Meta>): Optional<Meta> {
|
fun findDeviceMeta(config: Meta, criterion: (Meta) -> Boolean): Meta? {
|
||||||
return config.getMetaList("device").stream().filter(criterion).findFirst().map { it -> it }
|
return config.getMetaList("device").stream().filter(criterion).findFirst().nullable
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setupContext(meta: Meta): Context {
|
fun setupContext(meta: Meta): Context {
|
||||||
|
@ -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<Value> 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<Value> 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<String> listComponents() {
|
|
||||||
return Stream.concat(super.listComponents(), Stream.of(X_VALUE_KEY, Y_VALUE_KEY, POINT_LENGTH_NAME)).distinct();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<NumassBlock> blocks = new TreeSet<>(Comparator.comparing(NumassBlock::getStartTime));
|
|
||||||
|
|
||||||
public MetaBlock(NumassBlock... blocks) {
|
|
||||||
this.blocks.addAll(Arrays.asList(blocks));
|
|
||||||
}
|
|
||||||
|
|
||||||
public MetaBlock(Collection<NumassBlock> 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<NumassEvent> getEvents() {
|
|
||||||
return blocks.stream()
|
|
||||||
.sorted(Comparator.comparing(NumassBlock::getStartTime))
|
|
||||||
.flatMap(NumassBlock::getEvents);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<NumassFrame> getFrames() {
|
|
||||||
return blocks.stream()
|
|
||||||
.sorted(Comparator.comparing(NumassBlock::getStartTime))
|
|
||||||
.flatMap(NumassBlock::getFrames);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
* <p>
|
|
||||||
* 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<NumassEvent> getEvents();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream of frames. Could be empty
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Stream<NumassFrame> getFrames();
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<NumassBlock> 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
|
|
||||||
* <p>
|
|
||||||
* 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/
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
default Stream<NumassEvent> getEvents() {
|
|
||||||
return getBlocks().flatMap(NumassBlock::getEvents);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all frames in all blocks as a single sequence
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
default Stream<NumassFrame> getFrames() {
|
|
||||||
return getBlocks().flatMap(NumassBlock::getFrames);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <a href="mailto:altavir@gmail.com">Alexander Nozik</a>
|
|
||||||
*/
|
|
||||||
public interface NumassSet extends Named, Metoid, Iterable<NumassPoint>, Provider {
|
|
||||||
String DESCRIPTION_KEY = "info";
|
|
||||||
String NUMASS_POINT_PROVIDER_KEY = "point";
|
|
||||||
|
|
||||||
Stream<NumassPoint> getPoints();
|
|
||||||
|
|
||||||
// default String getDescription() {
|
|
||||||
// return getMeta().getString(DESCRIPTION_KEY, "");
|
|
||||||
// }
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
default Iterator<NumassPoint> 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<NumassPoint> optPoint(double voltage) {
|
|
||||||
return getPoints().filter(it -> it.getVoltage() == voltage).findFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List all points with given voltage
|
|
||||||
*
|
|
||||||
* @param voltage
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
default List<NumassPoint> getPoints(double voltage) {
|
|
||||||
return getPoints().filter(it -> it.getVoltage() == voltage).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides(NUMASS_POINT_PROVIDER_KEY)
|
|
||||||
default Optional<NumassPoint> optPoint(String voltage) {
|
|
||||||
return optPoint(Double.parseDouble(voltage));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
default String defaultTarget() {
|
|
||||||
return NUMASS_POINT_PROVIDER_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ProvidesNames(NUMASS_POINT_PROVIDER_KEY)
|
|
||||||
default Stream<String> listPoints() {
|
|
||||||
return getPoints().map(it -> Double.toString(it.getVoltage()));
|
|
||||||
}
|
|
||||||
|
|
||||||
default Optional<Table> getHvData() {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<NumassEvent> analyze(NumassFrame frame);
|
|
||||||
}
|
|
@ -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<NumassEvent> events;
|
|
||||||
|
|
||||||
public SimpleBlock(Instant startTime, Duration length, List<NumassEvent> 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<NumassEvent> getEvents() {
|
|
||||||
return events.stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<NumassFrame> getFrames() {
|
|
||||||
return Stream.empty();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<NumassBlock> blocks;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Input blocks must be sorted
|
|
||||||
* @param voltage
|
|
||||||
* @param blocks
|
|
||||||
*/
|
|
||||||
public SimpleNumassPoint(double voltage, Collection<? extends NumassBlock> 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<? extends NumassBlock> blocks) {
|
|
||||||
super(meta);
|
|
||||||
this.blocks = new ArrayList<>(blocks);
|
|
||||||
this.blocks.sort(Comparator.comparing(NumassBlock::getStartTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<NumassBlock> getBlocks() {
|
|
||||||
return blocks.stream();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<NumassEvent> 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<NumassPoint> getPoints() {
|
|
||||||
try (SeekableByteChannel channel = Files.newByteChannel(path, READ)) {
|
|
||||||
|
|
||||||
//int lab = readBlock(channel,1).get();
|
|
||||||
int lab;
|
|
||||||
List<NumassPoint> 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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
102
numass-core/src/main/kotlin/inr/numass/data/SpectrumAdapter.kt
Normal file
102
numass-core/src/main/kotlin/inr/numass/data/SpectrumAdapter.kt
Normal file
@ -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<Double> { 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<Value> {
|
||||||
|
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<String> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ import hep.dataforge.tables.TableFormat
|
|||||||
import hep.dataforge.tables.TableFormatBuilder
|
import hep.dataforge.tables.TableFormatBuilder
|
||||||
import inr.numass.data.api.NumassBlock
|
import inr.numass.data.api.NumassBlock
|
||||||
import inr.numass.data.api.NumassEvent
|
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.NumassSet
|
||||||
import inr.numass.data.api.SignalProcessor
|
import inr.numass.data.api.SignalProcessor
|
||||||
import java.lang.IllegalArgumentException
|
import java.lang.IllegalArgumentException
|
||||||
@ -48,7 +48,7 @@ abstract class AbstractAnalyzer @JvmOverloads constructor(private val processor:
|
|||||||
val loChannel = meta.getInt("window.lo", 0)
|
val loChannel = meta.getInt("window.lo", 0)
|
||||||
val upChannel = meta.getInt("window.up", Integer.MAX_VALUE)
|
val upChannel = meta.getInt("window.up", Integer.MAX_VALUE)
|
||||||
var res = getAllEvents(block).filter { event ->
|
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)) {
|
if (meta.getBoolean("sort", false)) {
|
||||||
res = res.sorted(Comparator.comparing<NumassEvent, Long> { it.timeOffset })
|
res = res.sorted(Comparator.comparing<NumassEvent, Long> { it.timeOffset })
|
||||||
|
@ -24,7 +24,7 @@ import hep.dataforge.values.Values
|
|||||||
import inr.numass.data.api.NumassBlock
|
import inr.numass.data.api.NumassBlock
|
||||||
import inr.numass.data.api.NumassEvent
|
import inr.numass.data.api.NumassEvent
|
||||||
import inr.numass.data.api.NumassPoint
|
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 inr.numass.data.api.NumassSet
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
@ -56,7 +56,7 @@ interface NumassAnalyzer {
|
|||||||
*/
|
*/
|
||||||
fun analyzePoint(point: NumassPoint, config: Meta = Meta.empty()): Values {
|
fun analyzePoint(point: NumassPoint, config: Meta = Meta.empty()): Values {
|
||||||
val map = HashMap(analyze(point, config).asMap())
|
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)
|
return ValueMap(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ fun getAmplitudeSpectrum(events: Sequence<NumassEvent>, length: Double, config:
|
|||||||
//optimized for fastest computation
|
//optimized for fastest computation
|
||||||
val spectrum: MutableMap<Int, AtomicLong> = HashMap()
|
val spectrum: MutableMap<Int, AtomicLong> = HashMap()
|
||||||
events.forEach { event ->
|
events.forEach { event ->
|
||||||
val channel = event.chanel.toInt()
|
val channel = event.amp.toInt()
|
||||||
spectrum.getOrPut(channel) {
|
spectrum.getOrPut(channel) {
|
||||||
AtomicLong(0)
|
AtomicLong(0)
|
||||||
}.incrementAndGet()
|
}.incrementAndGet()
|
||||||
|
@ -29,7 +29,7 @@ import hep.dataforge.values.Values
|
|||||||
import inr.numass.data.api.NumassBlock
|
import inr.numass.data.api.NumassBlock
|
||||||
import inr.numass.data.api.NumassEvent
|
import inr.numass.data.api.NumassEvent
|
||||||
import inr.numass.data.api.NumassPoint
|
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 inr.numass.data.api.SignalProcessor
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
38
numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt
Normal file
38
numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt
Normal file
@ -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<NumassBlock, Instant>{ 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<NumassEvent>
|
||||||
|
get() = blocks.stream()
|
||||||
|
.sorted(Comparator.comparing<NumassBlock, Instant>{ it.startTime })
|
||||||
|
.flatMap{ it.events }
|
||||||
|
|
||||||
|
override val frames: Stream<NumassFrame>
|
||||||
|
get() = blocks.stream()
|
||||||
|
.sorted(Comparator.comparing<NumassBlock, Instant>{ it.startTime })
|
||||||
|
.flatMap{ it.frames }
|
||||||
|
|
||||||
|
constructor(vararg blocks: NumassBlock) {
|
||||||
|
this.blocks.addAll(Arrays.asList(*blocks))
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(blocks: Collection<NumassBlock>) {
|
||||||
|
this.blocks.addAll(blocks)
|
||||||
|
}
|
||||||
|
}
|
@ -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<NumassEvent>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream of frames. Could be empty
|
||||||
|
*/
|
||||||
|
val frames: Stream<NumassFrame>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DEFAULT_CHANNEL: NumassChannel = -1
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
|
||||||
|
}
|
@ -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())
|
||||||
|
}
|
@ -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<NumassBlock>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<Instant>{ 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<Long>{ 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<NumassEvent>
|
||||||
|
get() = blocks.flatMap{ it.events }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all frames in all blocks as a single sequence
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
override val frames: Stream<NumassFrame>
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
93
numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt
Normal file
93
numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt
Normal file
@ -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<NumassPoint>, Provider {
|
||||||
|
|
||||||
|
val points: Stream<NumassPoint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<Instant>{ it.timeValue() }.orElseGet { firstPoint.startTime }
|
||||||
|
|
||||||
|
val hvData: Optional<Table>
|
||||||
|
get() = Optional.empty()
|
||||||
|
|
||||||
|
// default String getDescription() {
|
||||||
|
// return getMeta().getString(DESCRIPTION_KEY, "");
|
||||||
|
// }
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<NumassPoint> {
|
||||||
|
return points.iterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find first point with given voltage
|
||||||
|
*
|
||||||
|
* @param voltage
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun optPoint(voltage: Double): Optional<NumassPoint> {
|
||||||
|
return points.filter { it -> it.voltage == voltage }.findFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all points with given voltage
|
||||||
|
*
|
||||||
|
* @param voltage
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun getPoints(voltage: Double): List<NumassPoint> {
|
||||||
|
return points.filter { it -> it.voltage == voltage }.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides(NUMASS_POINT_PROVIDER_KEY)
|
||||||
|
fun optPoint(voltage: String): Optional<NumassPoint> {
|
||||||
|
return optPoint(java.lang.Double.parseDouble(voltage))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun defaultTarget(): String {
|
||||||
|
return NUMASS_POINT_PROVIDER_KEY
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProvidesNames(NUMASS_POINT_PROVIDER_KEY)
|
||||||
|
fun listPoints(): Stream<String> {
|
||||||
|
return points.map { it -> java.lang.Double.toString(it.voltage) }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DESCRIPTION_KEY = "info"
|
||||||
|
const val NUMASS_POINT_PROVIDER_KEY = "point"
|
||||||
|
}
|
||||||
|
}
|
@ -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<NumassEvent>
|
||||||
|
}
|
@ -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<NumassEvent>) : NumassBlock, Serializable {
|
||||||
|
|
||||||
|
override val frames: Stream<NumassFrame> = Stream.empty()
|
||||||
|
|
||||||
|
override val events: Stream<NumassEvent>
|
||||||
|
get() = eventList.stream()
|
||||||
|
|
||||||
|
}
|
@ -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<NumassBlock>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input blocks must be sorted
|
||||||
|
* @param voltage
|
||||||
|
* @param blocks
|
||||||
|
*/
|
||||||
|
constructor(voltage: Double, blocks: Collection<NumassBlock>) : super(MetaBuilder("point").setValue(NumassPoint.HV_KEY, voltage)) {
|
||||||
|
this.blockList = blocks.sortedBy { it.startTime }
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(meta: Meta, blocks: Collection<NumassBlock>) : super(meta) {
|
||||||
|
this.blockList = blocks.sortedBy { it.startTime }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val blocks: Stream<NumassBlock>
|
||||||
|
get() = blockList.stream()
|
||||||
|
}
|
@ -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<NumassPoint>
|
||||||
|
get() = try {
|
||||||
|
Files.newByteChannel(path, READ).use { channel ->
|
||||||
|
var lab: Int
|
||||||
|
val points = ArrayList<NumassPoint>()
|
||||||
|
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<NumassEvent>()
|
||||||
|
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<NumassBlock>(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);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -112,7 +112,7 @@ class NumassDataLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getStartTime(): Instant {
|
override fun getStartTime(): Instant {
|
||||||
return meta.optValue("start_time").map<Instant> { it.timeValue() }.orElseGet { super.getStartTime() }
|
return meta.optValue("start_time").map<Instant> { it.timeValue() }.orElseGet { super.startTime }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isOpen: Boolean
|
override val isOpen: Boolean
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package inr.numass.data.storage
|
package inr.numass.data.storage
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.io.envelopes.Envelope
|
import hep.dataforge.io.envelopes.Envelope
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import inr.numass.data.NumassProto
|
import inr.numass.data.NumassProto
|
||||||
@ -30,14 +32,14 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint {
|
|||||||
throw RuntimeException("Failed to read point via protobuf")
|
throw RuntimeException("Failed to read point via protobuf")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getBlocks(): Stream<NumassBlock> {
|
override val blocks: Stream<NumassBlock>
|
||||||
return point.channelsList.stream()
|
get() = point.channelsList.stream()
|
||||||
.flatMap { channel ->
|
.flatMap { channel ->
|
||||||
channel.blocksList.stream()
|
channel.blocksList.stream()
|
||||||
.map { block -> ProtoBlock(channel.num.toInt(), block, meta) }
|
.map { block -> ProtoBlock(channel.num.toInt(), block, meta) }
|
||||||
.sorted(Comparator.comparing<ProtoBlock, Instant> { it.startTime })
|
.sorted(Comparator.comparing<ProtoBlock, Instant> { it.startTime })
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMeta(): Meta {
|
override fun getMeta(): Meta {
|
||||||
return envelope.meta
|
return envelope.meta
|
||||||
@ -48,6 +50,10 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint {
|
|||||||
return ProtoNumassPoint(NumassFileEnvelope.open(path, true))
|
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 {
|
fun ofEpochNanos(nanos: Long): Instant {
|
||||||
val seconds = Math.floorDiv(nanos, 1e9.toInt().toLong())
|
val seconds = Math.floorDiv(nanos, 1e9.toInt().toLong())
|
||||||
val reminder = (nanos % 1e9).toInt()
|
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 {
|
override val startTime: Instant
|
||||||
return ProtoNumassPoint.ofEpochNanos(block.time)
|
get() = ProtoNumassPoint.ofEpochNanos(block.time)
|
||||||
}
|
|
||||||
|
|
||||||
override fun getLength(): Duration {
|
override val length: Duration
|
||||||
return Duration.ofNanos((meta.getDouble("params.b_size") / meta.getDouble("params.sample_freq") * 1e9).toLong())
|
get() = Duration.ofNanos((meta.getDouble("params.b_size") / meta.getDouble("params.sample_freq") * 1e9).toLong())
|
||||||
}
|
|
||||||
|
|
||||||
override fun getEvents(): Stream<NumassEvent> {
|
|
||||||
val blockTime = startTime
|
override val events: Stream<NumassEvent>
|
||||||
if (block.hasEvents()) {
|
get() = if (block.hasEvents()) {
|
||||||
val events = block.events
|
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 {
|
} else {
|
||||||
return Stream.empty()
|
Stream.empty()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFrames(): Stream<NumassFrame> {
|
|
||||||
val tickSize = Duration.ofNanos((1e9 / meta.getInt("params.sample_freq")).toLong())
|
override val frames: Stream<NumassFrame>
|
||||||
return block.framesList.stream().map { frame ->
|
get() {
|
||||||
val time = startTime.plusNanos(frame.time)
|
val tickSize = Duration.ofNanos((1e9 / meta.getInt("params.sample_freq")).toLong())
|
||||||
val data = frame.data.asReadOnlyByteBuffer()
|
return block.framesList.stream().map { frame ->
|
||||||
NumassFrame(time, tickSize, data.asShortBuffer())
|
val time = startTime.plusNanos(frame.time)
|
||||||
|
val data = frame.data.asReadOnlyByteBuffer()
|
||||||
|
NumassFrame(time, tickSize, data.asShortBuffer())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ new GrindShell(ctx).eval {
|
|||||||
|
|
||||||
def table = new SimpleHistogram([0d, 0d] as Double[], [2d, 100d] as Double[])
|
def table = new SimpleHistogram([0d, 0d] as Double[], [2d, 100d] as Double[])
|
||||||
.fill(new TimeAnalyzer().getEventsWithDelay(point, Meta.empty()).map {
|
.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()
|
}).asTable()
|
||||||
|
|
||||||
ColumnedDataWriter.writeTable(System.out, table, "hist")
|
ColumnedDataWriter.writeTable(System.out, table, "hist")
|
||||||
|
@ -200,7 +200,7 @@ public class MonitorCorrectAction extends OneToOneAction<Table, Table> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMonitorPoint(double monitor, Values point) {
|
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) {
|
private Instant getTime(Values point) {
|
||||||
|
@ -67,8 +67,8 @@ public class NMEventGenerator {
|
|||||||
// public void loadSpectrum(RawNMPoint point, int minChanel, int maxChanel) {
|
// public void loadSpectrum(RawNMPoint point, int minChanel, int maxChanel) {
|
||||||
// List<Short> shorts = new ArrayList<>();
|
// List<Short> shorts = new ArrayList<>();
|
||||||
// point.getEvents().stream()
|
// point.getEvents().stream()
|
||||||
// .filter((event) -> ((event.getChanel() > minChanel) && (event.getChanel() < maxChanel)))
|
// .filter((event) -> ((event.getAmp() > minChanel) && (event.getAmp() < maxChanel)))
|
||||||
// .forEach((event) -> shorts.add(event.getChanel()));
|
// .forEach((event) -> shorts.add(event.getAmp()));
|
||||||
// double[] doubles = new double[shorts.size()];
|
// double[] doubles = new double[shorts.size()];
|
||||||
//
|
//
|
||||||
// for (int i = 0; i < shorts.size(); i++) {
|
// for (int i = 0; i < shorts.size(); i++) {
|
||||||
|
@ -120,7 +120,7 @@ public class PileUpSimulator {
|
|||||||
//not counting double pileups
|
//not counting double pileups
|
||||||
if (generated.size() > 1) {
|
if (generated.size() > 1) {
|
||||||
double delay = (next.getTimeOffset() - lastRegisteredTime) / us; //time between events in microseconds
|
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
|
//just register new event
|
||||||
registered.add(next);
|
registered.add(next);
|
||||||
lastRegisteredTime = next.getTimeOffset();
|
lastRegisteredTime = next.getTimeOffset();
|
||||||
@ -131,7 +131,7 @@ public class PileUpSimulator {
|
|||||||
doublePileup.incrementAndGet();
|
doublePileup.incrementAndGet();
|
||||||
} else {
|
} else {
|
||||||
//pileup event
|
//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());
|
NumassEvent newEvent = new NumassEvent(newChannel, next.getBlockTime(), next.getTimeOffset());
|
||||||
//replace already registered event by event with new channel
|
//replace already registered event by event with new channel
|
||||||
registered.remove(registered.size() - 1);
|
registered.remove(registered.size() - 1);
|
||||||
|
@ -32,7 +32,7 @@ private fun correlation(sequence: Stream<NumassEvent>): Double {
|
|||||||
val amplitudes: MutableList<Double> = ArrayList()
|
val amplitudes: MutableList<Double> = ArrayList()
|
||||||
val times: MutableList<Double> = ArrayList()
|
val times: MutableList<Double> = ArrayList()
|
||||||
sequence.forEach {
|
sequence.forEach {
|
||||||
amplitudes.add(it.chanel.toDouble())
|
amplitudes.add(it.amp.toDouble())
|
||||||
times.add(it.timeOffset.toDouble())
|
times.add(it.timeOffset.toDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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<String>) {
|
||||||
|
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<NumassEvent> {
|
||||||
|
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 }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user