From caf8897194ad26a0ffc68900dbc465b500607f7d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 20 Mar 2018 22:08:37 +0300 Subject: [PATCH] Building function servers --- .../kotlin/inr/numass/control/ServerApp.kt | 2 +- .../numass/control/cryotemp/PKT8Channel.kt | 6 +- .../inr/numass/control/cryotemp/PKT8Device.kt | 2 +- .../numass/control/cryotemp/PKT8Display.kt | 4 +- .../inr/numass/control/msp/MspDevice.kt | 4 +- .../inr/numass/control/msp/MspDisplay.kt | 2 +- .../control/readvac/VacCollectorDisplay.kt | 2 +- .../inr/numass/control/readvac/VacDisplay.kt | 7 +- .../kotlin/inr/numass/NumassEnvelopeType.kt | 4 +- .../kotlin/inr/numass/data/NumassDataUtils.kt | 51 ++- .../inr/numass/data/analyzers/TimeAnalyzer.kt | 2 +- .../kotlin/inr/numass/data/api/MetaBlock.kt | 14 +- .../kotlin/inr/numass/data/api/NumassBlock.kt | 68 +++- .../kotlin/inr/numass/data/api/NumassEvent.kt | 38 --- .../kotlin/inr/numass/data/api/NumassSet.kt | 6 +- .../kotlin/inr/numass/data/api/SimpleBlock.kt | 19 -- .../inr/numass/data/legacy/NumassDatFile.kt | 31 +- .../numass/data/storage/ClassicNumassPoint.kt | 73 ++--- .../numass/data/storage/NumassDataLoader.kt | 26 +- .../numass/data/storage/ProtoNumassPoint.kt | 14 +- .../inr/numass/scripts/SimulatePileup.groovy | 306 +++++++++--------- .../numass/scripts/times/TestAnalyzer.groovy | 2 +- .../numass/actions/MonitorCorrectAction.java | 2 +- .../inr/numass/utils/NMEventGenerator.java | 176 ---------- .../utils/NMEventGeneratorWithPulser.java | 56 ---- .../inr/numass/utils/PileUpSimulator.java | 156 --------- .../src/main/kotlin/inr/numass/NumassUtils.kt | 6 +- .../inr/numass/actions/MergeDataAction.kt | 2 +- .../inr/numass/actions/SummaryAction.kt | 2 +- .../main/kotlin/inr/numass/data/Generator.kt | 74 +++-- .../kotlin/inr/numass/data/PileUpSimulator.kt | 172 ++++++++++ .../kotlin/inr/numass/data/Visualization.kt | 56 ++++ .../main/kotlin/inr/numass/scripts/Bunches.kt | 4 +- .../numass/scripts/tristan/AnalyzeTristan.kt | 25 +- .../numass/tasks/NumassFitScanSummaryTask.kt | 4 +- .../inr/numass/tasks/NumassFitScanTask.kt | 5 +- .../inr/numass/tasks/NumassFitSummaryTask.kt | 2 +- .../inr/numass/viewer/NumassDataCache.kt | 16 +- 38 files changed, 637 insertions(+), 804 deletions(-) delete mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt delete mode 100644 numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt delete mode 100644 numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java delete mode 100644 numass-main/src/main/java/inr/numass/utils/NMEventGeneratorWithPulser.java delete mode 100644 numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java create mode 100644 numass-main/src/main/kotlin/inr/numass/data/PileUpSimulator.kt create mode 100644 numass-main/src/main/kotlin/inr/numass/data/Visualization.kt diff --git a/numass-control/control-room/src/main/kotlin/inr/numass/control/ServerApp.kt b/numass-control/control-room/src/main/kotlin/inr/numass/control/ServerApp.kt index 001aa6fe..9fca9d64 100644 --- a/numass-control/control-room/src/main/kotlin/inr/numass/control/ServerApp.kt +++ b/numass-control/control-room/src/main/kotlin/inr/numass/control/ServerApp.kt @@ -11,7 +11,7 @@ class ServerApp : App(BoardView::class) { override fun start(stage: Stage) { - getConfig(this@ServerApp).ifPresent { + getConfig(this@ServerApp)?.let { controller.configure(it) } diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt index 07ee24e7..207279d2 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Channel.kt @@ -49,7 +49,7 @@ internal fun createChannel(meta: Meta): PKT8Channel { /** * Created by darksnake on 28-Sep-16. */ -class PKT8Channel(private val _meta: Meta, private val func: (Double) -> Double) : Named, Metoid { +class PKT8Channel(override val meta: Meta, private val func: (Double) -> Double) : Named, Metoid { private val _name: String by meta.stringValue() @@ -57,10 +57,6 @@ class PKT8Channel(private val _meta: Meta, private val func: (Double) -> Double) return _name } - override fun getMeta(): Meta { - return _meta - } - fun description(): String { return meta.getString("description", "") } diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt index aa195d17..3cd46dae 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt @@ -85,7 +85,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) { val abuf: String by stringState(ABUF) - private val duration = Duration.parse(getMeta().getString("averagingDuration", "PT30S")) + private val duration = Duration.parse(meta.getString("averagingDuration", "PT30S")) private fun buildLoader(connection: StorageConnection): TableLoader { val storage = connection.storage diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt index 43f60755..0ce45362 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Display.kt @@ -176,7 +176,7 @@ class PKT8Display : DeviceDisplay(), PKT8ValueListener { } init { - if (device.getMeta().hasMeta("plotConfig")) { + if (device.meta.hasMeta("plotConfig")) { with(plotFrame.plots) { //configure(device.meta().getMeta("plotConfig")) TimePlot.setMaxItems(this, 1000) @@ -204,7 +204,7 @@ class PKT8Display : DeviceDisplay(), PKT8ValueListener { } else { device.channels.values.find { it.name == channelName }?.let { TimePlot(it.name).apply { - configure(it.getMeta()) + configure(it.meta) plotFrame.add(this) } } diff --git a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt index a0a59bae..a010f3d4 100644 --- a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt +++ b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDevice.kt @@ -74,7 +74,7 @@ class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) { val isFilamentOn: Boolean get() = getState("filamentOn").booleanValue() - private val averagingDuration: Duration = Duration.parse(getMeta().getString("averagingDuration", "PT30S")) + private val averagingDuration: Duration = Duration.parse(meta.getString("averagingDuration", "PT30S")) @Throws(ControlException::class) override fun init() { @@ -140,7 +140,7 @@ class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) { @Throws(MeasurementException::class) override fun createMeasurement(): PeakJumpMeasurement { - val measurementMeta = getMeta().getMeta("peakJump") + val measurementMeta = meta.getMeta("peakJump") val s = measurementMeta.getString("type", "peakJump") if (s == "peakJump") { val measurement = PeakJumpMeasurement(measurementMeta) diff --git a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt index db7cf2a7..a5e78760 100644 --- a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt +++ b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt @@ -71,7 +71,7 @@ class MspDisplay() : DeviceDisplay(), DeviceListener, NamedValueListe inner class MspView : View("Numass mass-spectrometer measurement") { - private val plotFrameMeta: Meta = device.getMeta().getMeta("plotConfig", device.meta) + private val plotFrameMeta: Meta = device.meta.getMeta("plotConfig", device.meta) private val plotFrame: PlotFrame by lazy { val basePlotConfig = MetaBuilder("plotFrame") diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDisplay.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDisplay.kt index 5875c6cd..335d5c64 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDisplay.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDisplay.kt @@ -68,7 +68,7 @@ class VacCollectorDisplay : DeviceDisplay() { private val plottables = TimePlottableGroup().apply { viewList.forEach { val plot = TimePlot(it.getTitle(), it.device.name) - plot.configure(it.device.getMeta()) + plot.configure(it.device.meta) add(plot) } setValue("thickness", 3) diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacDisplay.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacDisplay.kt index 05d6d168..ac7e3f63 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacDisplay.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacDisplay.kt @@ -6,7 +6,6 @@ package inr.numass.control.readvac import hep.dataforge.control.devices.Device -import hep.dataforge.control.devices.PortSensor.CONNECTED_STATE import hep.dataforge.control.devices.Sensor import hep.dataforge.control.measurements.Measurement import hep.dataforge.control.measurements.MeasurementListener @@ -78,7 +77,7 @@ open class VacDisplay : DeviceDisplay(), MeasurementListener { } fun getTitle(): String{ - return device.getMeta().getString("title", device.name); + return device.meta.getString("title", device.name); } inner class VacView : View("Numass vacuumeter ${getTitle()}") { @@ -123,7 +122,7 @@ open class VacDisplay : DeviceDisplay(), MeasurementListener { prefHeight = 60.0 alignment = Pos.CENTER_RIGHT textProperty().bind(valueProperty) - device.getMeta().optValue("color").ifPresent { colorValue -> textFill = Color.valueOf(colorValue.stringValue()) } + device.meta.optValue("color").ifPresent { colorValue -> textFill = Color.valueOf(colorValue.stringValue()) } style { fontSize = 24.pt fontWeight = FontWeight.BOLD @@ -136,7 +135,7 @@ open class VacDisplay : DeviceDisplay(), MeasurementListener { prefHeight = 60.0 prefWidth = 75.0 alignment = Pos.CENTER_LEFT - text = device.getMeta().getString("units", "mbar") + text = device.meta.getString("units", "mbar") style { fontSize = 24.pt } diff --git a/numass-core/src/main/kotlin/inr/numass/NumassEnvelopeType.kt b/numass-core/src/main/kotlin/inr/numass/NumassEnvelopeType.kt index 1df13314..1656afcd 100644 --- a/numass-core/src/main/kotlin/inr/numass/NumassEnvelopeType.kt +++ b/numass-core/src/main/kotlin/inr/numass/NumassEnvelopeType.kt @@ -2,8 +2,8 @@ package inr.numass import hep.dataforge.io.envelopes.* import hep.dataforge.values.Value -import inr.numass.data.legacy.NumassFileEnvelope.LEGACY_END_SEQUENCE -import inr.numass.data.legacy.NumassFileEnvelope.LEGACY_START_SEQUENCE +import inr.numass.data.legacy.NumassFileEnvelope.Companion.LEGACY_END_SEQUENCE +import inr.numass.data.legacy.NumassFileEnvelope.Companion.LEGACY_START_SEQUENCE import org.slf4j.LoggerFactory import java.io.IOException import java.nio.ByteBuffer diff --git a/numass-core/src/main/kotlin/inr/numass/data/NumassDataUtils.kt b/numass-core/src/main/kotlin/inr/numass/data/NumassDataUtils.kt index be21e448..38cc3320 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/NumassDataUtils.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/NumassDataUtils.kt @@ -1,17 +1,16 @@ package inr.numass.data import hep.dataforge.io.envelopes.Envelope +import hep.dataforge.kodex.nullable import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaBuilder -import inr.numass.data.api.NumassBlock -import inr.numass.data.api.NumassPoint -import inr.numass.data.api.NumassSet -import inr.numass.data.api.SimpleNumassPoint +import inr.numass.data.api.* import inr.numass.data.storage.ProtoBlock import java.io.InputStream import java.util.stream.Collectors import java.util.stream.Stream import java.util.zip.ZipInputStream +import kotlin.streams.asSequence /** * Created by darksnake on 30-Jan-17. @@ -19,16 +18,16 @@ import java.util.zip.ZipInputStream object NumassDataUtils { fun join(name: String, sets: Collection): NumassSet { return object : NumassSet { - override fun getPoints(): Stream { + override val points: Stream by lazy { val points = sets.stream().flatMap { it.points } .collect(Collectors.groupingBy { it.voltage }) - return points.entries.stream().map { entry -> SimpleNumassPoint(entry.key, entry.value) } + points.entries.stream().map { entry -> SimpleNumassPoint(entry.key, entry.value) } } - override fun getMeta(): Meta { + override val meta: Meta by lazy { val metaBuilder = MetaBuilder() sets.forEach { set -> metaBuilder.putNode(set.name, set.meta) } - return metaBuilder + metaBuilder } override fun getName(): String { @@ -52,9 +51,41 @@ val Envelope.dataStream: InputStream this.data.stream } -val NumassBlock.channel: Int +val NumassBlock.channel: Int? get() = if (this is ProtoBlock) { this.channel } else { - 0 + this.meta.optValue("channel").map { it.intValue() }.nullable } + + +fun NumassBlock.transformChain(transform: (NumassEvent, NumassEvent) -> Pair): NumassBlock { + return SimpleBlock(this.startTime, this.length, this.meta) { owner -> + this.events.asSequence() + .sortedBy { it.timeOffset } + .zipWithNext(transform).map { NumassEvent(it.first, it.second, owner) }.asIterable() + } +} + +fun NumassBlock.filterChain(condition: (NumassEvent, NumassEvent) -> Boolean): NumassBlock { + return SimpleBlock(this.startTime, this.length, this.meta) { owner -> + this.events.asSequence() + .sortedBy { it.timeOffset } + .zipWithNext().filter { condition.invoke(it.first, it.second) }.map { it.second }.asIterable() + } +} + +fun NumassBlock.filter(condition: (NumassEvent) -> Boolean): NumassBlock { + return SimpleBlock(this.startTime, this.length, this.meta) { owner -> + this.events.asSequence() + .filter(condition).asIterable() + } +} + +fun NumassBlock.transform(transform: (NumassEvent) -> OrphanNumassEvent): NumassBlock { + return SimpleBlock(this.startTime, this.length, this.meta) { owner -> + this.events.asSequence() + .map { transform(it).adopt(owner) } + .asIterable() + } +} \ No newline at end of file diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt index 2af3d4a3..42fbdc26 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt @@ -88,7 +88,7 @@ class TimeAnalyzer @JvmOverloads constructor(private val processor: SignalProces .reduce(null) { v1, v2 -> this.combineBlockResults(v1, v2) } val map = HashMap(res.asMap()) - map.put(HV_KEY, Value.of(point.voltage)) + map[HV_KEY] = Value.of(point.voltage) return ValueMap(map) } diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt b/numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt index 53ca2f99..fba2bd5a 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/api/MetaBlock.kt @@ -1,5 +1,6 @@ package inr.numass.data.api +import hep.dataforge.meta.Meta import java.time.Duration import java.time.Instant import java.util.* @@ -9,9 +10,14 @@ 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 { +class MetaBlock(blocks: Collection, override val meta: Meta = Meta.empty()) : NumassBlock { + private val blocks = TreeSet(Comparator.comparing{ it.startTime }) + init{ + this.blocks.addAll(blocks) + } + override val startTime: Instant get() = blocks.first().startTime @@ -28,11 +34,5 @@ class MetaBlock : NumassBlock { .sorted(Comparator.comparing{ it.startTime }) .flatMap{ it.frames } - constructor(vararg blocks: NumassBlock) { - this.blocks.addAll(Arrays.asList(*blocks)) - } - constructor(blocks: Collection) { - this.blocks.addAll(blocks) - } } diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt index ad822822..fb711ee6 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/api/NumassBlock.kt @@ -1,12 +1,33 @@ package inr.numass.data.api +import hep.dataforge.meta.Meta +import hep.dataforge.meta.Metoid +import inr.numass.data.channel +import kotlinx.coroutines.experimental.runBlocking +import java.io.Serializable import java.time.Duration import java.time.Instant import java.util.stream.Stream -typealias NumassChannel = Int +/** + * A single numass event with given amplitude and time. + * + * @author Darksnake + * @property amp the amplitude of the event + * @property timeOffset time in nanoseconds relative to block start + * @property owner an owner block for this event + * + */ +class NumassEvent(val amp: Short, val timeOffset: Long, val owner: NumassBlock) : Serializable { + val channel: Int? + get() = owner.channel + + val time: Instant + get() = owner.startTime.plusNanos(timeOffset) + +} /** @@ -15,13 +36,7 @@ typealias NumassChannel = Int * * Created by darksnake on 06-Jul-17. */ -interface NumassBlock { - - /** - * A channel - */ - val channel: NumassChannel - get() = DEFAULT_CHANNEL +interface NumassBlock : Metoid { /** * The absolute start time of the block @@ -42,8 +57,37 @@ interface NumassBlock { * Stream of frames. Could be empty */ val frames: Stream - - companion object { - val DEFAULT_CHANNEL: NumassChannel = -1 - } } + + +typealias OrphanNumassEvent = Pair + +inline fun OrphanNumassEvent.adopt(parent: NumassBlock): NumassEvent { + return NumassEvent(this.first, this.second, parent) +} + +val OrphanNumassEvent.timeOffset: Long + get() = this.second + +val OrphanNumassEvent.amp: Short + get() = this.first + + +/** + * 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, + override val meta: Meta = Meta.empty(), + producer: suspend (NumassBlock) -> Iterable) : NumassBlock, Serializable { + + private val eventList = runBlocking { producer(this@SimpleBlock).toList()} + + override val frames: Stream = Stream.empty() + + override val events: Stream + get() = eventList.stream() + +} \ No newline at end of file diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt deleted file mode 100644 index d5851918..00000000 --- a/numass-core/src/main/kotlin/inr/numass/data/api/NumassEvent.kt +++ /dev/null @@ -1,38 +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 - * @property amp the amplitude of the event - * @property blockTime - * @property timeOffset time in nanoseconds relative to block start - * - */ -class NumassEvent(val amp: Short, val timeOffset: Long, val block: NumassBlock? = null) : Serializable { - - val channel: NumassChannel? - get() = block?.channel - - val time: Instant - get() = (block?.startTime ?: Instant.EPOCH).plusNanos(timeOffset) - -} diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt b/numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt index c126141f..84d8a653 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/api/NumassSet.kt @@ -23,7 +23,7 @@ import java.util.stream.Stream */ interface NumassSet : Named, Metoid, Iterable, Provider { - val points: Stream + val points: Stream /** * Get the first point if it exists. Throw runtime exception otherwise. @@ -58,7 +58,7 @@ interface NumassSet : Named, Metoid, Iterable, Provider { * @param voltage * @return */ - fun optPoint(voltage: Double): Optional { + fun optPoint(voltage: Double): Optional { return points.filter { it -> it.voltage == voltage }.findFirst() } @@ -73,7 +73,7 @@ interface NumassSet : Named, Metoid, Iterable, Provider { } @Provides(NUMASS_POINT_PROVIDER_KEY) - fun optPoint(voltage: String): Optional { + fun optPoint(voltage: String): Optional { return optPoint(java.lang.Double.parseDouble(voltage)) } diff --git a/numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt b/numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt deleted file mode 100644 index 7a9f25d6..00000000 --- a/numass-core/src/main/kotlin/inr/numass/data/api/SimpleBlock.kt +++ /dev/null @@ -1,19 +0,0 @@ -package inr.numass.data.api - -import java.io.Serializable -import java.time.Duration -import java.time.Instant -import java.util.stream.Stream - -/** - * A simple in-memory implementation of block of events. No frames are allowed - * Created by darksnake on 08.07.2017. - */ -class SimpleBlock(override val startTime: Instant, override val length: Duration, private val eventList: List) : NumassBlock, Serializable { - - override val frames: Stream = Stream.empty() - - override val events: Stream - get() = eventList.stream() - -} diff --git a/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt b/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt index 6072ae42..b0e980ad 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/legacy/NumassDatFile.kt @@ -24,14 +24,13 @@ import java.util.stream.Stream */ class NumassDatFile @Throws(IOException::class) constructor(private val name: String, private val path: Path, meta: Meta) : NumassSet { - private val meta: Meta + override val meta: Meta private val hVdev: Double - get() = getMeta().getDouble("dat.hvDev", 2.468555393226049) + get() = meta.getDouble("dat.hvDev", 2.468555393226049) - override//int lab = readBlock(channel,1).get(); //TODO check point start - val points: Stream + override val points: Stream get() = try { Files.newByteChannel(path, READ).use { channel -> var lab: Int @@ -58,16 +57,12 @@ constructor(private val name: String, private val path: Path, meta: Meta) : Numa .build() } - override fun getMeta(): Meta { - return meta - } - override fun getName(): String { return name } private fun hasUset(): Boolean { - return getMeta().getBoolean("dat.uSet", true) + return meta.getBoolean("dat.uSet", true) } @Throws(IOException::class) @@ -127,10 +122,10 @@ constructor(private val name: String, private val path: Path, meta: Meta) : Numa if (phoneFlag) { timeDiv /= 20.0 - length = (length*20).toShort() + length = (length * 20).toShort() } - val events = ArrayList() + val events = ArrayList>() var lab = readBlock(channel, 1).get().toInt() while (lab == 0xBF) { @@ -161,13 +156,15 @@ constructor(private val name: String, private val path: Path, meta: Meta) : Numa val uRead = ending.getInt(39) val uSet: Double - if (!this.hasUset()) { - uSet = uRead.toDouble() / 10.0 / hVdev + uSet = if (!this.hasUset()) { + uRead.toDouble() / 10.0 / hVdev } else { - uSet = voltage / 10.0 + voltage / 10.0 } - val block = SimpleBlock(absoluteTime.toInstant(ZoneOffset.UTC), Duration.ofSeconds(length.toLong()), events) + val block = SimpleBlock(absoluteTime.toInstant(ZoneOffset.UTC), Duration.ofSeconds(length.toLong())) { parent -> + events.map { it.adopt(parent) } + } val pointMeta = MetaBuilder("point") .setValue(HV_KEY, uSet) @@ -192,7 +189,7 @@ constructor(private val name: String, private val path: Path, meta: Meta) : Numa } @Throws(IOException::class) - private fun readEvent(channel: SeekableByteChannel, b: Int, timeDiv: Double): NumassEvent { + private fun readEvent(channel: SeekableByteChannel, b: Int, timeDiv: Double): OrphanNumassEvent { val chanel: Short val time: Long @@ -219,7 +216,7 @@ constructor(private val name: String, private val path: Path, meta: Meta) : Numa else -> throw IOException("Event head expected") } - return NumassEvent(chanel, (time / timeDiv).toLong()) + return Pair(chanel, (time / timeDiv).toLong()) } @Throws(IOException::class) diff --git a/numass-core/src/main/kotlin/inr/numass/data/storage/ClassicNumassPoint.kt b/numass-core/src/main/kotlin/inr/numass/data/storage/ClassicNumassPoint.kt index 7ffacf8d..588e7432 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/storage/ClassicNumassPoint.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/storage/ClassicNumassPoint.kt @@ -22,55 +22,38 @@ import java.util.stream.StreamSupport */ class ClassicNumassPoint(private val envelope: Envelope) : NumassPoint { - override fun getBlocks(): Stream { - // double u = envelope.meta().getDouble("external_meta.HV1_value", 0); - val length: Long - if (envelope.meta.hasValue("external_meta.acquisition_time")) { - length = envelope.meta.getValue("external_meta.acquisition_time").longValue() - } else { - length = envelope.meta.getValue("acquisition_time").longValue() + override val blocks: Stream + get() { + val length: Long = if (envelope.meta.hasValue("external_meta.acquisition_time")) { + envelope.meta.getValue("external_meta.acquisition_time").longValue() + } else { + envelope.meta.getValue("acquisition_time").longValue() + } + return Stream.of(ClassicBlock(startTime, Duration.ofSeconds(length))) } - return Stream.of(ClassicBlock(startTime, Duration.ofSeconds(length))) - } - override fun getStartTime(): Instant { - return if (meta.hasValue("start_time")) { + override val startTime: Instant + get() = if (meta.hasValue("start_time")) { meta.getValue("start_time").timeValue() } else { Instant.EPOCH } - } - override fun getVoltage(): Double { - return meta.getDouble("external_meta.HV1_value", 0.0) - } + override val meta: Meta = envelope.meta - override fun getIndex(): Int { - return meta.getInt("external_meta.point_index", -1) - } + override val voltage: Double = meta.getDouble("external_meta.HV1_value", 0.0) + + override val index: Int = meta.getInt("external_meta.point_index", -1) - override fun getMeta(): Meta { - return envelope.meta - } //TODO split blocks using meta - private inner class ClassicBlock - // private final long blockOffset; + private inner class ClassicBlock( + override val startTime: Instant, + override val length: Duration, + override val meta: Meta = Meta.empty()) : NumassBlock, Iterable { - (private val startTime: Instant, private val length: Duration)// this.blockOffset = blockOffset; - : NumassBlock, Iterable { - - override fun getStartTime(): Instant { - return startTime - } - - override fun getLength(): Duration { - return length - } - - override fun getEvents(): Stream { - return StreamSupport.stream(this.spliterator(), false) - } + override val events: Stream + get() = StreamSupport.stream(this.spliterator(), false) override fun iterator(): Iterator { val timeCoef = envelope.meta.getDouble("time_coeff", 50.0) @@ -84,16 +67,16 @@ class ClassicNumassPoint(private val envelope: Envelope) : NumassPoint { override fun hasNext(): Boolean { try { - if (buffer.hasRemaining()) { - return true + return if (buffer.hasRemaining()) { + true } else { buffer.flip() val num = channel.read(buffer) if (num > 0) { buffer.flip() - return true + true } else { - return false + false } } } catch (e: IOException) { @@ -104,10 +87,10 @@ class ClassicNumassPoint(private val envelope: Envelope) : NumassPoint { } override fun next(): NumassEvent { - val channel = java.lang.Short.toUnsignedInt(buffer.short).toShort() + val amp = java.lang.Short.toUnsignedInt(buffer.short).toShort() val time = Integer.toUnsignedLong(buffer.int) val status = buffer.get() // status is ignored - return NumassEvent(channel, startTime, (time * timeCoef).toLong()) + return NumassEvent(amp, (time * timeCoef).toLong(), this@ClassicBlock) } } } catch (ex: IOException) { @@ -117,9 +100,7 @@ class ClassicNumassPoint(private val envelope: Envelope) : NumassPoint { } - override fun getFrames(): Stream { - return Stream.empty() - } + override val frames: Stream = Stream.empty() } companion object { diff --git a/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt b/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt index b279f083..f5dc9125 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/storage/NumassDataLoader.kt @@ -53,6 +53,8 @@ class NumassDataLoader( override var isReadOnly: Boolean = true ) : AbstractLoader(storage, name, meta), ObjectLoader, NumassSet, Provider { + override val meta: Meta = items[META_FRAGMENT_NAME]?.get()?.meta ?: Meta.empty() + private val hvEnvelope: Optional get() = Optional.ofNullable(items[HV_FRAGMENT_NAME]).map { it.get() } @@ -74,13 +76,8 @@ class NumassDataLoader( return items.keys } - override fun getMeta(): Meta { - return items[META_FRAGMENT_NAME]?.get()?.meta ?: Meta.empty() - - } - - override fun getHvData(): Optional { - return hvEnvelope.map { hvEnvelope -> + override val hvData: Optional
+ get() = hvEnvelope.map { hvEnvelope -> try { ColumnedDataReader(hvEnvelope.data.stream, "timestamp", "block", "value").toTable() } catch (ex: IOException) { @@ -89,11 +86,11 @@ class NumassDataLoader( } } - } - override fun getPoints(): Stream { - return pointEnvelopes.map { ClassicNumassPoint(it) } - } + override val points: Stream + get() { + return pointEnvelopes.map { ClassicNumassPoint(it) } + } override fun pull(fragmentName: String): Envelope { //PENDING read data to memory? @@ -111,9 +108,8 @@ class NumassDataLoader( throw TODO("Not supported yet.") } - override fun getStartTime(): Instant { - return meta.optValue("start_time").map { it.timeValue() }.orElseGet { super.startTime } - } + override val startTime: Instant = meta.optValue("start_time").map { it.timeValue() }.orElseGet { super.startTime } + override val isOpen: Boolean get() = true @@ -161,7 +157,7 @@ class NumassDataLoader( || fileName.startsWith(POINT_FRAGMENT_NAME)) }.forEach { file -> try { - items[FileStorage.entryName(file)] = Supplier{ NumassFileEnvelope.open(file, true) } + items[FileStorage.entryName(file)] = Supplier { NumassFileEnvelope.open(file, true) } } catch (ex: Exception) { LoggerFactory.getLogger(NumassDataLoader::class.java) .error("Can't load numass data directory " + FileStorage.entryName(directory), ex) diff --git a/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt b/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt index c4429f0e..fef9d952 100644 --- a/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt +++ b/numass-core/src/main/kotlin/inr/numass/data/storage/ProtoNumassPoint.kt @@ -3,6 +3,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.kodex.buildMeta import hep.dataforge.meta.Meta import inr.numass.data.NumassProto import inr.numass.data.api.NumassBlock @@ -36,14 +37,12 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint { get() = point.channelsList.stream() .flatMap { channel -> channel.blocksList.stream() - .map { block -> ProtoBlock(channel.num.toInt(), block, meta) } + .map { block -> ProtoBlock(channel.num.toInt(), block) } .sorted(Comparator.comparing { it.startTime }) } - override fun getMeta(): Meta { - return envelope.meta - } + override val meta: Meta =envelope.meta companion object { fun readFile(path: Path): ProtoNumassPoint { @@ -62,7 +61,12 @@ class ProtoNumassPoint(private val envelope: Envelope) : NumassPoint { } } -class ProtoBlock(override val channel: Int, private val block: NumassProto.Point.Channel.Block, private val meta: Meta) : NumassBlock { +class ProtoBlock(val channel: Int, private val block: NumassProto.Point.Channel.Block) : NumassBlock { + override val meta: Meta by lazy { + buildMeta{ + "channel" to channel + } + } override val startTime: Instant get() = ProtoNumassPoint.ofEpochNanos(block.time) diff --git a/numass-main/src/main/groovy/inr/numass/scripts/SimulatePileup.groovy b/numass-main/src/main/groovy/inr/numass/scripts/SimulatePileup.groovy index ce68a698..b8efe3c5 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/SimulatePileup.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/SimulatePileup.groovy @@ -1,155 +1,157 @@ -/* - * 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.scripts - -import hep.dataforge.grind.Grind -import hep.dataforge.values.Values -import inr.numass.NumassUtils -import inr.numass.data.api.NumassPoint -import inr.numass.data.storage.NumassDataLoader -import inr.numass.utils.NMEventGeneratorWithPulser -import inr.numass.utils.PileUpSimulator -import inr.numass.utils.UnderflowCorrection -import org.apache.commons.math3.random.JDKRandomGenerator - -rnd = new JDKRandomGenerator(); - -////Loading data -File dataDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_1\\set_28") -//File dataDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_2_wide\\set_7") -if (!dataDir.exists()) { - println "dataDir directory does not exist" -} -def data = NumassDataLoader.fromLocalDir(null, dataDir).getNMPoints() - -//File rootDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_1") -////File rootDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_2_wide") -////File rootDir = new File("D:\\Work\\Numass\\data\\2017_01\\Fill_2_wide") +///* +// * 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. +// */ // -//NumassStorage storage = NumassStorage.buildLocalNumassRoot(rootDir, true); +//package inr.numass.scripts // -//Collection data = NumassDataUtils.joinSpectra( -// StorageUtils.loaderStream(storage) -// .filter { it.key.matches("set_3.") } -// .map { -// println "loading ${it.key}" -// it.value +//import hep.dataforge.grind.Grind +//import hep.dataforge.values.Values +//import inr.numass.NumassUtils +//import inr.numass.data.api.NumassPoint +//import inr.numass.data.storage.NumassDataLoader +// +//import inr.numass.data.PileUpSimulator +//import inr.numass.utils.UnderflowCorrection +//import org.apache.commons.math3.random.JDKRandomGenerator +// +//rnd = new JDKRandomGenerator(); +// +//////Loading data +//File dataDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_1\\set_28") +////File dataDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_2_wide\\set_7") +//if (!dataDir.exists()) { +// println "dataDir directory does not exist" +//} +//def data = NumassDataLoader.fromLocalDir(null, dataDir).getNMPoints() +// +////File rootDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_1") +//////File rootDir = new File("D:\\Work\\Numass\\data\\2016_10\\Fill_2_wide") +//////File rootDir = new File("D:\\Work\\Numass\\data\\2017_01\\Fill_2_wide") +//// +////NumassStorage storage = NumassStorage.buildLocalNumassRoot(rootDir, true); +//// +////Collection data = NumassDataUtils.joinSpectra( +//// StorageUtils.loaderStream(storage) +//// .filter { it.key.matches("set_3.") } +//// .map { +//// println "loading ${it.key}" +//// it.value +//// } +////) +// +////Simulation process +//Map> res = [:] +// +//List generated = new ArrayList<>(); +//List registered = new ArrayList<>(); +//List firstIteration = new ArrayList<>(); +//List secondIteration = new ArrayList<>(); +//List pileup = new ArrayList<>(); +// +//lowerChannel = 400; +//upperChannel = 1800; +// +//PileUpSimulator buildSimulator(NumassPoint point, double cr, NumassPoint reference = null, boolean extrapolate = true, double scale = 1d) { +// def cfg = Grind.buildMeta(cr: cr) { +// pulser(mean: 3450, sigma: 86.45, freq: 66.43) +// } +// //NMEventGeneratorWithPulser generator = new NMEventGeneratorWithPulser(rnd, cfg) +// +// def generator = b +// +// if (extrapolate) { +// double[] chanels = new double[RawNMPoint.MAX_CHANEL]; +// double[] values = new double[RawNMPoint.MAX_CHANEL]; +// Values fitResult = new UnderflowCorrection().fitPoint(point, 400, 600, 1800, 20); +// +// def amp = fitResult.getDouble("amp") +// def sigma = fitResult.getDouble("expConst") +// if (sigma > 0) { +// +// for (int i = 0; i < upperChannel; i++) { +// chanels[i] = i; +// if (i < lowerChannel) { +// values[i] = point.getLength()*amp * Math.exp((i as double) / sigma) +// } else { +// values[i] = Math.max(0, point.getCount(i) - (reference == null ? 0 : reference.getCount(i)) as int); +// } // } -//) - -//Simulation process -Map> res = [:] - -List generated = new ArrayList<>(); -List registered = new ArrayList<>(); -List firstIteration = new ArrayList<>(); -List secondIteration = new ArrayList<>(); -List pileup = new ArrayList<>(); - -lowerChannel = 400; -upperChannel = 1800; - -PileUpSimulator buildSimulator(NumassPoint point, double cr, NumassPoint reference = null, boolean extrapolate = true, double scale = 1d) { - def cfg = Grind.buildMeta(cr: cr) { - pulser(mean: 3450, sigma: 86.45, freq: 66.43) - } - NMEventGeneratorWithPulser generator = new NMEventGeneratorWithPulser(rnd, cfg) - - if (extrapolate) { - double[] chanels = new double[RawNMPoint.MAX_CHANEL]; - double[] values = new double[RawNMPoint.MAX_CHANEL]; - Values fitResult = new UnderflowCorrection().fitPoint(point, 400, 600, 1800, 20); - - def amp = fitResult.getDouble("amp") - def sigma = fitResult.getDouble("expConst") - if (sigma > 0) { - - for (int i = 0; i < upperChannel; i++) { - chanels[i] = i; - if (i < lowerChannel) { - values[i] = point.getLength()*amp * Math.exp((i as double) / sigma) - } else { - values[i] = Math.max(0, point.getCount(i) - (reference == null ? 0 : reference.getCount(i)) as int); - } - } - generator.loadSpectrum(chanels, values) - } else { - generator.loadSpectrum(point, reference, lowerChannel, upperChannel); - } - } else { - generator.loadSpectrum(point, reference, lowerChannel, upperChannel); - } - - return new PileUpSimulator(point.length * scale, rnd, generator).withUset(point.voltage).generate(); -} - -double adjustCountRate(PileUpSimulator simulator, NumassPoint point) { - double generatedInChannel = simulator.generated().getCountInWindow(lowerChannel, upperChannel); - double registeredInChannel = simulator.registered().getCountInWindow(lowerChannel, upperChannel); - return (generatedInChannel / registeredInChannel) * (point.getCountInWindow(lowerChannel, upperChannel) / point.getLength()); -} - -data.forEach { point -> - double cr = NumassUtils.countRateWithDeadTime(point, lowerChannel, upperChannel, 6.55e-6); - - PileUpSimulator simulator = buildSimulator(point, cr); - - //second iteration to exclude pileup overlap - NumassPoint pileupPoint = simulator.pileup(); - firstIteration.add(simulator.registered()); - - //updating count rate - cr = adjustCountRate(simulator, point); - simulator = buildSimulator(point, cr, pileupPoint); - - pileupPoint = simulator.pileup(); - secondIteration.add(simulator.registered()); - - cr = adjustCountRate(simulator, point); - simulator = buildSimulator(point, cr, pileupPoint); - - generated.add(simulator.generated()); - registered.add(simulator.registered()); - pileup.add(simulator.pileup()); -} -res.put("original", data); -res.put("generated", generated); -res.put("registered", registered); -// res.put("firstIteration", new SimulatedPoint("firstIteration", firstIteration)); -// res.put("secondIteration", new SimulatedPoint("secondIteration", secondIteration)); -res.put("pileup", pileup); - -def keys = res.keySet(); - -//print spectra for selected point -double u = 16500d; - -List points = res.values().collect { it.find { it.voltage == u }.getMap(20, true) } - -println "\n Spectrum example for U = ${u}\n" - -print "channel\t" -println keys.join("\t") - -points.first().keySet().each { - print "${it}\t" - println points.collect { map -> map[it] }.join("\t") -} - -//printing count rate in window -print "U\tLength\t" -print keys.collect { it + "[total]" }.join("\t") + "\t" -print keys.collect { it + "[pulse]" }.join("\t") + "\t" -println keys.join("\t") - -for (int i = 0; i < data.size(); i++) { - print "${data.get(i).getVoltage()}\t" - print "${data.get(i).getLength()}\t" - print keys.collect { res[it].get(i).getTotalCount() }.join("\t") + "\t" - print keys.collect { res[it].get(i).getCountInWindow(3100, 3800) }.join("\t") + "\t" - println keys.collect { res[it].get(i).getCountInWindow(400, 3100) }.join("\t") -} +// generator.loadSpectrum(chanels, values) +// } else { +// generator.loadSpectrum(point, reference, lowerChannel, upperChannel); +// } +// } else { +// generator.loadSpectrum(point, reference, lowerChannel, upperChannel); +// } +// +// return new PileUpSimulator(point.length * scale, rnd, generator).withUset(point.voltage).generate(); +//} +// +//double adjustCountRate(PileUpSimulator simulator, NumassPoint point) { +// double generatedInChannel = simulator.generated().getCountInWindow(lowerChannel, upperChannel); +// double registeredInChannel = simulator.registered().getCountInWindow(lowerChannel, upperChannel); +// return (generatedInChannel / registeredInChannel) * (point.getCountInWindow(lowerChannel, upperChannel) / point.getLength()); +//} +// +//data.forEach { point -> +// double cr = NumassUtils.countRateWithDeadTime(point, lowerChannel, upperChannel, 6.55e-6); +// +// PileUpSimulator simulator = buildSimulator(point, cr); +// +// //second iteration to exclude pileup overlap +// NumassPoint pileupPoint = simulator.pileup(); +// firstIteration.add(simulator.registered()); +// +// //updating count rate +// cr = adjustCountRate(simulator, point); +// simulator = buildSimulator(point, cr, pileupPoint); +// +// pileupPoint = simulator.pileup(); +// secondIteration.add(simulator.registered()); +// +// cr = adjustCountRate(simulator, point); +// simulator = buildSimulator(point, cr, pileupPoint); +// +// generated.add(simulator.generated()); +// registered.add(simulator.registered()); +// pileup.add(simulator.pileup()); +//} +//res.put("original", data); +//res.put("generated", generated); +//res.put("registered", registered); +//// res.put("firstIteration", new SimulatedPoint("firstIteration", firstIteration)); +//// res.put("secondIteration", new SimulatedPoint("secondIteration", secondIteration)); +//res.put("pileup", pileup); +// +//def keys = res.keySet(); +// +////print spectra for selected point +//double u = 16500d; +// +//List points = res.values().collect { it.find { it.voltage == u }.getMap(20, true) } +// +//println "\n Spectrum example for U = ${u}\n" +// +//print "channel\t" +//println keys.join("\t") +// +//points.first().keySet().each { +// print "${it}\t" +// println points.collect { map -> map[it] }.join("\t") +//} +// +////printing count rate in window +//print "U\tLength\t" +//print keys.collect { it + "[total]" }.join("\t") + "\t" +//print keys.collect { it + "[pulse]" }.join("\t") + "\t" +//println keys.join("\t") +// +//for (int i = 0; i < data.size(); i++) { +// print "${data.get(i).getVoltage()}\t" +// print "${data.get(i).getLength()}\t" +// print keys.collect { res[it].get(i).getTotalCount() }.join("\t") + "\t" +// print keys.collect { res[it].get(i).getCountInWindow(3100, 3800) }.join("\t") + "\t" +// println keys.collect { res[it].get(i).getCountInWindow(400, 3100) }.join("\t") +//} diff --git a/numass-main/src/main/groovy/inr/numass/scripts/times/TestAnalyzer.groovy b/numass-main/src/main/groovy/inr/numass/scripts/times/TestAnalyzer.groovy index ea7ba249..aaff507a 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/times/TestAnalyzer.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/times/TestAnalyzer.groovy @@ -32,7 +32,7 @@ new GrindShell(ctx).eval { def blocks = (1..num).collect { - def chain = GeneratorKt.buildSimpleEventChain(cr, new JDKRandomGenerator(),{10000}) + def chain = GeneratorKt.generateEvents(cr, new JDKRandomGenerator(),{10000}) GeneratorKt.generateBlock(Instant.now().plusNanos(it * length), length, chain) } diff --git a/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java b/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java index f1e07259..15ef9024 100644 --- a/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java +++ b/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java @@ -200,7 +200,7 @@ public class MonitorCorrectAction extends OneToOneAction { } private boolean isMonitorPoint(double monitor, Values point) { - return point.getValue(NumassPoint.Companion.getHV_KEY()).doubleValue() == monitor; + return point.getValue(NumassPoint.HV_KEY).doubleValue() == monitor; } private Instant getTime(Values point) { diff --git a/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java b/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java deleted file mode 100644 index b61ff31a..00000000 --- a/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java +++ /dev/null @@ -1,176 +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.utils; - -import hep.dataforge.meta.Meta; -import hep.dataforge.tables.Table; -import inr.numass.data.api.NumassBlock; -import inr.numass.data.api.NumassEvent; -import inr.numass.data.api.SimpleBlock; -import org.apache.commons.math3.distribution.EnumeratedRealDistribution; -import org.apache.commons.math3.distribution.RealDistribution; -import org.apache.commons.math3.random.RandomGenerator; - -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; - -import static inr.numass.data.analyzers.NumassAnalyzer.COUNT_RATE_KEY; - -/** - * A generator for Numass events with given energy spectrum - * - * @author Darksnake - */ -@Deprecated -public class NMEventGenerator { - - protected final RandomGenerator rnd; - protected double cr; - protected RealDistribution distribution; - protected NumassEvent prevEvent; - - public NMEventGenerator(RandomGenerator rnd, double cr) { - this.cr = cr; - this.rnd = rnd; - } - - public NMEventGenerator(RandomGenerator rnd, Meta meta) { - this.cr = meta.getDouble("cr"); - this.rnd = rnd; - } - - public void setSpectrum(Table spectrum) { - double[] chanels = new double[spectrum.size()]; - double[] values = new double[spectrum.size()]; - for (int i = 0; i < spectrum.size(); i++) { - chanels[i] = spectrum.get("channel", i).doubleValue(); - values[i] = spectrum.get(COUNT_RATE_KEY, i).doubleValue(); - } - distribution = new EnumeratedRealDistribution(chanels, values); - } - -// public void loadSpectrum(RawNMPoint point, int minChanel, int maxChanel) { -// List shorts = new ArrayList<>(); -// point.getEvents().stream() -// .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++) { -// doubles[i] = shorts.get(i); -// } -// -// EmpiricalDistribution d = new EmpiricalDistribution(); -// d.load(doubles); -// -// distribution = d; -// } -// -// public void loadSpectrum(Map spectrum) { -// double[] chanels = new double[spectrum.size()]; -// double[] values = new double[spectrum.size()]; -// int i = 0; -// for (Map.Entry entry : spectrum.entrySet()) { -// chanels[i] = entry.getKey(); -// values[i] = entry.getValue(); -// } -// distribution = new EnumeratedRealDistribution(chanels, values); -// } -// -// public void loadSpectrum(double[] channels, double[] values) { -// distribution = new EnumeratedRealDistribution(channels, values); -// } -// -// public void loadSpectrum(NumassPoint point) { -// double[] chanels = new double[RawNMPoint.MAX_CHANEL]; -// double[] values = new double[RawNMPoint.MAX_CHANEL]; -// for (int i = 0; i < RawNMPoint.MAX_CHANEL; i++) { -// chanels[i] = i; -// values[i] = point.getCount(i); -// } -// distribution = new EnumeratedRealDistribution(chanels, values); -// } -// -// public void loadSpectrum(NumassPoint point, NumassPoint reference) { -// double[] chanels = new double[RawNMPoint.MAX_CHANEL]; -// double[] values = new double[RawNMPoint.MAX_CHANEL]; -// for (int i = 0; i < RawNMPoint.MAX_CHANEL; i++) { -// chanels[i] = i; -// values[i] = Math.max(0, point.getCount(i) - reference.getCount(i)); -// } -// distribution = new EnumeratedRealDistribution(chanels, values); -// } -// -// /** -// * @param point -// * @param reference -// * @param lower lower channel for spectrum generation -// * @param upper upper channel for spectrum generation -// */ -// public void loadSpectrum(NumassPoint point, NumassPoint reference, int lower, int upper) { -// double[] chanels = new double[RawNMPoint.MAX_CHANEL]; -// double[] values = new double[RawNMPoint.MAX_CHANEL]; -// for (int i = lower; i < upper; i++) { -// chanels[i] = i; -// values[i] = Math.max(0, point.getCount(i) - (reference == null ? 0 : reference.getCount(i))); -// } -// distribution = new EnumeratedRealDistribution(chanels, values); -// } - - protected short generateChannel() { - if (distribution != null) { - return (short) distribution.sample(); - } else { - return 1600; - } - } - - protected long generateDeltaTime() { - return (long) (nextExpDecay(1d / cr) * 1e9); - } - - - protected NumassEvent nextEvent(NumassEvent prev) { - if (prev == null) { - return new NumassEvent(generateChannel(), Instant.EPOCH, 0); - } else { - return new NumassEvent(generateChannel(), prev.getBlockTime(), prev.getTimeOffset() + generateDeltaTime()); - } - } - - -// @Override -// public synchronized NumassEvent get() { -// return prevEvent = nextEvent(prevEvent); -// } - - public NumassBlock generateBlock(Instant stsrt, long length) { - List events = new ArrayList<>(); - NumassEvent event = nextEvent(null); - while (event.getTimeOffset() < length) { - events.add(event); - event = nextEvent(event); - } - return new SimpleBlock(stsrt, Duration.ofNanos(length), events); - } - - private double nextExpDecay(double mean) { - return - mean * Math.log(1 - rnd.nextDouble()); - } - -} diff --git a/numass-main/src/main/java/inr/numass/utils/NMEventGeneratorWithPulser.java b/numass-main/src/main/java/inr/numass/utils/NMEventGeneratorWithPulser.java deleted file mode 100644 index 408047cd..00000000 --- a/numass-main/src/main/java/inr/numass/utils/NMEventGeneratorWithPulser.java +++ /dev/null @@ -1,56 +0,0 @@ -package inr.numass.utils; - -import hep.dataforge.meta.Meta; -import inr.numass.data.api.NumassEvent; -import org.apache.commons.math3.distribution.NormalDistribution; -import org.apache.commons.math3.distribution.RealDistribution; -import org.apache.commons.math3.random.RandomGenerator; - -/** - * Created by darksnake on 25-Nov-16. - */ -public class NMEventGeneratorWithPulser extends NMEventGenerator { - private RealDistribution pulserChanelDistribution; - private double pulserDist; - private NumassEvent pulserEvent; - private NumassEvent nextEvent; - - public NMEventGeneratorWithPulser(RandomGenerator rnd, Meta meta) { - super(rnd, meta); - pulserChanelDistribution = new NormalDistribution( - meta.getDouble("pulser.mean", 3450), - meta.getDouble("pulser.sigma", 86.45) - ); - pulserDist = 1d / meta.getDouble("pulser.freq", 66.43); - pulserEvent = generatePulserEvent(); - } - - public synchronized NumassEvent get() { - //expected next event - if (nextEvent == null) { - nextEvent = nextEvent(prevEvent); - } - //if pulser event is first, then leave next event as is and return pulser event - if (pulserEvent.getTimeOffset() < nextEvent.getTimeOffset()) { - NumassEvent res = pulserEvent; - pulserEvent = generatePulserEvent(); - return res; - } else { - //else return saved next event and generate next one - prevEvent = nextEvent; - nextEvent = nextEvent(prevEvent); - return prevEvent; - } - } - - private NumassEvent generatePulserEvent() { - short channel = (short) pulserChanelDistribution.sample(); - double time; - if (pulserEvent == null) { - time = rnd.nextDouble() * pulserDist * 1e9; - } else { - time = pulserEvent.getTimeOffset() + pulserDist*1e9; - } - return new NumassEvent(channel, (long) time); - } -} diff --git a/numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java b/numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java deleted file mode 100644 index 09c59fb7..00000000 --- a/numass-main/src/main/java/inr/numass/utils/PileUpSimulator.java +++ /dev/null @@ -1,156 +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.utils; - -import inr.numass.data.api.NumassBlock; -import inr.numass.data.api.NumassEvent; -import inr.numass.data.api.SimpleBlock; -import org.apache.commons.math3.random.RandomGenerator; - -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import static java.lang.Math.max; - -/** - * @author Alexander Nozik - */ -public class PileUpSimulator { - private final static double us = 1e-6;//microsecond - private final long pointLength; - private final RandomGenerator rnd; - private final List generated = new ArrayList<>(); - private final List pileup = new ArrayList<>(); - private final List registered = new ArrayList<>(); - private NMEventGenerator generator; - private double uSet = 0; - private AtomicInteger doublePileup = new AtomicInteger(0); - - - public PileUpSimulator(long length, RandomGenerator rnd, double countRate) { - this.rnd = rnd; - generator = new NMEventGenerator(rnd, countRate); - this.pointLength = length; - } - - public PileUpSimulator(long pointLength, NMEventGenerator generator) { - this.pointLength = pointLength; - this.generator = generator; - this.rnd = generator.rnd; - } - - public PileUpSimulator withUset(double uset) { - this.uSet = uset; - return this; - } - - public NumassBlock generated() { - return new SimpleBlock(Instant.EPOCH, Duration.ofNanos(pointLength), generated); - } - - public NumassBlock registered() { - return new SimpleBlock(Instant.EPOCH, Duration.ofNanos(pointLength), registered); - } - - public NumassBlock pileup() { - return new SimpleBlock(Instant.EPOCH, Duration.ofNanos(pointLength), pileup); - } - - /** - * The amplitude for pileup event - * - * @param x - * @return - */ - private short pileupChannel(double x, short prevChanel, short nextChanel) { - assert x > 0; - //эмпирическая формула для канала - double coef = max(0, 0.99078 + 0.05098 * x - 0.45775 * x * x + 0.10962 * x * x * x); - if (coef < 0 || coef > 1) { - throw new Error(); - } - - return (short) (prevChanel + coef * nextChanel); - } - - /** - * pileup probability - * - * @param delay - * @return - */ - private boolean pileup(double delay) { - double prob = 1d / (1d + Math.pow(delay / (2.5 + 0.2), 42.96)); - return random(prob); - } - - /** - * Probability for next event to register - * - * @param delay - * @return - */ - private boolean nextEventRegistered(short prevChanel, double delay) { - double average = 6.76102 - 4.31897E-4 * prevChanel + 7.88429E-8 * prevChanel * prevChanel + 0.2; - double prob = 1d - 1d / (1d + Math.pow(delay / average, 75.91)); - return random(prob); - } - - private boolean random(double prob) { - return rnd.nextDouble() <= prob; - } - - public synchronized PileUpSimulator generate() { - NumassEvent next = null; - double lastRegisteredTime = 0; // Time of DAQ closing - //flag that shows that previous event was pileup - boolean pileupFlag = false; - while (true) { - next = generator.nextEvent(next); - if (next.getTimeOffset() > pointLength) { - break; - } - generated.add(next); - //not counting double pileups - if (generated.size() > 1) { - double delay = (next.getTimeOffset() - lastRegisteredTime) / us; //time between events in microseconds - if (nextEventRegistered(next.getAmp(), delay)) { - //just register new event - registered.add(next); - lastRegisteredTime = next.getTimeOffset(); - pileupFlag = false; - } else if (pileup(delay)) { - if (pileupFlag) { - //increase double pileup stack - doublePileup.incrementAndGet(); - } else { - //pileup event - 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); - registered.add(newEvent); - pileup.add(newEvent); - //do not change DAQ close time - pileupFlag = true; // up the flag to avoid secondary pileup - } - } else { - // second event not registered, DAQ closed - pileupFlag = false; - } - } else { - //register first event - registered.add(next); - lastRegisteredTime = next.getTimeOffset(); - } - } - return this; - } - -} diff --git a/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt b/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt index bb250b26..3016955c 100644 --- a/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt +++ b/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt @@ -101,7 +101,7 @@ object NumassUtils { } fun wrap(obj: Markedup, meta: Meta = Meta.empty()): EnvelopeBuilder { - return wrap(obj,meta){SimpleMarkupRenderer(this).render(it.markup(meta))} + return wrap(obj, meta) { SimpleMarkupRenderer(this).render(it.markup(meta)) } } @@ -280,7 +280,7 @@ fun FitResult.display(context: Context, stage: String = "fit") { val func = { x: Double -> model.spectrum.value(x, parameters) } - val fit = XYFunctionPlot("fit",func) + val fit = XYFunctionPlot("fit", func) fit.density = 100 // ensuring all data points are calculated explicitly data.rows.map { dp -> Adapters.getXValue(adapter, dp).doubleValue() }.sorted().forEach { fit.calculateIn(it) } @@ -297,7 +297,7 @@ fun FitResult.display(context: Context, stage: String = "fit") { data.rows.forEach { val x = Adapters.getXValue(adapter, it).doubleValue() val y = Adapters.getYValue(adapter, it).doubleValue() - val err = Adapters.optYError(adapter,it).orElse(1.0) + val err = Adapters.optYError(adapter, it).orElse(1.0) residual += Adapters.buildXYDataPoint(x, (y - func(x)) / err, 1.0) } diff --git a/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt b/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt index 519666e2..025a5d0c 100644 --- a/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt +++ b/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt @@ -40,7 +40,7 @@ class MergeDataAction : ManyToOneAction() { private val parnames = arrayOf(NumassPoint.HV_KEY, NumassPoint.LENGTH_KEY, NumassAnalyzer.COUNT_KEY, NumassAnalyzer.COUNT_RATE_KEY, NumassAnalyzer.COUNT_RATE_ERROR_KEY) override fun buildGroups(context: Context, input: DataNode
, actionMeta: Meta): List> { - val meta = inputMeta(context, input.getMeta(), actionMeta) + val meta = inputMeta(context, input.meta, actionMeta) val groups: List> if (meta.hasValue("grouping.byValue")) { groups = super.buildGroups(context, input, actionMeta) diff --git a/numass-main/src/main/kotlin/inr/numass/actions/SummaryAction.kt b/numass-main/src/main/kotlin/inr/numass/actions/SummaryAction.kt index 88ce4dbc..356bbb5c 100644 --- a/numass-main/src/main/kotlin/inr/numass/actions/SummaryAction.kt +++ b/numass-main/src/main/kotlin/inr/numass/actions/SummaryAction.kt @@ -40,7 +40,7 @@ import java.util.* class SummaryAction : ManyToOneAction() { protected override fun buildGroups(context: Context, input: DataNode, actionMeta: Meta): List> { - val meta = inputMeta(context, input.getMeta(), actionMeta) + val meta = inputMeta(context, input.meta, actionMeta) val groups: List> if (meta.hasValue("grouping.byValue")) { groups = super.buildGroups(context, input, actionMeta) diff --git a/numass-main/src/main/kotlin/inr/numass/data/Generator.kt b/numass-main/src/main/kotlin/inr/numass/data/Generator.kt index fd69a995..182ac5ee 100644 --- a/numass-main/src/main/kotlin/inr/numass/data/Generator.kt +++ b/numass-main/src/main/kotlin/inr/numass/data/Generator.kt @@ -4,12 +4,14 @@ import hep.dataforge.maths.chain.Chain import hep.dataforge.maths.chain.MarkovChain import hep.dataforge.maths.chain.StatefulChain import hep.dataforge.stat.defaultGenerator -import inr.numass.data.api.NumassBlock -import inr.numass.data.api.NumassEvent -import inr.numass.data.api.SimpleBlock +import hep.dataforge.tables.Table +import inr.numass.data.analyzers.NumassAnalyzer.Companion.CHANNEL_KEY +import inr.numass.data.analyzers.NumassAnalyzer.Companion.COUNT_RATE_KEY +import inr.numass.data.api.* +import kotlinx.coroutines.experimental.channels.map import kotlinx.coroutines.experimental.channels.takeWhile import kotlinx.coroutines.experimental.channels.toList -import kotlinx.coroutines.experimental.runBlocking +import org.apache.commons.math3.distribution.EnumeratedRealDistribution import org.apache.commons.math3.random.RandomGenerator import java.time.Duration import java.time.Instant @@ -22,24 +24,50 @@ private fun RandomGenerator.nextDeltaTime(cr: Double): Long { return (nextExp(1.0 / cr) * 1e9).toLong() } -fun generateBlock(start: Instant, length: Long, chain: Chain): NumassBlock { - - val events = runBlocking { chain.channel.takeWhile { it.timeOffset < length }.toList()} - return SimpleBlock(start, Duration.ofNanos(length), events) +fun generateBlock(start: Instant, length: Long, chain: Chain): NumassBlock { + return SimpleBlock(start, Duration.ofNanos(length)) { parent -> + chain.channel.map { it.adopt(parent) }.takeWhile { it.timeOffset < length }.toList() + } } -internal val defaultAmplitudeGenerator: RandomGenerator.(NumassEvent?, Long) -> Short = { _, _ -> ((nextDouble() + 2.0) * 100).toShort() } +internal val defaultAmplitudeGenerator: RandomGenerator.(OrphanNumassEvent?, Long) -> Short = { _, _ -> ((nextDouble() + 2.0) * 100).toShort() } -fun buildSimpleEventChain( +/** + * Generate an event chain with fixed count rate + * @param cr = count rate in Hz + * @param rnd = random number generator + * @param amp amplitude generator for the chain. The receiver is rng, first argument is the previous event and second argument + * is the delay between the next event. The result is the amplitude in channels + */ +fun generateEvents( cr: Double, rnd: RandomGenerator = defaultGenerator, - amp: RandomGenerator.(NumassEvent?, Long) -> Short = defaultAmplitudeGenerator): Chain { - return MarkovChain(NumassEvent(rnd.amp(null, 0), Instant.now(), 0)) { event -> + amp: RandomGenerator.(OrphanNumassEvent?, Long) -> Short = defaultAmplitudeGenerator): Chain { + return MarkovChain(OrphanNumassEvent(rnd.amp(null, 0), 0)) { event -> val deltaT = rnd.nextDeltaTime(cr) - NumassEvent(rnd.amp(event, deltaT), event.blockTime, event.timeOffset + deltaT) + OrphanNumassEvent(rnd.amp(event, deltaT), event.timeOffset + deltaT) } } +/** + * Generate a chain using provided spectrum for amplitudes + */ +fun generateEvents( + cr: Double, + rnd: RandomGenerator = defaultGenerator, + spectrum: Table): Chain { + + val channels = DoubleArray(spectrum.size()) + val values = DoubleArray(spectrum.size()) + for (i in 0 until spectrum.size()) { + channels[i] = spectrum.get(CHANNEL_KEY, i).doubleValue() + values[i] = spectrum.get(COUNT_RATE_KEY, i).doubleValue() + } + val distribution = EnumeratedRealDistribution(channels, values) + + return generateEvents(cr, rnd) { _, _ -> distribution.sample().toShort() } +} + private data class BunchState(var bunchStart: Long = 0, var bunchEnd: Long = 0) /** @@ -53,24 +81,24 @@ fun buildBunchChain( bunchRate: Double, bunchLength: Double, rnd: RandomGenerator = defaultGenerator, - amp: RandomGenerator.(NumassEvent?, Long) -> Short = defaultAmplitudeGenerator -): Chain { + amp: RandomGenerator.(OrphanNumassEvent?, Long) -> Short = defaultAmplitudeGenerator +): Chain { return StatefulChain( BunchState(0, 0), - NumassEvent(rnd.amp(null, 0), Instant.now(), 0)) { event -> + OrphanNumassEvent(rnd.amp(null, 0), 0)) { event -> if (event.timeOffset >= bunchEnd) { bunchStart = bunchEnd + (rnd.nextDeltaTime(bunchRate)).toLong() - bunchEnd = bunchStart + (bunchLength*1e9).toLong() - NumassEvent(rnd.amp(null, 0), Instant.EPOCH, bunchStart) + bunchEnd = bunchStart + (bunchLength * 1e9).toLong() + OrphanNumassEvent(rnd.amp(null, 0), bunchStart) } else { val deltaT = rnd.nextDeltaTime(cr) - NumassEvent(rnd.amp(event, deltaT), event.blockTime, event.timeOffset + deltaT) + OrphanNumassEvent(rnd.amp(event, deltaT), event.timeOffset + deltaT) } } } -private class MergingState(private val chains: List>) { - suspend fun poll(): NumassEvent { +private class MergingState(private val chains: List>) { + suspend fun poll(): OrphanNumassEvent { val next = chains.minBy { it.value.timeOffset } ?: chains.first() val res = next.value next.next() @@ -79,8 +107,8 @@ private class MergingState(private val chains: List>) { } -fun mergeEventChains(vararg chains: Chain): Chain { - return StatefulChain(MergingState(listOf(*chains)),NumassEvent(0, Instant.now(), 0)){ +fun mergeEventChains(vararg chains: Chain): Chain { + return StatefulChain(MergingState(listOf(*chains)), OrphanNumassEvent(0, 0)) { poll() } } diff --git a/numass-main/src/main/kotlin/inr/numass/data/PileUpSimulator.kt b/numass-main/src/main/kotlin/inr/numass/data/PileUpSimulator.kt new file mode 100644 index 00000000..e984df4a --- /dev/null +++ b/numass-main/src/main/kotlin/inr/numass/data/PileUpSimulator.kt @@ -0,0 +1,172 @@ +/* + * Copyright 2018 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. + */ + +/* + * 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 + +import hep.dataforge.maths.chain.Chain +import inr.numass.data.api.* +import kotlinx.coroutines.experimental.runBlocking +import org.apache.commons.math3.random.RandomGenerator +import java.lang.Math.max +import java.time.Duration +import java.time.Instant +import java.util.* +import java.util.concurrent.atomic.AtomicInteger + +/** + * @author [Alexander Nozik](mailto:altavir@gmail.com) + */ +class PileUpSimulator { + private val pointLength: Long + private val rnd: RandomGenerator + private val generated = ArrayList() + private val pileup = ArrayList() + private val registered = ArrayList() + private var generator: Chain + //private double uSet = 0; + private val doublePileup = AtomicInteger(0) + + + constructor(length: Long, rnd: RandomGenerator, countRate: Double) { + this.rnd = rnd + generator = generateEvents(countRate, rnd) + this.pointLength = length + } + + constructor(pointLength: Long, rnd: RandomGenerator, generator: Chain) { + this.rnd = rnd + this.pointLength = pointLength + this.generator = generator + } + +// fun withUset(uset: Double): PileUpSimulator { +// this.uSet = uset +// return this +// } + + fun generated(): NumassBlock { + return SimpleBlock(Instant.EPOCH, Duration.ofNanos(pointLength)) { parent -> generated.map { it.adopt(parent) } } + } + + fun registered(): NumassBlock { + return SimpleBlock(Instant.EPOCH, Duration.ofNanos(pointLength)) { parent -> registered.map { it.adopt(parent) } } + } + + fun pileup(): NumassBlock { + return SimpleBlock(Instant.EPOCH, Duration.ofNanos(pointLength)) { parent -> pileup.map { it.adopt(parent) } } + } + + /** + * The amplitude for pileup event + * + * @param x + * @return + */ + private fun pileupChannel(x: Double, prevChanel: Short, nextChanel: Short): Short { + assert(x > 0) + //эмпирическая формула для канала + val coef = max(0.0, 0.99078 + 0.05098 * x - 0.45775 * x * x + 0.10962 * x * x * x) + if (coef < 0 || coef > 1) { + throw Error() + } + + return (prevChanel + coef * nextChanel).toShort() + } + + /** + * pileup probability + * + * @param delay + * @return + */ + private fun pileup(delay: Double): Boolean { + val prob = 1.0 / (1.0 + Math.pow(delay / (2.5 + 0.2), 42.96)) + return random(prob) + } + + /** + * Probability for next event to register + * + * @param delay + * @return + */ + private fun nextEventRegistered(prevChanel: Short, delay: Double): Boolean { + val average = 6.76102 - 4.31897E-4 * prevChanel + 7.88429E-8 * prevChanel.toDouble() * prevChanel.toDouble() + 0.2 + val prob = 1.0 - 1.0 / (1.0 + Math.pow(delay / average, 75.91)) + return random(prob) + } + + private fun random(prob: Double): Boolean { + return rnd.nextDouble() <= prob + } + + @Synchronized + fun generate() { + var next: OrphanNumassEvent + var lastRegisteredTime = 0.0 // Time of DAQ closing + //flag that shows that previous event was pileup + var pileupFlag = false + runBlocking { + next = generator.next() + while (next.timeOffset <= pointLength) { + generated.add(next) + //not counting double pileups + if (generated.size > 1) { + val delay = (next.timeOffset - lastRegisteredTime) / us //time between events in microseconds + if (nextEventRegistered(next.amp, delay)) { + //just register new event + registered.add(next) + lastRegisteredTime = next.timeOffset.toDouble() + pileupFlag = false + } else if (pileup(delay)) { + if (pileupFlag) { + //increase double pileup stack + doublePileup.incrementAndGet() + } else { + //pileup event + val newChannel = pileupChannel(delay, next.amp, next.amp) + val newEvent = OrphanNumassEvent(newChannel, next.timeOffset) + //replace already registered event by event with new channel + registered.removeAt(registered.size - 1) + registered.add(newEvent) + pileup.add(newEvent) + //do not change DAQ close time + pileupFlag = true // up the flag to avoid secondary pileup + } + } else { + // second event not registered, DAQ closed + pileupFlag = false + } + } else { + //register first event + registered.add(next) + lastRegisteredTime = next.timeOffset.toDouble() + } + next = generator.next() + } + } + } + + companion object { + private const val us = 1e-6//microsecond + } + +} diff --git a/numass-main/src/main/kotlin/inr/numass/data/Visualization.kt b/numass-main/src/main/kotlin/inr/numass/data/Visualization.kt new file mode 100644 index 00000000..9a38911e --- /dev/null +++ b/numass-main/src/main/kotlin/inr/numass/data/Visualization.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2018 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.context.Context +import hep.dataforge.context.Global +import hep.dataforge.fx.plots.FXPlotManager +import hep.dataforge.kodex.KMetaBuilder +import hep.dataforge.kodex.buildMeta +import hep.dataforge.kodex.configure +import hep.dataforge.plots.data.DataPlot +import hep.dataforge.tables.Adapters +import inr.numass.data.analyzers.NumassAnalyzer +import inr.numass.data.analyzers.SmartAnalyzer +import inr.numass.data.api.NumassBlock + + +fun NumassBlock.plotAmplitudeSpectrum(plotName: String = "spectrum", frameName: String = "", context: Context = Global, metaAction: KMetaBuilder.() -> Unit) { + val meta = buildMeta("meta", metaAction) + val plotManager = context.load(FXPlotManager::class) + val data = SmartAnalyzer().getAmplitudeSpectrum(this, meta.getMetaOrEmpty("spectrum")) + plotManager.display(name = frameName) { + val valueAxis = if (meta.getBoolean("normalize",true)) { + NumassAnalyzer.COUNT_RATE_KEY + } else { + NumassAnalyzer.COUNT_KEY + } + val plot = DataPlot.plot( + plotName, + Adapters.buildXYAdapter(NumassAnalyzer.CHANNEL_KEY, valueAxis), + data + ).configure { + "connectionType" to "step" + "thickness" to 2 + "showLine" to true + "showSymbol" to false + "showErrors" to false + "JFreeChart.cache" to true + } + add(plot) + } +} \ No newline at end of file diff --git a/numass-main/src/main/kotlin/inr/numass/scripts/Bunches.kt b/numass-main/src/main/kotlin/inr/numass/scripts/Bunches.kt index a4703b7d..e4df94f3 100644 --- a/numass-main/src/main/kotlin/inr/numass/scripts/Bunches.kt +++ b/numass-main/src/main/kotlin/inr/numass/scripts/Bunches.kt @@ -5,8 +5,8 @@ import hep.dataforge.kodex.buildMeta import inr.numass.actions.TimeAnalyzerAction import inr.numass.data.api.SimpleNumassPoint import inr.numass.data.buildBunchChain -import inr.numass.data.buildSimpleEventChain import inr.numass.data.generateBlock +import inr.numass.data.generateEvents import inr.numass.data.mergeEventChains import java.time.Instant @@ -19,7 +19,7 @@ fun main(args: Array) { val num = 60; val blocks = (1..num).map { - val regularChain = buildSimpleEventChain(cr) + val regularChain = generateEvents(cr) val bunchChain = buildBunchChain(40.0, 0.01, 5.0) val generator = mergeEventChains(regularChain, bunchChain) diff --git a/numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt b/numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt index 352715de..1bef7611 100644 --- a/numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt +++ b/numass-main/src/main/kotlin/inr/numass/scripts/tristan/AnalyzeTristan.kt @@ -1,34 +1,11 @@ package inr.numass.scripts.tristan -import hep.dataforge.meta.Meta -import hep.dataforge.tables.Table -import hep.dataforge.values.Values -import inr.numass.data.analyzers.NumassAnalyzer -import inr.numass.data.api.NumassBlock -import inr.numass.data.api.NumassEvent -import inr.numass.data.api.NumassSet import inr.numass.data.storage.ProtoNumassPoint -import java.util.stream.Stream fun main(args: Array) { - val analyzer = object : NumassAnalyzer{ - override fun analyze(block: NumassBlock, config: Meta): Values { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun getEvents(block: NumassBlock, meta: Meta): Stream { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun analyzeSet(set: NumassSet, config: Meta): Table { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - } - val file = ProtoNumassPoint.readFile("D:\\Work\\Numass\\data\\TRISTAN_11_2017\\df\\gun_16_19.df ") - val events = Sequence { file.events.iterator() }.sortedBy { it.time } + val filtered = file.filter { it.channel == 4 } } \ No newline at end of file diff --git a/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanSummaryTask.kt b/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanSummaryTask.kt index 5efeea99..d20a43e0 100644 --- a/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanSummaryTask.kt +++ b/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanSummaryTask.kt @@ -30,7 +30,9 @@ class NumassFitScanSummaryTask : AbstractTask
() { val builder = DataSet.builder(Table::class.java) val action = FitSummaryAction() val input = data.checked(FitResult::class.java) - input.nodeStream().filter { it -> it.getSize(false) > 0 }.forEach { node -> builder.putData(node.name, action.run(model.context, node, model.getMeta()).data) } + input.nodeStream() + .filter { it -> it.getSize(false) > 0 } + .forEach { node -> builder.putData(node.name, action.run(model.context, node, model.meta).data) } return builder.build() } diff --git a/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanTask.kt b/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanTask.kt index 14868de5..c169473a 100644 --- a/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanTask.kt +++ b/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitScanTask.kt @@ -25,7 +25,7 @@ class NumassFitScanTask : AbstractTask() { override fun run(model: TaskModel, data: DataNode<*>): DataNode { - val config = model.getMeta() + val config = model.meta val scanParameter = config.getString("parameter", "msterile2") val scanValues: Value = if (config.hasValue("masses")) { @@ -57,7 +57,8 @@ class NumassFitScanTask : AbstractTask() { overrideMeta.setValue("params.$scanParameter.value", `val`) } else { overrideMeta.getMetaList("params.param").stream() - .filter { par -> par.getString("name") == scanParameter }.forEach { par -> par.setValue("value", `val`) } + .filter { par -> par.getString("name") == scanParameter } + .forEach { it.setValue("value", `val`) } } // Data
newData = new Data
(data.getGoal(),data.type(),overrideMeta); val node = action.run(model.context, DataNode.of(resultName, table, Meta.empty()), overrideMeta) diff --git a/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitSummaryTask.kt b/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitSummaryTask.kt index a4f80c44..7b80d26c 100644 --- a/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitSummaryTask.kt +++ b/numass-main/src/main/kotlin/inr/numass/tasks/NumassFitSummaryTask.kt @@ -42,7 +42,7 @@ class NumassFitSummaryTask : SingleActionTask() { } override fun transformMeta(model: TaskModel): Meta { - return model.getMeta().getMeta("summary") + return model.meta.getMeta("summary") } override fun buildModel(model: TaskModel.Builder, meta: Meta) { diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/NumassDataCache.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/NumassDataCache.kt index cf3327cb..b640426d 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/NumassDataCache.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/NumassDataCache.kt @@ -14,28 +14,20 @@ import java.util.stream.Stream */ class NumassDataCache(val data: NumassSet) : NumassSet { //private val cachedDescription: String by lazy { data.description } - private val cachedMeta: Meta by lazy { data.meta } + override val meta: Meta by lazy { data.meta } private val cachedPoints: List by lazy { data.points.collect(Collectors.toList()) } - private val hv: Optional
by lazy { data.hvData } + override val hvData: Optional
by lazy { data.hvData } - override fun getPoints(): Stream { - return cachedPoints.stream(); - } + override val points: Stream + get() = cachedPoints.stream() // override fun getDescription(): String { // return cachedDescription // } - override fun getMeta(): Meta { - return cachedMeta - } override fun getName(): String { return data.name; } - - override fun getHvData(): Optional
{ - return hv; - } } \ No newline at end of file