Analyzers for Tristan

This commit is contained in:
Alexander Nozik 2018-03-19 16:57:07 +03:00
parent cf3268244e
commit ae97c0be68
43 changed files with 932 additions and 1041 deletions

View File

@ -12,7 +12,6 @@ version = "0.2.0";
dependencies {
compile project(':numass-control')
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
}
task testDevice(dependsOn: classes, type: JavaExec) {
@ -22,28 +21,7 @@ task testDevice(dependsOn: classes, type: JavaExec) {
description "Start application in debug mode with default virtual port"
group "test"
}
buildscript {
ext.kotlin_version = '1.1.60'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
repositories {
mavenCentral()
}
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
//task testRun(dependsOn: classes, type: JavaExec) {
// main mainClass

View File

@ -33,13 +33,9 @@ internal fun createChannel(meta: Meta): PKT8Channel {
when (transformationType) {
"default", "hyperbolic" -> {
val coefs = meta.getValue("coefs").listValue()
val r0 = meta.getDouble("r0", 1000.0)!!
val r0 = meta.getDouble("r0", 1000.0)
return PKT8Channel(meta) { r ->
if (coefs == null) {
-1.0
} else {
coefs.indices.sumByDouble { coefs[it].doubleValue() * Math.pow(r0 / r, it.toDouble()) }
}
coefs?.indices?.sumByDouble { coefs[it].doubleValue() * Math.pow(r0 / r, it.toDouble()) } ?: -1.0
}
}
else -> throw RuntimeException("Unknown transformation type")
@ -50,13 +46,6 @@ internal fun createChannel(meta: Meta): PKT8Channel {
}
}
data class PKT8Result(val channel: String, val rawValue: Double, val temperature: Double) {
val rawString: String = String.format("%.2f", rawValue)
val temperatureString: String = String.format("%.2f", temperature)
}
/**
* Created by darksnake on 28-Sep-16.
*/

View File

@ -39,6 +39,7 @@ import hep.dataforge.utils.DateTimeUtils
import inr.numass.control.DeviceView
import inr.numass.control.StorageHelper
import java.time.Duration
import java.time.Instant
import java.util.*
@ -52,7 +53,7 @@ import java.util.*
RoleDef(name = Roles.VIEW_ROLE)
)
@ValueDef(name = "port", def = "virtual", info = "The name of the port for this PKT8")
@StateDef(ValueDef(name = "storing"))
@StateDef(value = ValueDef(name = "storing", info = "Define if this device is currently writes to storage"), writable = true)
@DeviceView(PKT8Display::class)
class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
/**
@ -103,9 +104,9 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
//read channel configuration
if (meta.hasMeta("channel")) {
for (node in getMeta().getMetaList("channel")) {
for (node in meta.getMetaList("channel")) {
val designation = node.getString("designation", "default")
this.channels.put(designation, createChannel(node))
this.channels[designation] = createChannel(node)
}
} else {
//set default channel configuration
@ -229,13 +230,18 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
}
private fun notifyChannelResult(designation: String, rawValue: Double) {
updateLogicalState("raw.$designation", rawValue)
val channel = channels[designation]
if (channel != null) {
collector.put(channel.name, channel.getTemperature(rawValue))
} else {
result(PKT8Result(designation, rawValue, -1.0))
val temperature = channel?.let {
val temp = it.getTemperature(rawValue)
updateLogicalState("temp.$designation", temp)
collector.put(it.name, temp)
temp
}
forEachConnection(PKT8ValueListener::class.java) {
it.report(PKT8Reading(channel?.name ?: designation, rawValue, temperature))
}
}
@ -313,5 +319,15 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
const val ABUF = "abuf"
private val CHANNEL_DESIGNATIONS = arrayOf("a", "b", "c", "d", "e", "f", "g", "h")
}
}
data class PKT8Reading(val channel: String, val rawValue: Double, val temperature: Double?) {
val rawString: String = String.format("%.2f", rawValue)
val temperatureString: String = String.format("%.2f", temperature)
}
interface PKT8ValueListener {
fun report(reading: PKT8Reading, time: Instant = Instant.now())
}

View File

@ -1,8 +1,6 @@
package inr.numass.control.cryotemp
import hep.dataforge.control.devices.Sensor
import hep.dataforge.control.measurements.Measurement
import hep.dataforge.control.measurements.MeasurementListener
import hep.dataforge.description.Descriptors
import hep.dataforge.fx.bindWindow
import hep.dataforge.fx.dfIconView
@ -15,7 +13,6 @@ import hep.dataforge.plots.PlotUtils
import hep.dataforge.plots.data.TimePlot
import hep.dataforge.plots.jfreechart.JFreeChartFrame
import inr.numass.control.DeviceDisplay
import javafx.application.Platform
import javafx.beans.binding.ListBinding
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
@ -33,11 +30,11 @@ import java.time.Instant
/**
* Created by darksnake on 30-May-17.
*/
class PKT8Display : DeviceDisplay<PKT8Device>(), MeasurementListener {
class PKT8Display : DeviceDisplay<PKT8Device>(), PKT8ValueListener {
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")
@ -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 onMeasurementResult(measurement: Measurement<*>, result: Any, time: Instant) {
if (result is PKT8Result) {
Platform.runLater {
lastUpdateProperty.set(time.toString())
table.put(result.channel, result);
}
override fun report(reading: PKT8Reading, time: Instant) {
runLater {
lastUpdateProperty.set(time.toString())
table[reading.channel] = reading;
}
}
@ -104,24 +109,24 @@ class PKT8Display : DeviceDisplay<PKT8Device>(), MeasurementListener {
}
}
center {
tableview<PKT8Result> {
items = object : ListBinding<PKT8Result>() {
tableview<PKT8Reading> {
items = object : ListBinding<PKT8Reading>() {
init {
bind(table)
}
override fun computeValue(): ObservableList<PKT8Result> {
override fun computeValue(): ObservableList<PKT8Reading> {
return FXCollections.observableArrayList(table.values).apply {
sortBy { it.channel }
}
}
}
column("Sensor", PKT8Result::channel);
column("Resistance", PKT8Result::rawValue).cellFormat {
column("Sensor", PKT8Reading::channel);
column("Resistance", PKT8Reading::rawValue).cellFormat {
text = String.format("%.2f", it)
}
column("Temperature", PKT8Result::temperature).cellFormat {
column("Temperature", PKT8Reading::temperature).cellFormat {
text = String.format("%.2f", it)
}
}

View File

@ -18,26 +18,29 @@ import java.util.function.Supplier
/**
* @author Alexander Nozik
*/
class PKT8VirtualPort(portName: String, meta: Meta) : VirtualPort(meta), Metoid {
class PKT8VirtualPort(private val portName: String, meta: Meta) : VirtualPort(meta), Metoid {
private val generator = Random()
init {
super.configureValue("id", portName)
}
// init {
// super.configureValue("id", portName)
// }
override fun getName(): String = portName
@Synchronized override fun evaluateRequest(request: String) {
when (request) {
"s" -> {
val letters = arrayOf("a", "b", "c", "d", "e", "f", "g", "h")
for (letter in letters) {
val channelMeta = MetaUtils.findNodeByValue(getMeta(), "channel", "letter", Value.of(letter)).orElse(Meta.empty())
val channelMeta = MetaUtils.findNodeByValue(meta, "channel", "letter", Value.of(letter)).orElse(Meta.empty())
val average: Double
val sigma: Double
if (channelMeta != null) {
average = channelMeta.getDouble("av", 1200.0)!!
sigma = channelMeta.getDouble("sigma", 50.0)!!
average = channelMeta.getDouble("av", 1200.0)
sigma = channelMeta.getDouble("sigma", 50.0)
} else {
average = 1200.0
sigma = 50.0
@ -56,7 +59,7 @@ class PKT8VirtualPort(portName: String, meta: Meta) : VirtualPort(meta), Metoid
}
"p" -> {
cancelByTag("measurement")
this.receivePhrase("Stopped")
planResponse("Stopped", Duration.ofMillis(50))
}
}
}

View File

@ -61,7 +61,7 @@ import java.util.function.Consumer
StateDef(ValueDef(name = "filamentStatus", info = "Filament status"))
)
@DeviceView(MspDisplay::class)
class MspDevice(context: Context, meta: Meta) : PortSensor<Values>(context, meta) {
class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
private var measurementDelegate: Consumer<MspResponse>? = null

View File

@ -5,13 +5,13 @@ import hep.dataforge.control.connections.Roles
import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.DeviceFactory
import hep.dataforge.exceptions.ControlException
import hep.dataforge.kodex.optional
import hep.dataforge.meta.Meta
import javafx.scene.Scene
import javafx.stage.Stage
import org.slf4j.LoggerFactory
import tornadofx.*
import java.util.*
import java.util.function.Predicate
/**
* Created by darksnake on 14-May-17.
@ -25,6 +25,7 @@ abstract class NumassControlApplication<in D : Device> : App() {
rootLogger.level = Level.INFO
device = setupDevice()
val controller = device.getDisplay()
device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE)
val scene = Scene(controller.view?.root ?: controller.getBoardView())
@ -47,12 +48,11 @@ abstract class NumassControlApplication<in D : Device> : App() {
protected abstract fun acceptDevice(meta: Meta): Boolean
private fun setupDevice(): D {
val config = getConfig(this)
.orElseGet { readResourceMeta("/config/devices.xml") }
val config = getConfig(this).optional.orElseGet { readResourceMeta("/config/devices.xml") }
val ctx = setupContext(config)
val deviceConfig = findDeviceMeta(config, Predicate<Meta> { this.acceptDevice(it) })
.orElseThrow { RuntimeException("Device configuration not found") }
val deviceConfig = findDeviceMeta(config) { this.acceptDevice(it) }
?: throw RuntimeException("Device configuration not found")
try {

View File

@ -8,6 +8,7 @@ import hep.dataforge.exceptions.StorageException
import hep.dataforge.fx.dfIcon
import hep.dataforge.io.MetaFileReader
import hep.dataforge.io.XMLMetaReader
import hep.dataforge.kodex.nullable
import hep.dataforge.meta.Meta
import hep.dataforge.storage.commons.StorageConnection
import hep.dataforge.storage.commons.StorageManager
@ -19,8 +20,6 @@ import java.io.IOException
import java.nio.file.Files
import java.nio.file.Paths
import java.text.ParseException
import java.util.*
import java.util.function.Predicate
/**
* Created by darksnake on 08-May-17.
@ -70,10 +69,10 @@ fun readResourceMeta(path: String): Meta {
}
fun getConfig(app: Application): Optional<Meta> {
fun getConfig(app: Application): Meta? {
val debugConfig = app.parameters.named["config.resource"]
if (debugConfig != null) {
return Optional.ofNullable(readResourceMeta(debugConfig))
return readResourceMeta(debugConfig)
}
var configFileName: String? = app.parameters.named["config"]
@ -84,25 +83,17 @@ fun getConfig(app: Application): Optional<Meta> {
}
val configFile = Paths.get(configFileName)
if (Files.exists(configFile)) {
try {
val config = MetaFileReader.read(configFile)
return Optional.of(config)
} catch (e: IOException) {
throw RuntimeException(e)
} catch (e: ParseException) {
throw RuntimeException(e)
}
return if (Files.exists(configFile)) {
MetaFileReader.read(configFile)
} else {
logger.warn("Configuration file not found")
return Optional.empty<Meta>()
null
}
}
fun findDeviceMeta(config: Meta, criterion: Predicate<Meta>): Optional<Meta> {
return config.getMetaList("device").stream().filter(criterion).findFirst().map { it -> it }
fun findDeviceMeta(config: Meta, criterion: (Meta) -> Boolean): Meta? {
return config.getMetaList("device").stream().filter(criterion).findFirst().nullable
}
fun setupContext(meta: Meta): Context {

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
// }
// }
}

View File

@ -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();
}
}

View 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"
}
}

View File

@ -24,7 +24,7 @@ import hep.dataforge.tables.TableFormat
import hep.dataforge.tables.TableFormatBuilder
import inr.numass.data.api.NumassBlock
import inr.numass.data.api.NumassEvent
import inr.numass.data.api.NumassPoint.HV_KEY
import inr.numass.data.api.NumassPoint.Companion.HV_KEY
import inr.numass.data.api.NumassSet
import inr.numass.data.api.SignalProcessor
import java.lang.IllegalArgumentException
@ -48,7 +48,7 @@ abstract class AbstractAnalyzer @JvmOverloads constructor(private val processor:
val loChannel = meta.getInt("window.lo", 0)
val upChannel = meta.getInt("window.up", Integer.MAX_VALUE)
var res = getAllEvents(block).filter { event ->
event.chanel.toInt() in loChannel..(upChannel - 1)
event.amp.toInt() in loChannel..(upChannel - 1)
}
if (meta.getBoolean("sort", false)) {
res = res.sorted(Comparator.comparing<NumassEvent, Long> { it.timeOffset })

View File

@ -24,7 +24,7 @@ import hep.dataforge.values.Values
import inr.numass.data.api.NumassBlock
import inr.numass.data.api.NumassEvent
import inr.numass.data.api.NumassPoint
import inr.numass.data.api.NumassPoint.HV_KEY
import inr.numass.data.api.NumassPoint.Companion.HV_KEY
import inr.numass.data.api.NumassSet
import java.util.*
import java.util.concurrent.atomic.AtomicLong
@ -56,7 +56,7 @@ interface NumassAnalyzer {
*/
fun analyzePoint(point: NumassPoint, config: Meta = Meta.empty()): Values {
val map = HashMap(analyze(point, config).asMap())
map.put(HV_KEY, Value.of(point.voltage))
map[HV_KEY] = Value.of(point.voltage)
return ValueMap(map)
}
@ -161,7 +161,7 @@ fun getAmplitudeSpectrum(events: Sequence<NumassEvent>, length: Double, config:
//optimized for fastest computation
val spectrum: MutableMap<Int, AtomicLong> = HashMap()
events.forEach { event ->
val channel = event.chanel.toInt()
val channel = event.amp.toInt()
spectrum.getOrPut(channel) {
AtomicLong(0)
}.incrementAndGet()

View File

@ -29,7 +29,7 @@ import hep.dataforge.values.Values
import inr.numass.data.api.NumassBlock
import inr.numass.data.api.NumassEvent
import inr.numass.data.api.NumassPoint
import inr.numass.data.api.NumassPoint.HV_KEY
import inr.numass.data.api.NumassPoint.Companion.HV_KEY
import inr.numass.data.api.SignalProcessor
import java.util.*
import java.util.concurrent.atomic.AtomicLong

View 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)
}
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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())
}

View File

@ -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"
}
}

View 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"
}
}

View File

@ -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>
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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);
// }
// }
}

View File

@ -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)
}
}
}
}

View File

@ -112,7 +112,7 @@ class NumassDataLoader(
}
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

View File

@ -1,5 +1,7 @@
package inr.numass.data.storage
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.io.envelopes.Envelope
import hep.dataforge.meta.Meta
import inr.numass.data.NumassProto
@ -30,14 +32,14 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint {
throw RuntimeException("Failed to read point via protobuf")
}
override fun getBlocks(): Stream<NumassBlock> {
return point.channelsList.stream()
override val blocks: Stream<NumassBlock>
get() = point.channelsList.stream()
.flatMap { channel ->
channel.blocksList.stream()
.map { block -> ProtoBlock(channel.num.toInt(), block, meta) }
.sorted(Comparator.comparing<ProtoBlock, Instant> { it.startTime })
}
}
override fun getMeta(): Meta {
return envelope.meta
@ -48,6 +50,10 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint {
return ProtoNumassPoint(NumassFileEnvelope.open(path, true))
}
fun readFile(path: String, context: Context = Global): ProtoNumassPoint {
return readFile(context.io.getFile(path).absolutePath)
}
fun ofEpochNanos(nanos: Long): Instant {
val seconds = Math.floorDiv(nanos, 1e9.toInt().toLong())
val reminder = (nanos % 1e9).toInt()
@ -56,32 +62,31 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint {
}
}
class ProtoBlock(val channel: Int, private val block: NumassProto.Point.Channel.Block, private val meta: Meta) : NumassBlock {
class ProtoBlock(override val channel: Int, private val block: NumassProto.Point.Channel.Block, private val meta: Meta) : NumassBlock {
override fun getStartTime(): Instant {
return ProtoNumassPoint.ofEpochNanos(block.time)
}
override val startTime: Instant
get() = ProtoNumassPoint.ofEpochNanos(block.time)
override fun getLength(): Duration {
return Duration.ofNanos((meta.getDouble("params.b_size") / meta.getDouble("params.sample_freq") * 1e9).toLong())
}
override val length: Duration
get() = Duration.ofNanos((meta.getDouble("params.b_size") / meta.getDouble("params.sample_freq") * 1e9).toLong())
override fun getEvents(): Stream<NumassEvent> {
val blockTime = startTime
if (block.hasEvents()) {
override val events: Stream<NumassEvent>
get() = if (block.hasEvents()) {
val events = block.events
return IntStream.range(0, events.timesCount).mapToObj { i -> NumassEvent(events.getAmplitudes(i).toShort(), blockTime, events.getTimes(i)) }
IntStream.range(0, events.timesCount).mapToObj { i -> NumassEvent(events.getAmplitudes(i).toShort(), events.getTimes(i), this) }
} else {
return Stream.empty()
Stream.empty()
}
}
override fun getFrames(): Stream<NumassFrame> {
val tickSize = Duration.ofNanos((1e9 / meta.getInt("params.sample_freq")).toLong())
return block.framesList.stream().map { frame ->
val time = startTime.plusNanos(frame.time)
val data = frame.data.asReadOnlyByteBuffer()
NumassFrame(time, tickSize, data.asShortBuffer())
override val frames: Stream<NumassFrame>
get() {
val tickSize = Duration.ofNanos((1e9 / meta.getInt("params.sample_freq")).toLong())
return block.framesList.stream().map { frame ->
val time = startTime.plusNanos(frame.time)
val data = frame.data.asReadOnlyByteBuffer()
NumassFrame(time, tickSize, data.asShortBuffer())
}
}
}
}

View File

@ -28,7 +28,7 @@ new GrindShell(ctx).eval {
def table = new SimpleHistogram([0d, 0d] as Double[], [2d, 100d] as Double[])
.fill(new TimeAnalyzer().getEventsWithDelay(point, Meta.empty()).map {
[it.value / 1000, it.key.chanel] as Double[]
[it.value / 1000, it.key.amp] as Double[]
}).asTable()
ColumnedDataWriter.writeTable(System.out, table, "hist")

View File

@ -200,7 +200,7 @@ public class MonitorCorrectAction extends OneToOneAction<Table, Table> {
}
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) {

View File

@ -67,8 +67,8 @@ public class NMEventGenerator {
// public void loadSpectrum(RawNMPoint point, int minChanel, int maxChanel) {
// List<Short> shorts = new ArrayList<>();
// point.getEvents().stream()
// .filter((event) -> ((event.getChanel() > minChanel) && (event.getChanel() < maxChanel)))
// .forEach((event) -> shorts.add(event.getChanel()));
// .filter((event) -> ((event.getAmp() > minChanel) && (event.getAmp() < maxChanel)))
// .forEach((event) -> shorts.add(event.getAmp()));
// double[] doubles = new double[shorts.size()];
//
// for (int i = 0; i < shorts.size(); i++) {

View File

@ -120,7 +120,7 @@ public class PileUpSimulator {
//not counting double pileups
if (generated.size() > 1) {
double delay = (next.getTimeOffset() - lastRegisteredTime) / us; //time between events in microseconds
if (nextEventRegistered(next.getChanel(), delay)) {
if (nextEventRegistered(next.getAmp(), delay)) {
//just register new event
registered.add(next);
lastRegisteredTime = next.getTimeOffset();
@ -131,7 +131,7 @@ public class PileUpSimulator {
doublePileup.incrementAndGet();
} else {
//pileup event
short newChannel = pileupChannel(delay, next.getChanel(), next.getChanel());
short newChannel = pileupChannel(delay, next.getAmp(), next.getAmp());
NumassEvent newEvent = new NumassEvent(newChannel, next.getBlockTime(), next.getTimeOffset());
//replace already registered event by event with new channel
registered.remove(registered.size() - 1);

View File

@ -32,7 +32,7 @@ private fun correlation(sequence: Stream<NumassEvent>): Double {
val amplitudes: MutableList<Double> = ArrayList()
val times: MutableList<Double> = ArrayList()
sequence.forEach {
amplitudes.add(it.chanel.toDouble())
amplitudes.add(it.amp.toDouble())
times.add(it.timeOffset.toDouble())
}

View File

@ -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 }
}