diff --git a/build.gradle b/build.gradle index a98f9e23..e138c1a7 100644 --- a/build.gradle +++ b/build.gradle @@ -21,9 +21,9 @@ allprojects{ } dependencies{ - compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.10" compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.10" - compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.2.10' + compile "org.jetbrains.kotlin:kotlin-reflect:1.2.10" + testCompile group: 'junit', name: 'junit', version: '4.+' } 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 b2420e68..ffd270b5 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 @@ -7,7 +7,7 @@ import hep.dataforge.grind.GrindShell import hep.dataforge.meta.Meta import inr.numass.NumassPlugin import inr.numass.actions.TimeAnalyzerAction -import inr.numass.data.SimpleChainGenerator +import inr.numass.data.GeneratorKt import inr.numass.data.api.SimpleNumassPoint import org.apache.commons.math3.random.JDKRandomGenerator @@ -32,8 +32,8 @@ new GrindShell(ctx).eval { def blocks = (1..num).collect { - def generator = new SimpleChainGenerator(cr, new JDKRandomGenerator(), { 1000 }) - generator.generateBlock(Instant.now().plusNanos(it * length), length) { prev, next -> next.timeOffset - prev.timeOffset > dt * 1000 } + def chain = GeneratorKt.buildSimpleEventChain(cr, new JDKRandomGenerator(),{10000}) + GeneratorKt.generateBlock(Instant.now().plusNanos(it * length), length, chain) } def point = new SimpleNumassPoint(10000, blocks) diff --git a/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt b/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt index bb7b2465..f91135db 100644 --- a/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt +++ b/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt @@ -99,7 +99,7 @@ class NumassPlugin : BasicPlugin() { BivariateFunction { E: Double, U: Double -> val D = E - U val factor = 7.33 - E / 1000.0 / 3.0 - return@BivariateFunction 1.0 - (3.05346E-7 * D - 5.45738E-10 * Math.pow(D, 2.0) - 6.36105E-14 * Math.pow(D, 3.0))*factor + return@BivariateFunction 1.0 - (3.05346E-7 * D - 5.45738E-10 * Math.pow(D, 2.0) - 6.36105E-14 * Math.pow(D, 3.0)) * factor } } } @@ -281,6 +281,6 @@ class NumassPlugin : BasicPlugin() { fun displayJFreeChart(title: String, width: Double = 800.0, height: Double = 600.0, meta: Meta = Meta.empty()): JFreeChartFrame { val frame = JFreeChartFrame(meta) frame.configureValue("title", title) - FXPlugin().apply { startGlobal() }.display (PlotContainer(frame)) + FXPlugin().apply { startGlobal() }.display(PlotContainer(frame), width, height) return frame } diff --git a/numass-main/src/main/kotlin/inr/numass/data/ChainGenerator.kt b/numass-main/src/main/kotlin/inr/numass/data/ChainGenerator.kt deleted file mode 100644 index 4f750f8f..00000000 --- a/numass-main/src/main/kotlin/inr/numass/data/ChainGenerator.kt +++ /dev/null @@ -1,114 +0,0 @@ -package inr.numass.data - -import inr.numass.data.api.NumassBlock -import inr.numass.data.api.NumassEvent -import inr.numass.data.api.SimpleBlock -import org.apache.commons.math3.random.JDKRandomGenerator -import org.apache.commons.math3.random.RandomGenerator -import java.time.Duration -import java.time.Instant -import java.util.* -import kotlin.collections.ArrayList - -interface ChainGenerator { - - fun next(event: NumassEvent?): NumassEvent - - fun generateBlock(start: Instant, length: Long, filter: (NumassEvent, NumassEvent) -> Boolean = { _, _ -> true }): NumassBlock { - val events = ArrayList() - var event = next(null) - events.add(event) - while (event.timeOffset < length) { - val nextEvent = next(event) - if (filter(event, nextEvent)) { - event = nextEvent - if (event.timeOffset < length) { - events.add(event) - } - } - } - return SimpleBlock(start, Duration.ofNanos(length), events) - } -} - - -private fun RandomGenerator.nextExp(mean: Double): Double { - return -mean * Math.log(1 - nextDouble()) -} - -private fun RandomGenerator.nextDeltaTime(cr: Double): Long { - return (nextExp(1.0 / cr) * 1e9).toLong() -} - -class SimpleChainGenerator( - val cr: Double, - private val rnd: RandomGenerator = JDKRandomGenerator(), - private val amp: RandomGenerator.(NumassEvent?, Long) -> Short = { _, _ -> ((nextDouble() + 2.0) * 100).toShort() } -) : ChainGenerator { - - override fun next(event: NumassEvent?): NumassEvent { - return if (event == null) { - NumassEvent(rnd.amp(null, 0), Instant.EPOCH, 0) - } else { - val deltaT = rnd.nextDeltaTime(cr) - NumassEvent(rnd.amp(event, deltaT), event.blockTime, event.timeOffset + deltaT) - } - } -} - -class BunchGenerator( - private val cr: Double, - private val bunchRate: Double, - private val bunchLength: RandomGenerator.() -> Long, - private val rnd: RandomGenerator = JDKRandomGenerator(), - private val amp: RandomGenerator.(NumassEvent?, Long) -> Short = { _, _ -> ((nextDouble() + 2.0) * 100).toShort() } -) : ChainGenerator { - - private val internalGenerator = SimpleChainGenerator(cr, rnd, amp) - - var bunchStart: Long = 0 - var bunchEnd: Long = 0 - - override fun next(event: NumassEvent?): NumassEvent { - if (event?.timeOffset ?: 0 >= bunchEnd) { - bunchStart = bunchEnd + rnd.nextExp(bunchRate).toLong() - bunchEnd = bunchStart + rnd.bunchLength() - return NumassEvent(rnd.amp(null, 0), Instant.EPOCH, bunchStart) - } else { - return internalGenerator.next(event) - } - } - - override fun generateBlock(start: Instant, length: Long, filter: (NumassEvent, NumassEvent) -> Boolean): NumassBlock { - bunchStart = 0 - bunchEnd = 0 - return super.generateBlock(start, length, filter) - } -} - - -class MergingGenerator(private vararg val generators: ChainGenerator) : ChainGenerator { - - private val waiting: TreeSet> = TreeSet(Comparator.comparing, Long> { it.second.timeOffset }) - - init { - generators.forEach { generator -> - waiting.add(Pair(generator, generator.next(null))) - } - } - - override fun next(event: NumassEvent?): NumassEvent { - val pair = waiting.first() - waiting.remove(pair) - waiting.add(Pair(pair.first, pair.first.next(pair.second))) - return pair.second - } - - override fun generateBlock(start: Instant, length: Long, filter: (NumassEvent, NumassEvent) -> Boolean): NumassBlock { - generators.forEach { generator -> - waiting.add(Pair(generator, generator.next(null))) - } - return super.generateBlock(start, length, filter) - } -} - diff --git a/numass-main/src/main/kotlin/inr/numass/data/Generator.kt b/numass-main/src/main/kotlin/inr/numass/data/Generator.kt new file mode 100644 index 00000000..6c71bc12 --- /dev/null +++ b/numass-main/src/main/kotlin/inr/numass/data/Generator.kt @@ -0,0 +1,186 @@ +package inr.numass.data + +import hep.dataforge.maths.chain.Chain +import hep.dataforge.maths.chain.MarkovChain +import hep.dataforge.maths.chain.StatefulChain +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.NumassEvent +import inr.numass.data.api.SimpleBlock +import org.apache.commons.math3.random.JDKRandomGenerator +import org.apache.commons.math3.random.RandomGenerator +import java.time.Duration +import java.time.Instant + +private fun RandomGenerator.nextExp(mean: Double): Double { + return -mean * Math.log(1 - nextDouble()) +} + +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 = chain.asSequence().takeWhile { it.timeOffset < length }.toList() + return SimpleBlock(start, Duration.ofNanos(length), events) +} + +internal val defaultGenerator = JDKRandomGenerator() + +internal val defaultAmplitudeGenerator: RandomGenerator.(NumassEvent?, Long) -> Short = { _, _ -> ((nextDouble() + 2.0) * 100).toShort() } + +fun buildSimpleEventChain( + cr: Double, + rnd: RandomGenerator = defaultGenerator, + amp: RandomGenerator.(NumassEvent?, Long) -> Short = defaultAmplitudeGenerator): Chain { + return MarkovChain(NumassEvent(rnd.amp(null, 0), Instant.now(), 0)) { event -> + val deltaT = rnd.nextDeltaTime(cr) + NumassEvent(rnd.amp(event, deltaT), event.blockTime, event.timeOffset + deltaT) + } +} + +private data class BunchState(var bunchStart: Long = 0, var bunchEnd: Long = 0) + +/** + * The chain of bunched events + * @param cr count rate of events inside bunch + * @param bunchRate number of bunches per second + * @param bunchLength the length of bunch + */ +fun buildBunchChain( + cr: Double, + bunchRate: Double, + bunchLength: Double, + rnd: RandomGenerator = defaultGenerator, + amp: RandomGenerator.(NumassEvent?, Long) -> Short = defaultAmplitudeGenerator +): Chain { + return StatefulChain( + BunchState(0, 0), + NumassEvent(rnd.amp(null, 0), Instant.now(), 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) + } else { + val deltaT = rnd.nextDeltaTime(cr) + NumassEvent(rnd.amp(event, deltaT), event.blockTime, event.timeOffset + deltaT) + } + } +} + +private class MergingState(private val chains: List>) { + suspend fun poll(): NumassEvent { + val next = chains.minBy { it.value.timeOffset } ?: chains.first() + val res = next.value + next.next() + return res + } + +} + +fun mergeEventChains(vararg chains: Chain): Chain { + return StatefulChain(MergingState(listOf(*chains)),NumassEvent(0, Instant.now(), 0)){ + poll() + } +} +// +// +///** +// * @param S - intermediate state of generator +// */ +//abstract class ChainGenerator { +// +// protected abstract fun next(event: NumassEvent?, state: S = buildState()): NumassEvent +// +// fun buildSequence(): Sequence { +// val state = buildState() +// return generateSequence(seed = null) { event: NumassEvent? -> +// next(event, state) +// } +// } +// +// protected abstract fun buildState(): S +// +// fun generateBlock(start: Instant, length: Long): NumassBlock { +// val events = buildSequence().takeWhile { it.timeOffset < length }.toList() +// return SimpleBlock(start, Duration.ofNanos(length), events) +// } +//} +// +// +//class SimpleChainGenerator( +// val cr: Double, +// private val rnd: RandomGenerator = JDKRandomGenerator(), +// private val amp: RandomGenerator.(NumassEvent?, Long) -> Short = { _, _ -> ((nextDouble() + 2.0) * 100).toShort() } +//) : ChainGenerator() { +// +// override fun buildState() { +// return Unit +// } +// +// override fun next(event: NumassEvent?, state: Unit): NumassEvent { +// return if (event == null) { +// NumassEvent(rnd.amp(null, 0), Instant.EPOCH, 0) +// } else { +// val deltaT = rnd.nextDeltaTime(cr) +// NumassEvent(rnd.amp(event, deltaT), event.blockTime, event.timeOffset + deltaT) +// } +// } +// +// fun next(event: NumassEvent?): NumassEvent { +// return next(event, Unit) +// } +//} +// +//class BunchGenerator( +// private val cr: Double, +// private val bunchRate: Double, +// private val bunchLength: RandomGenerator.() -> Long, +// private val rnd: RandomGenerator = JDKRandomGenerator(), +// private val amp: RandomGenerator.(NumassEvent?, Long) -> Short = { _, _ -> ((nextDouble() + 2.0) * 100).toShort() } +//) : ChainGenerator() { +// +// private val internalGenerator = SimpleChainGenerator(cr, rnd, amp) +// +// class BunchState(var bunchStart: Long = 0, var bunchEnd: Long = 0) +// +// override fun next(event: NumassEvent?, state: BunchState): NumassEvent { +// if (event?.timeOffset ?: 0 >= state.bunchEnd) { +// state.bunchStart = state.bunchEnd + (rnd.nextExp(bunchRate) * 1e9).toLong() +// state.bunchEnd = state.bunchStart + rnd.bunchLength() +// return NumassEvent(rnd.amp(null, 0), Instant.EPOCH, state.bunchStart) +// } else { +// return internalGenerator.next(event) +// } +// } +// +// override fun buildState(): BunchState { +// return BunchState(0, 0) +// } +//} +// +// +//class MergingGenerator(private vararg val generators: ChainGenerator<*>) : ChainGenerator() { +// +// inner class MergingState { +// val queue: PriorityQueue, NumassEvent>> = +// PriorityQueue(Comparator.comparing, NumassEvent>, Long> { it.second.timeOffset }) +// +// init { +// generators.forEach { generator -> +// val sequence = generator.buildSequence() +// queue.add(Pair(sequence, sequence.iterator().next())) +// } +// } +// } +// +// override fun next(event: NumassEvent?, state: MergingState): NumassEvent { +// val pair = state.queue.poll() +// state.queue.add(Pair(pair.first, pair.first.iterator().next())) +// return pair.second +// } +// +// override fun buildState(): MergingState { +// return MergingState() +// } +//} +// 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 abd842e1..28f5f374 100644 --- a/numass-main/src/main/kotlin/inr/numass/scripts/Bunches.kt +++ b/numass-main/src/main/kotlin/inr/numass/scripts/Bunches.kt @@ -1,33 +1,27 @@ package inr.numass.scripts -import hep.dataforge.fx.plots.PlotManager -import hep.dataforge.kodex.buildContext import hep.dataforge.kodex.buildMeta -import inr.numass.NumassPlugin -import inr.numass.data.BunchGenerator -import inr.numass.data.MergingGenerator -import inr.numass.data.SimpleChainGenerator import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.SmartAnalyzer 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.mergeEventChains import java.time.Instant fun main(args: Array) { - val context = buildContext("NUMASS", NumassPlugin::class.java, PlotManager::class.java) - val cr = 10.0 - val length = 30e9.toLong() - val num = 50; - val dt = 6.5 - - val regularGenerator = SimpleChainGenerator(cr) - val bunchGenerator = BunchGenerator(40.0, 0.1, { 2e9.toLong() }) - - val generator = MergingGenerator(regularGenerator, bunchGenerator) + val length = 1e12.toLong() + val num = 20; val blocks = (1..num).map { - generator.generateBlock(Instant.now().plusNanos(it * length), length) + val regularChain = buildSimpleEventChain(cr) + val bunchChain = buildBunchChain(20.0, 0.01, 5.0) + + val generator = mergeEventChains(regularChain, bunchChain) + generateBlock(Instant.now().plusNanos(it * length), length, generator) } val point = SimpleNumassPoint(10000.0, blocks) @@ -36,11 +30,11 @@ fun main(args: Array) { "t0.crFraction" to 0.1 } - println("actual count rate: ${point.events.count() / point.length.seconds}") + println("actual count rate: ${point.events.count().toDouble() / point.length.seconds}") - val res = SmartAnalyzer().analyze(point,meta) + val res = SmartAnalyzer().analyze(point, meta) .getDouble(NumassAnalyzer.COUNT_RATE_KEY) - println("estimated count rate: ${res}") + println("estimated count rate: $res") } \ No newline at end of file diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt index acb0662f..25c051ea 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt @@ -3,6 +3,7 @@ package inr.numass.viewer import hep.dataforge.fx.dfIcon import hep.dataforge.fx.plots.PlotContainer import hep.dataforge.fx.runGoal +import hep.dataforge.fx.ui import hep.dataforge.goals.Goal import hep.dataforge.kodex.configure import hep.dataforge.meta.Meta @@ -13,6 +14,7 @@ import hep.dataforge.tables.Adapters import hep.dataforge.tables.Table import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.SimpleAnalyzer +import inr.numass.data.analyzers.spectrumWithBinning import inr.numass.data.api.NumassPoint import javafx.beans.Observable import javafx.beans.binding.DoubleBinding @@ -131,7 +133,7 @@ class AmplitudeView( DataPlot.plot( key, Adapters.buildXYAdapter(NumassAnalyzer.CHANNEL_KEY, valueAxis), - NumassAnalyzer.spectrumWithBinning(getSpectrum(point), binning) + spectrumWithBinning(getSpectrum(point), binning) ).configure { "connectionType" to "step" "thickness" to 2 @@ -140,7 +142,7 @@ class AmplitudeView( "showErrors" to false "JFreeChart.cache" to true } - }.ui { plot -> + } ui { plot -> frame.add(plot) progress.invalidate() } diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt index 1d9e0bd9..2e955e25 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt @@ -13,6 +13,7 @@ import hep.dataforge.tables.Adapters import hep.dataforge.tables.Table import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.SimpleAnalyzer +import inr.numass.data.analyzers.countInWindow import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassSet import javafx.beans.property.SimpleIntegerProperty @@ -172,7 +173,7 @@ class SpectrumView( runGoal("spectrumData[$name]") { set.points.map { point -> - val count = NumassAnalyzer.countInWindow(getSpectrum(point), loChannel.toShort(), upChannel.toShort()); + val count = countInWindow(getSpectrum(point), loChannel.toShort(), upChannel.toShort()); val seconds = point.length.toMillis() / 1000.0; runLater { container.progress = progress.incrementAndGet().toDouble() / totalProgress diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt index 680232ec..8a712488 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt @@ -12,7 +12,6 @@ import inr.numass.viewer.SpectrumView import javafx.application.Application import javafx.scene.image.ImageView import tornadofx.* -import java.io.File import java.util.concurrent.ConcurrentHashMap import java.util.stream.Collectors @@ -36,8 +35,7 @@ class ViewerComponentsTest : View(title = "Numass viewer test", icon = ImageView button("Click me!") { action { runAsync { - val rootDir = File("D:\\Work\\Numass\\data\\2017_05\\Fill_2") - val set: NumassSet = NumassStorageFactory.buildLocal(global, rootDir, true, true) + val set: NumassSet = NumassStorageFactory.buildLocal(global, "D:\\Work\\Numass\\data\\2017_05\\Fill_2", true, true) .provide("loader::set_2", NumassSet::class.java) .orElseThrow { RuntimeException("err") } update(set);