Refactor visualization

Replace usage of Stream:toList because of glitches in scripting
This commit is contained in:
Alexander Nozik 2022-06-07 12:44:30 +03:00
parent b911790238
commit ef670f8418
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
39 changed files with 1118 additions and 2401 deletions

1
.gitignore vendored
View File

@ -5,5 +5,6 @@ out/
.gradle
build/
/notebooks/.ipynb_checkpoints
/kotlin-js-store/
!gradle-wrapper.jar

View File

@ -1,24 +1,25 @@
plugins {
id("ru.mipt.npm.gradle.project")
id("space.kscience.gradle.project")
}
allprojects {
repositories {
mavenLocal()
maven("https://repo.kotlin.link")
maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
}
group = "ru.inr.mass"
version = "0.1.3"
}
val dataforgeVersion by extra("0.5.2")
val tablesVersion: String by extra("0.1.5")
val kmathVersion by extra("0.3.0")
val plotlyVersion: String by extra("0.5.0")
val dataforgeVersion by extra("0.6.0-dev-15")
val tablesVersion: String by extra("0.2.0-dev-3")
val kmathVersion by extra("0.3.1-dev-6")
val visionForgeVersion: String by rootProject.extra("0.3.0-dev-4")
ksciencePublish{
github("numass")
space("https://maven.pkg.jetbrains.space/mipt-npm/p/numass/maven")
}

View File

@ -12,4 +12,4 @@ org.gradle.configureondemand=true
org.gradle.parallel=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
toolsVersion=0.11.2-kotlin-1.6.10
toolsVersion=0.13.3-kotlin-1.7.20

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
"source": [
"@file:Repository(\"https://repo.kotlin.link\")\n",
"@file:Repository(\"*mavenLocal\")\n",
"@file:DependsOn(\"ru.inr.mass:numass-workspace:0.1.1\")"
"@file:DependsOn(\"ru.inr.mass:numass-workspace:0.1.3\")"
]
},
{

View File

@ -1,6 +1,5 @@
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
id("space.kscience.gradle.mpp")
`maven-publish`
}
@ -22,8 +21,8 @@ kotlin.sourceSets {
}
}
kscience{
useAtomic()
}
//kscience{
// useAtomic()
//}

View File

@ -23,10 +23,6 @@ import ru.inr.mass.data.api.NumassPoint.Companion.HV_KEY
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.values.ListValue
import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.ValueType
import space.kscience.dataforge.values.int
import space.kscience.tables.ColumnHeader
import space.kscience.tables.MetaRow
import space.kscience.tables.RowTable

View File

@ -31,7 +31,9 @@ import kotlin.math.*
* An analyzer which uses time information from events
* Created by darksnake on 11.07.2017.
*/
public open class TimeAnalyzer(override val extractor: NumassEventExtractor) : NumassAnalyzer() {
public open class TimeAnalyzer(
override val extractor: NumassEventExtractor = NumassEventExtractor.EVENTS_ONLY,
) : NumassAnalyzer() {
override suspend fun analyzeInternal(
block: NumassBlock,
@ -76,7 +78,7 @@ public open class TimeAnalyzer(override val extractor: NumassEventExtractor) : N
filter { pair -> pair.second >= t0 }.collect { pair ->
totalN++
//TODO add progress listener here
totalT+= pair.second
totalT += pair.second
}
if (totalN == 0L) {
@ -114,10 +116,12 @@ public open class TimeAnalyzer(override val extractor: NumassEventExtractor) : N
sumOf { it.countRate } / size,
sumOf { it.countRateError.pow(2.0) } / size / size
)
AveragingMethod.WEIGHTED -> Pair(
sumOf { it.countRate * it.length } / totalTime,
sumOf { (it.countRateError * it.length / totalTime).pow(2.0) }
)
AveragingMethod.GEOMETRIC -> {
val mean = exp(sumOf { ln(it.countRate) } / size)
val variance = (mean / size).pow(2.0) * sumOf {

View File

@ -1,6 +1,5 @@
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
id("space.kscience.gradle.mpp")
`maven-publish`
}
@ -12,7 +11,7 @@ kotlin.sourceSets {
dependencies {
api("space.kscience:dataforge-context:$dataforgeVersion")
api("space.kscience:dataforge-data:$dataforgeVersion")
api("org.jetbrains.kotlinx:kotlinx-datetime:${ru.mipt.npm.gradle.KScienceVersions.dateTimeVersion}")
api("org.jetbrains.kotlinx:kotlinx-datetime:${space.kscience.gradle.KScienceVersions.dateTimeVersion}")
}
}
jvmMain{

View File

@ -1,7 +1,6 @@
plugins {
kotlin("jvm")
id("ru.mipt.npm.gradle.common")
id("com.squareup.wire") version "4.2.0"
id("space.kscience.gradle.jvm")
id("com.squareup.wire") version "4.4.1"
`maven-publish`
}
@ -12,6 +11,13 @@ dependencies {
api("space.kscience:dataforge-io:$dataforgeVersion")
}
wire{
kotlin{}
wire {
kotlin {
out = "src/gen/kotlin"
}
}
sourceSets.main {
kotlin.srcDir("src/gen/kotlin")
}

View File

@ -0,0 +1,659 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source: ru.inr.mass.data.proto.Point in numass-proto.proto
package ru.inr.mass.`data`.proto
import com.squareup.wire.*
import com.squareup.wire.Syntax.PROTO_3
import com.squareup.wire.internal.immutableCopyOf
import com.squareup.wire.internal.redactElements
import okio.ByteString
public class Point(
channels: List<Channel> = emptyList(),
unknownFields: ByteString = ByteString.EMPTY,
) : Message<Point, Nothing>(ADAPTER, unknownFields) {
/**
* Array of measuring channels
*/
@field:WireField(
tag = 1,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel#ADAPTER",
label = WireField.Label.REPEATED,
)
public val channels: List<Channel> = immutableCopyOf("channels", channels)
@Deprecated(
message = "Shouldn't be used in Kotlin",
level = DeprecationLevel.HIDDEN,
)
public override fun newBuilder(): Nothing = throw
AssertionError("Builders are deprecated and only available in a javaInterop build; see https://square.github.io/wire/wire_compiler/#kotlin")
public override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Point) return false
if (unknownFields != other.unknownFields) return false
if (channels != other.channels) return false
return true
}
public override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
result = result * 37 + channels.hashCode()
super.hashCode = result
}
return result
}
public override fun toString(): String {
val result = mutableListOf<String>()
if (channels.isNotEmpty()) result += """channels=$channels"""
return result.joinToString(prefix = "Point{", separator = ", ", postfix = "}")
}
public fun copy(channels: List<Channel> = this.channels, unknownFields: ByteString =
this.unknownFields): Point = Point(channels, unknownFields)
public companion object {
@JvmField
public val ADAPTER: ProtoAdapter<Point> = object : ProtoAdapter<Point>(
FieldEncoding.LENGTH_DELIMITED,
Point::class,
"type.googleapis.com/ru.inr.mass.data.proto.Point",
PROTO_3,
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Point): Int {
var size = value.unknownFields.size
size += Channel.ADAPTER.asRepeated().encodedSizeWithTag(1, value.channels)
return size
}
public override fun encode(writer: ProtoWriter, `value`: Point): Unit {
Channel.ADAPTER.asRepeated().encodeWithTag(writer, 1, value.channels)
writer.writeBytes(value.unknownFields)
}
public override fun encode(writer: ReverseProtoWriter, `value`: Point): Unit {
writer.writeBytes(value.unknownFields)
Channel.ADAPTER.asRepeated().encodeWithTag(writer, 1, value.channels)
}
public override fun decode(reader: ProtoReader): Point {
val channels = mutableListOf<Channel>()
val unknownFields = reader.forEachTag { tag ->
when (tag) {
1 -> channels.add(Channel.ADAPTER.decode(reader))
else -> reader.readUnknownField(tag)
}
}
return Point(
channels = channels,
unknownFields = unknownFields
)
}
public override fun redact(`value`: Point): Point = value.copy(
channels = value.channels.redactElements(Channel.ADAPTER),
unknownFields = ByteString.EMPTY
)
}
private const val serialVersionUID: Long = 0L
}
/**
* A single channel for multichannel detector readout
*/
public class Channel(
/**
* The number of measuring channel
*/
@field:WireField(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
)
public val id: Long = 0L,
blocks: List<Block> = emptyList(),
unknownFields: ByteString = ByteString.EMPTY,
) : Message<Channel, Nothing>(ADAPTER, unknownFields) {
/**
* Blocks
*/
@field:WireField(
tag = 2,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel${'$'}Block#ADAPTER",
label = WireField.Label.REPEATED,
)
public val blocks: List<Block> = immutableCopyOf("blocks", blocks)
@Deprecated(
message = "Shouldn't be used in Kotlin",
level = DeprecationLevel.HIDDEN,
)
public override fun newBuilder(): Nothing = throw
AssertionError("Builders are deprecated and only available in a javaInterop build; see https://square.github.io/wire/wire_compiler/#kotlin")
public override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Channel) return false
if (unknownFields != other.unknownFields) return false
if (id != other.id) return false
if (blocks != other.blocks) return false
return true
}
public override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
result = result * 37 + id.hashCode()
result = result * 37 + blocks.hashCode()
super.hashCode = result
}
return result
}
public override fun toString(): String {
val result = mutableListOf<String>()
result += """id=$id"""
if (blocks.isNotEmpty()) result += """blocks=$blocks"""
return result.joinToString(prefix = "Channel{", separator = ", ", postfix = "}")
}
public fun copy(
id: Long = this.id,
blocks: List<Block> = this.blocks,
unknownFields: ByteString = this.unknownFields,
): Channel = Channel(id, blocks, unknownFields)
public companion object {
@JvmField
public val ADAPTER: ProtoAdapter<Channel> = object : ProtoAdapter<Channel>(
FieldEncoding.LENGTH_DELIMITED,
Channel::class,
"type.googleapis.com/ru.inr.mass.data.proto.Point.Channel",
PROTO_3,
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Channel): Int {
var size = value.unknownFields.size
if (value.id != 0L) size += ProtoAdapter.UINT64.encodedSizeWithTag(1, value.id)
size += Block.ADAPTER.asRepeated().encodedSizeWithTag(2, value.blocks)
return size
}
public override fun encode(writer: ProtoWriter, `value`: Channel): Unit {
if (value.id != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.id)
Block.ADAPTER.asRepeated().encodeWithTag(writer, 2, value.blocks)
writer.writeBytes(value.unknownFields)
}
public override fun encode(writer: ReverseProtoWriter, `value`: Channel): Unit {
writer.writeBytes(value.unknownFields)
Block.ADAPTER.asRepeated().encodeWithTag(writer, 2, value.blocks)
if (value.id != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.id)
}
public override fun decode(reader: ProtoReader): Channel {
var id: Long = 0L
val blocks = mutableListOf<Block>()
val unknownFields = reader.forEachTag { tag ->
when (tag) {
1 -> id = ProtoAdapter.UINT64.decode(reader)
2 -> blocks.add(Block.ADAPTER.decode(reader))
else -> reader.readUnknownField(tag)
}
}
return Channel(
id = id,
blocks = blocks,
unknownFields = unknownFields
)
}
public override fun redact(`value`: Channel): Channel = value.copy(
blocks = value.blocks.redactElements(Block.ADAPTER),
unknownFields = ByteString.EMPTY
)
}
private const val serialVersionUID: Long = 0L
}
/**
* A continuous measurement block
*/
public class Block(
/**
* Block start in epoch nanos
*/
@field:WireField(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
)
public val time: Long = 0L,
frames: List<Frame> = emptyList(),
/**
* Events array
*/
@field:WireField(
tag = 3,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel${'$'}Block${'$'}Events#ADAPTER",
label = WireField.Label.OMIT_IDENTITY,
)
public val events: Events? = null,
/**
* block size in nanos. If missing, take from meta.
*/
@field:WireField(
tag = 4,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
)
public val length: Long = 0L,
/**
* tick size in nanos. Obsolete, to be removed
*/
@field:WireField(
tag = 5,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
jsonName = "binSize",
)
public val bin_size: Long = 0L,
unknownFields: ByteString = ByteString.EMPTY,
) : Message<Block, Nothing>(ADAPTER, unknownFields) {
/**
* Frames array
*/
@field:WireField(
tag = 2,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel${'$'}Block${'$'}Frame#ADAPTER",
label = WireField.Label.REPEATED,
)
public val frames: List<Frame> = immutableCopyOf("frames", frames)
@Deprecated(
message = "Shouldn't be used in Kotlin",
level = DeprecationLevel.HIDDEN,
)
public override fun newBuilder(): Nothing = throw
AssertionError("Builders are deprecated and only available in a javaInterop build; see https://square.github.io/wire/wire_compiler/#kotlin")
public override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Block) return false
if (unknownFields != other.unknownFields) return false
if (time != other.time) return false
if (frames != other.frames) return false
if (events != other.events) return false
if (length != other.length) return false
if (bin_size != other.bin_size) return false
return true
}
public override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
result = result * 37 + time.hashCode()
result = result * 37 + frames.hashCode()
result = result * 37 + (events?.hashCode() ?: 0)
result = result * 37 + length.hashCode()
result = result * 37 + bin_size.hashCode()
super.hashCode = result
}
return result
}
public override fun toString(): String {
val result = mutableListOf<String>()
result += """time=$time"""
if (frames.isNotEmpty()) result += """frames=$frames"""
if (events != null) result += """events=$events"""
result += """length=$length"""
result += """bin_size=$bin_size"""
return result.joinToString(prefix = "Block{", separator = ", ", postfix = "}")
}
public fun copy(
time: Long = this.time,
frames: List<Frame> = this.frames,
events: Events? = this.events,
length: Long = this.length,
bin_size: Long = this.bin_size,
unknownFields: ByteString = this.unknownFields,
): Block = Block(time, frames, events, length, bin_size, unknownFields)
public companion object {
@JvmField
public val ADAPTER: ProtoAdapter<Block> = object : ProtoAdapter<Block>(
FieldEncoding.LENGTH_DELIMITED,
Block::class,
"type.googleapis.com/ru.inr.mass.data.proto.Point.Channel.Block",
PROTO_3,
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Block): Int {
var size = value.unknownFields.size
if (value.time != 0L) size += ProtoAdapter.UINT64.encodedSizeWithTag(1, value.time)
size += Frame.ADAPTER.asRepeated().encodedSizeWithTag(2, value.frames)
if (value.events != null) size += Events.ADAPTER.encodedSizeWithTag(3, value.events)
if (value.length != 0L) size += ProtoAdapter.UINT64.encodedSizeWithTag(4, value.length)
if (value.bin_size != 0L) size += ProtoAdapter.UINT64.encodedSizeWithTag(5,
value.bin_size)
return size
}
public override fun encode(writer: ProtoWriter, `value`: Block): Unit {
if (value.time != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.time)
Frame.ADAPTER.asRepeated().encodeWithTag(writer, 2, value.frames)
if (value.events != null) Events.ADAPTER.encodeWithTag(writer, 3, value.events)
if (value.length != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 4, value.length)
if (value.bin_size != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 5, value.bin_size)
writer.writeBytes(value.unknownFields)
}
public override fun encode(writer: ReverseProtoWriter, `value`: Block): Unit {
writer.writeBytes(value.unknownFields)
if (value.bin_size != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 5, value.bin_size)
if (value.length != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 4, value.length)
if (value.events != null) Events.ADAPTER.encodeWithTag(writer, 3, value.events)
Frame.ADAPTER.asRepeated().encodeWithTag(writer, 2, value.frames)
if (value.time != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.time)
}
public override fun decode(reader: ProtoReader): Block {
var time: Long = 0L
val frames = mutableListOf<Frame>()
var events: Events? = null
var length: Long = 0L
var bin_size: Long = 0L
val unknownFields = reader.forEachTag { tag ->
when (tag) {
1 -> time = ProtoAdapter.UINT64.decode(reader)
2 -> frames.add(Frame.ADAPTER.decode(reader))
3 -> events = Events.ADAPTER.decode(reader)
4 -> length = ProtoAdapter.UINT64.decode(reader)
5 -> bin_size = ProtoAdapter.UINT64.decode(reader)
else -> reader.readUnknownField(tag)
}
}
return Block(
time = time,
frames = frames,
events = events,
length = length,
bin_size = bin_size,
unknownFields = unknownFields
)
}
public override fun redact(`value`: Block): Block = value.copy(
frames = value.frames.redactElements(Frame.ADAPTER),
events = value.events?.let(Events.ADAPTER::redact),
unknownFields = ByteString.EMPTY
)
}
private const val serialVersionUID: Long = 0L
}
/**
* Raw data frame
*/
public class Frame(
/**
* Time in nanos from the beginning of the block
*/
@field:WireField(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
)
public val time: Long = 0L,
/**
* Frame data as an array of int16 measured in arbitrary channels
*/
@field:WireField(
tag = 2,
adapter = "com.squareup.wire.ProtoAdapter#BYTES",
label = WireField.Label.OMIT_IDENTITY,
declaredName = "data",
)
public val data_: ByteString = ByteString.EMPTY,
unknownFields: ByteString = ByteString.EMPTY,
) : Message<Frame, Nothing>(ADAPTER, unknownFields) {
@Deprecated(
message = "Shouldn't be used in Kotlin",
level = DeprecationLevel.HIDDEN,
)
public override fun newBuilder(): Nothing = throw
AssertionError("Builders are deprecated and only available in a javaInterop build; see https://square.github.io/wire/wire_compiler/#kotlin")
public override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Frame) return false
if (unknownFields != other.unknownFields) return false
if (time != other.time) return false
if (data_ != other.data_) return false
return true
}
public override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
result = result * 37 + time.hashCode()
result = result * 37 + data_.hashCode()
super.hashCode = result
}
return result
}
public override fun toString(): String {
val result = mutableListOf<String>()
result += """time=$time"""
result += """data_=$data_"""
return result.joinToString(prefix = "Frame{", separator = ", ", postfix = "}")
}
public fun copy(
time: Long = this.time,
data_: ByteString = this.data_,
unknownFields: ByteString = this.unknownFields,
): Frame = Frame(time, data_, unknownFields)
public companion object {
@JvmField
public val ADAPTER: ProtoAdapter<Frame> = object : ProtoAdapter<Frame>(
FieldEncoding.LENGTH_DELIMITED,
Frame::class,
"type.googleapis.com/ru.inr.mass.data.proto.Point.Channel.Block.Frame",
PROTO_3,
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Frame): Int {
var size = value.unknownFields.size
if (value.time != 0L) size += ProtoAdapter.UINT64.encodedSizeWithTag(1, value.time)
if (value.data_ != ByteString.EMPTY) size += ProtoAdapter.BYTES.encodedSizeWithTag(2,
value.data_)
return size
}
public override fun encode(writer: ProtoWriter, `value`: Frame): Unit {
if (value.time != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.time)
if (value.data_ != ByteString.EMPTY) ProtoAdapter.BYTES.encodeWithTag(writer, 2,
value.data_)
writer.writeBytes(value.unknownFields)
}
public override fun encode(writer: ReverseProtoWriter, `value`: Frame): Unit {
writer.writeBytes(value.unknownFields)
if (value.data_ != ByteString.EMPTY) ProtoAdapter.BYTES.encodeWithTag(writer, 2,
value.data_)
if (value.time != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.time)
}
public override fun decode(reader: ProtoReader): Frame {
var time: Long = 0L
var data_: ByteString = ByteString.EMPTY
val unknownFields = reader.forEachTag { tag ->
when (tag) {
1 -> time = ProtoAdapter.UINT64.decode(reader)
2 -> data_ = ProtoAdapter.BYTES.decode(reader)
else -> reader.readUnknownField(tag)
}
}
return Frame(
time = time,
data_ = data_,
unknownFields = unknownFields
)
}
public override fun redact(`value`: Frame): Frame = value.copy(
unknownFields = ByteString.EMPTY
)
}
private const val serialVersionUID: Long = 0L
}
}
/**
* Event block obtained directly from device of from frame analysis
* In order to save space, times and amplitudes are in separate arrays.
* Amplitude and time with the same index correspond to the same event
*/
public class Events(
times: List<Long> = emptyList(),
amplitudes: List<Long> = emptyList(),
unknownFields: ByteString = ByteString.EMPTY,
) : Message<Events, Nothing>(ADAPTER, unknownFields) {
/**
* Array of time in nanos from the beginning of the block
*/
@field:WireField(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.PACKED,
)
public val times: List<Long> = immutableCopyOf("times", times)
/**
* Array of amplitudes of events in channels
*/
@field:WireField(
tag = 2,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.PACKED,
)
public val amplitudes: List<Long> = immutableCopyOf("amplitudes", amplitudes)
@Deprecated(
message = "Shouldn't be used in Kotlin",
level = DeprecationLevel.HIDDEN,
)
public override fun newBuilder(): Nothing = throw
AssertionError("Builders are deprecated and only available in a javaInterop build; see https://square.github.io/wire/wire_compiler/#kotlin")
public override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Events) return false
if (unknownFields != other.unknownFields) return false
if (times != other.times) return false
if (amplitudes != other.amplitudes) return false
return true
}
public override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
result = result * 37 + times.hashCode()
result = result * 37 + amplitudes.hashCode()
super.hashCode = result
}
return result
}
public override fun toString(): String {
val result = mutableListOf<String>()
if (times.isNotEmpty()) result += """times=$times"""
if (amplitudes.isNotEmpty()) result += """amplitudes=$amplitudes"""
return result.joinToString(prefix = "Events{", separator = ", ", postfix = "}")
}
public fun copy(
times: List<Long> = this.times,
amplitudes: List<Long> = this.amplitudes,
unknownFields: ByteString = this.unknownFields,
): Events = Events(times, amplitudes, unknownFields)
public companion object {
@JvmField
public val ADAPTER: ProtoAdapter<Events> = object : ProtoAdapter<Events>(
FieldEncoding.LENGTH_DELIMITED,
Events::class,
"type.googleapis.com/ru.inr.mass.data.proto.Point.Channel.Block.Events",
PROTO_3,
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Events): Int {
var size = value.unknownFields.size
size += ProtoAdapter.UINT64.asPacked().encodedSizeWithTag(1, value.times)
size += ProtoAdapter.UINT64.asPacked().encodedSizeWithTag(2, value.amplitudes)
return size
}
public override fun encode(writer: ProtoWriter, `value`: Events): Unit {
ProtoAdapter.UINT64.asPacked().encodeWithTag(writer, 1, value.times)
ProtoAdapter.UINT64.asPacked().encodeWithTag(writer, 2, value.amplitudes)
writer.writeBytes(value.unknownFields)
}
public override fun encode(writer: ReverseProtoWriter, `value`: Events): Unit {
writer.writeBytes(value.unknownFields)
ProtoAdapter.UINT64.asPacked().encodeWithTag(writer, 2, value.amplitudes)
ProtoAdapter.UINT64.asPacked().encodeWithTag(writer, 1, value.times)
}
public override fun decode(reader: ProtoReader): Events {
val times = mutableListOf<Long>()
val amplitudes = mutableListOf<Long>()
val unknownFields = reader.forEachTag { tag ->
when (tag) {
1 -> times.add(ProtoAdapter.UINT64.decode(reader))
2 -> amplitudes.add(ProtoAdapter.UINT64.decode(reader))
else -> reader.readUnknownField(tag)
}
}
return Events(
times = times,
amplitudes = amplitudes,
unknownFields = unknownFields
)
}
public override fun redact(`value`: Events): Events = value.copy(
unknownFields = ByteString.EMPTY
)
}
private const val serialVersionUID: Long = 0L
}
}
}
}
}

View File

@ -4,10 +4,7 @@ import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.api.NumassSet.Companion.NUMASS_HV_TARGET
import ru.inr.mass.data.api.readEnvelope
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.error
import space.kscience.dataforge.context.logger
import space.kscience.dataforge.context.warn
import space.kscience.dataforge.context.*
import space.kscience.dataforge.io.io
import space.kscience.dataforge.io.readEnvelopeFile
import space.kscience.dataforge.meta.Meta
@ -16,14 +13,16 @@ import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import java.nio.file.Files
import java.nio.file.Path
import java.util.stream.Collectors
import kotlin.io.path.*
import kotlin.streams.toList
@OptIn(ExperimentalPathApi::class)
public class NumassDirectorySet internal constructor(
public val context: Context,
public val numassProto: NumassProtoPlugin,
public val path: Path,
) : NumassSet {
) : NumassSet, ContextAware {
override val context: Context
get() = numassProto.context
@OptIn(DFExperimental::class)
override val meta: Meta
@ -43,12 +42,12 @@ public class NumassDirectorySet internal constructor(
it.fileName.name.startsWith("p")
}.map { pointPath ->
try {
context.readNumassPointFile(pointPath)
numassProto.readNumassPointFile(pointPath)
} catch (e: Exception) {
context.logger.error(e) { "Error reading Numass point file $pointPath" }
null
}
}.toList().filterNotNull()
}.collect(Collectors.toList()).filterNotNull()
@OptIn(DFExperimental::class)
@ -73,20 +72,3 @@ public class NumassDirectorySet internal constructor(
public companion object
}
@OptIn(DFExperimental::class)
public fun Context.readNumassPointFile(path: Path): NumassPoint? {
val envelope = io.readEnvelopeFile(path)
return ProtoNumassPoint.fromEnvelope(envelope)
}
public fun Context.readNumassPointFile(path: String): NumassPoint? = readNumassPointFile(Path.of(path))
@OptIn(ExperimentalPathApi::class)
public fun Context.readNumassDirectory(path: Path): NumassDirectorySet {
if (!path.exists()) error("Path $path does not exist")
if (!path.isDirectory()) error("The path $path is not a directory")
return NumassDirectorySet(this, path)
}
public fun Context.readNumassDirectory(path: String): NumassDirectorySet = readNumassDirectory(Path.of(path))

View File

@ -1,28 +1,77 @@
package ru.inr.mass.data.proto
import kotlinx.coroutines.launch
import ru.inr.mass.data.api.NumassPoint
import space.kscience.dataforge.context.AbstractPlugin
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.data.DataSource
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.static
import space.kscience.dataforge.io.EnvelopeFormatFactory
import space.kscience.dataforge.io.IOPlugin
import space.kscience.dataforge.io.readEnvelopeFile
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.relativeTo
import kotlin.reflect.KClass
public class NumassProtoPlugin : AbstractPlugin() {
public val io: IOPlugin by require(IOPlugin)
override val tag: PluginTag get() = Companion.tag
override fun content(target: String): Map<Name, Any> = if(target == EnvelopeFormatFactory.ENVELOPE_FORMAT_TYPE){
override fun content(target: String): Map<Name, Any> = if (target == EnvelopeFormatFactory.ENVELOPE_FORMAT_TYPE) {
mapOf(TaggedNumassEnvelopeFormat.name to TaggedNumassEnvelopeFormat)
} else{
} else {
super.content(target)
}
public companion object : PluginFactory<NumassProtoPlugin> {
override fun invoke(meta: Meta, context: Context): NumassProtoPlugin = NumassProtoPlugin()
override fun build(context: Context, meta: Meta): NumassProtoPlugin = NumassProtoPlugin()
override val tag: PluginTag = PluginTag("numass-proto", group = "ru.inr.mass")
override val type: KClass<out NumassProtoPlugin> = NumassProtoPlugin::class
}
}
@OptIn(DFExperimental::class)
public fun NumassProtoPlugin.readNumassPointFile(path: Path): NumassPoint? {
val envelope = io.readEnvelopeFile(path)
return ProtoNumassPoint.fromEnvelope(envelope)
}
public fun NumassProtoPlugin.readNumassPointFile(path: String): NumassPoint? = readNumassPointFile(Path.of(path))
public fun NumassProtoPlugin.readNumassDirectory(path: Path): NumassDirectorySet {
if (!path.exists()) error("Path $path does not exist")
if (!path.isDirectory()) error("The path $path is not a directory")
return NumassDirectorySet(this, path)
}
public fun NumassProtoPlugin.readNumassDirectory(path: String): NumassDirectorySet = readNumassDirectory(Path.of(path))
public suspend fun NumassProtoPlugin.readRepository(path: Path): DataTree<NumassDirectorySet> = DataSource {
Files.walk(path).filter {
it.isDirectory() && it.resolve("meta").exists()
}.forEach { childPath ->
val name = Name(childPath.relativeTo(path).map { segment ->
NameToken(segment.fileName.toString())
})
val value = readNumassDirectory(childPath)
launch {
static(name, value, value.meta)
}
}
//TODO add file watcher
}
public suspend fun NumassProtoPlugin.readRepository(path: String): DataTree<NumassDirectorySet> = readRepository(Path.of(path))
public fun NumassProtoPlugin.readPoint(path: String): NumassPoint = readNumassPointFile(path)
?: error("Can't read numass point at $path")

View File

@ -31,9 +31,6 @@ import ru.inr.mass.data.api.NumassFrame
import ru.inr.mass.data.api.NumassPoint
import space.kscience.dataforge.io.Envelope
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.values.ValueType
import space.kscience.dataforge.values.long
import space.kscience.dataforge.values.string
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.InputStream
@ -87,9 +84,10 @@ internal class ProtoNumassPoint(
override val startTime: Instant
get() {
val startTimeValue = meta["start_time"]?.value
return when{
return when {
startTimeValue == null -> Instant.DISTANT_PAST
startTimeValue.type == ValueType.STRING -> LocalDateTime.parse(startTimeValue.string).toInstant(TimeZone.UTC)
startTimeValue.type == ValueType.STRING -> LocalDateTime.parse(startTimeValue.string)
.toInstant(TimeZone.UTC)
//TODO fix time zones!!!
startTimeValue.type == ValueType.NUMBER -> Instant.fromEpochMilliseconds(startTimeValue.long)
else -> error("Can't decode start time")
@ -116,7 +114,7 @@ internal class ProtoNumassPoint(
override fun toString(): String = "ProtoNumassPoint(index = ${index}, hv = $voltage)"
public companion object {
companion object {
/**
* Get valid data stream utilizing compression if it is present
@ -142,6 +140,7 @@ internal class ProtoNumassPoint(
inflater.end()
ByteArrayInputStream(unzippeddata).use(block)
}
else -> {
data?.read {
block(asInputStream())
@ -149,7 +148,7 @@ internal class ProtoNumassPoint(
}
}
public fun fromEnvelope(envelope: Envelope): ProtoNumassPoint? {
fun fromEnvelope(envelope: Envelope): ProtoNumassPoint? {
if (envelope.data == null) return null
return ProtoNumassPoint(envelope.meta) {
envelope.useData {
@ -180,6 +179,7 @@ public class ProtoNumassBlock(
block.length > 0 -> block.length.nanoseconds
parent?.meta?.get("acquisition_time") != null ->
(parent.meta["acquisition_time"].double ?: (0.0 * 1000)).milliseconds
else -> {
LoggerFactory.getLogger(javaClass)
.error("No length information on block. Trying to infer from first and last events")
@ -221,7 +221,8 @@ public class ProtoNumassBlock(
} else {
ShortArray(shortBuffer.limit()) { shortBuffer.get(it) }
}
FrameType.TQDC2021 -> ShortArray(shortBuffer.limit()){
FrameType.TQDC2021 -> ShortArray(shortBuffer.limit()) {
(shortBuffer.get(it).toUShort().toInt() - Short.MAX_VALUE).toShort()
}
}

View File

@ -18,18 +18,19 @@ package ru.inr.mass.data.proto
import io.ktor.utils.io.core.*
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.invoke
import space.kscience.dataforge.io.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.parseAsName
import java.util.*
public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeFormat {
private fun Tag.toBinary() = Binary(24) {
private fun Tag.toBinary() = Binary {
writeRawString(START_SEQUENCE)
writeRawString("DFNU")
writeShort(metaFormatKey)
@ -70,7 +71,7 @@ public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeForm
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
?: error("Meta format with key ${tag.metaFormatKey} not found")
val meta: Meta = metaFormat.readObject(input.readBinary(tag.metaSize.toInt()))
val meta: Meta = metaFormat.readObjectFrom(input.readBinary(tag.metaSize.toInt()))
val data = input.readBinary(tag.dataSize.toInt())
@ -87,10 +88,10 @@ public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeForm
?: error("Meta format with key ${tag.metaFormatKey} not found")
}
val meta: Meta = metaFormat.readObject(input.readBinary(tag.metaSize.toInt()))
val meta: Meta = metaFormat.readObjectFrom(input.readBinary(tag.metaSize.toInt()))
return PartialEnvelope(meta, 30u + tag.metaSize, tag.dataSize)
return PartialEnvelope(meta, 30 + tag.metaSize.toInt(), tag.dataSize)
}
private data class Tag(
@ -99,17 +100,17 @@ public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeForm
val dataSize: ULong,
)
override fun toMeta(): Meta = Meta {
IOFormat.NAME_KEY put name.toString()
}
// override fun toMeta(): Meta = Meta {
// NAME_KEY put name.toString()
// }
public companion object : EnvelopeFormatFactory {
private const val START_SEQUENCE = "#!"
private const val END_SEQUENCE = "!#\r\n"
override val name: Name = super.name + "numass"
override val name: Name = "envelope.numass".parseAsName()
override fun invoke(meta: Meta, context: Context): EnvelopeFormat {
override fun build(context: Context, meta: Meta): EnvelopeFormat {
val io = context.io
val metaFormatName = meta["name"].string?.let { Name.parse(it) } ?: JsonMetaFormat.name

View File

@ -6,9 +6,10 @@ import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.api.ParentBlock
import ru.inr.mass.data.api.channels
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.meta.ListValue
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.values.ListValue
import java.nio.file.Path
import kotlin.test.assertEquals
@ -16,11 +17,12 @@ class TestNumassDirectory {
val context = Context("numass-test") {
plugin(NumassProtoPlugin)
}
val numassProto = context.fetch(NumassProtoPlugin)
@Test
fun testDanteRead() {
val dataPath = Path.of("src/test/resources", "testData/dante")
val testSet = context.readNumassDirectory(dataPath)
val testSet = numassProto.readNumassDirectory(dataPath)
assertEquals("2018-04-13T22:01:46", testSet.meta["end_time"].string)
assertEquals(ListValue.EMPTY, testSet.meta["comments"]?.value)
assertEquals(31, testSet.points.size)
@ -32,12 +34,12 @@ class TestNumassDirectory {
@Test
fun testTQDCRead() = runBlocking {
val pointPath = Path.of("src/test/resources", "testData/tqdc")
val set: NumassSet = context.readNumassDirectory(pointPath)
val set: NumassSet = numassProto.readNumassDirectory(pointPath)
val point = set.first { it.voltage == 18200.0 }
point.channels.forEach { (channel, block) ->
println("$channel: $block")
if(block is ParentBlock){
block.blocks.toList().forEach{
if (block is ParentBlock) {
block.blocks.toList().forEach {
println("\t${it.channel}:${it.eventsCount}")
}
}

View File

@ -1,13 +1,14 @@
plugins {
kotlin("multiplatform")
id("ru.mipt.npm.gradle.common")
id("space.kscience.gradle.mpp")
`maven-publish`
}
val visionForgeVersion = "0.2.0-dev-24"
val visionForgeVersion: String by rootProject.extra
val production: Boolean by rootProject.extra(false)
kotlin {
js{
js(IR) {
browser {
webpackTask {
this.outputFileName = "js/numass-web.js"
@ -16,17 +17,6 @@ kotlin {
binaries.executable()
}
afterEvaluate {
val jsBrowserDistribution by tasks.getting
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(jsBrowserDistribution)
afterEvaluate {
from(jsBrowserDistribution)
}
}
}
sourceSets {
commonMain {
dependencies {
@ -44,8 +34,26 @@ kotlin {
}
}
kscience{
afterEvaluate {
val distributionTask = if (production) {
tasks.getByName("jsBrowserDistribution")
} else {
tasks.getByName("jsBrowserDevelopmentExecutableDistribution")
}
tasks.getByName<ProcessResources>("jvmProcessResources") {
dependsOn(distributionTask)
from(distributionTask)
include("**/*.js")
if (production) {
include("**/*.map")
}
}
}
kscience {
useSerialization {
json()
}
withContextReceivers()
}

View File

@ -8,28 +8,22 @@ import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionBase
import space.kscience.visionforge.VisionGroupBase
import space.kscience.visionforge.VisionPlugin
import space.kscience.visionforge.plotly.PlotlyPlugin
import kotlin.reflect.KClass
public class NumassCommonPlugin(meta: Meta) : VisionPlugin(meta) {
public class NumassCommonPlugin(meta: Meta = Meta.EMPTY) : VisionPlugin(meta) {
override val tag: PluginTag get() = Companion.tag
public val plotlyPlugin: PlotlyPlugin by require(PlotlyPlugin)
override val visionSerializersModule: SerializersModule get() = numassSerializersModule
public companion object : PluginFactory<NumassCommonPlugin> {
override val tag: PluginTag = PluginTag("numass.common", "ru.inr.mass")
override val type: KClass<NumassCommonPlugin> = NumassCommonPlugin::class
override fun invoke(meta: Meta, context: Context): NumassCommonPlugin = NumassCommonPlugin()
private val numassSerializersModule = SerializersModule {
override fun build(context: Context, meta: Meta): NumassCommonPlugin = NumassCommonPlugin()
internal val numassSerializersModule = SerializersModule {
polymorphic(Vision::class) {
subclass(VisionBase.serializer())
subclass(VisionGroupBase.serializer())
subclass(VisionOfNumassHv.serializer())
subclass(VisionOfNumassPoint.serializer())
subclass(VisionOfNumassHv.serializer())

View File

@ -1,24 +1,23 @@
package ru.inr.mass.data.server
import kotlinx.coroutines.flow.collect
import kotlinx.serialization.Serializable
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.api.NumassSet.Companion.NUMASS_HV_TARGET
import ru.inr.mass.data.api.channels
import ru.inr.mass.data.proto.HVData
import ru.inr.mass.data.proto.HVEntry
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.provider.top
import space.kscience.visionforge.VisionBase
import space.kscience.visionforge.VisionGroupBase
import space.kscience.visionforge.AbstractVision
public typealias SimpleAmplitudeSpectrum = Map<UShort, UInt>
public typealias SimpleAmplitudeSpectrum = Map<Short, UInt>
private suspend fun NumassBlock.simpleAmplitudeSpectrum(): SimpleAmplitudeSpectrum {
val res = mutableMapOf<UShort, UInt>()
internal suspend fun NumassBlock.simpleAmplitudeSpectrum(): SimpleAmplitudeSpectrum {
val res = mutableMapOf<Short, UInt>()
events.collect {
res[it.amplitude] = (res[it.amplitude] ?: 0U) + 1U
}
@ -31,26 +30,26 @@ public class VisionOfNumassPoint(
public val index: Int,
public val voltage: Double,
public val spectra: Map<String, SimpleAmplitudeSpectrum>,
) : VisionBase()
) : AbstractVision()
public suspend fun NumassPoint.toVision(): VisionOfNumassPoint = VisionOfNumassPoint(
meta,
index,
voltage,
getChannels().entries.associate { (k, v) ->
channels.entries.associate { (k, v) ->
k.toString() to v.simpleAmplitudeSpectrum()
}
)
@Serializable
public class VisionOfNumassHv(public val hv: HVData) : VisionBase(), Iterable<HVEntry> {
public class VisionOfNumassHv(public val hv: HVData) : AbstractVision(), Iterable<HVEntry> {
override fun iterator(): Iterator<HVEntry> = hv.iterator()
}
private val VisionOfNumassPoint.token: NameToken get() = NameToken("point", index.toString())
@Serializable
public class VisionOfNumassSet(public val points: List<VisionOfNumassPoint>) : VisionBase() {
public class VisionOfNumassSet(public val points: List<VisionOfNumassPoint>) : AbstractVision() {
// init {
// points.forEach {
// //childrenInternal[it.token] = it
@ -61,6 +60,6 @@ public class VisionOfNumassSet(public val points: List<VisionOfNumassPoint>) : V
public suspend fun NumassSet.toVision(): VisionOfNumassSet = VisionOfNumassSet(points.map { it.toVision() }).apply {
this@toVision.top<HVData>(NUMASS_HV_TARGET).forEach { (key, hv) ->
// set(key, VisionOfNumassHv(hv))
// set(key, VisionOfNumassHv(hv))
}
}

View File

@ -8,17 +8,22 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.plotly.models.LineShape
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.plot
import space.kscience.plotly.plotElement
import space.kscience.plotly.scatter
import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin
import kotlin.reflect.KClass
public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer {
public val client: VisionClient by require(VisionClient)
public val numassCommon: NumassCommonPlugin by require(NumassCommonPlugin)
private val plotly = numassCommon.plotlyPlugin
public val plotly: PlotlyPlugin by require(PlotlyPlugin)
override val tag: PluginTag get() = Companion.tag
@ -27,6 +32,11 @@ public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer {
else -> ElementVisionRenderer.ZERO_RATING
}
override fun content(target: String): Map<Name, Any> = when (target) {
ElementVisionRenderer.TYPE -> mapOf("numass".asName() to this)
else -> super.content(target)
}
override fun render(element: Element, vision: Vision, meta: Meta) {
when (vision) {
is VisionOfNumassHv -> element.append {
@ -47,22 +57,25 @@ public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer {
}
}
}
is VisionOfNumassPoint -> element.append {
h1{ +"Point"}
plot {
h1 { +"Point" }
plotElement {
vision.spectra.forEach { (channel, spectrum) ->
val pairs = spectrum.entries.sortedBy { it.key }
scatter {
name = channel
mode = ScatterMode.lines
line {
shape = LineShape.hv
}
x.numbers = spectrum.keys.map { it.toInt() }
y.numbers = spectrum.values.map { it.toInt() }
x.numbers = pairs.map { it.key.toInt() }
y.numbers = pairs.map { it.value.toInt() }
}
}
}
}
is VisionOfNumassSet -> {}
}
}
@ -71,6 +84,8 @@ public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer {
public companion object : PluginFactory<NumassJsPlugin> {
override val tag: PluginTag = PluginTag("numass.js", "ru.inr.mass")
override val type: KClass<NumassJsPlugin> = NumassJsPlugin::class
override fun invoke(meta: Meta, context: Context): NumassJsPlugin = NumassJsPlugin()
override fun build(context: Context, meta: Meta): NumassJsPlugin = NumassJsPlugin()
}
}

View File

@ -1,53 +0,0 @@
package ru.inr.mass.data.server
import kotlinx.coroutines.runBlocking
import kotlinx.html.div
import kotlinx.html.h1
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.proto.NumassProtoPlugin
import ru.inr.mass.data.proto.readNumassPointFile
import space.kscience.dataforge.context.Context
import space.kscience.visionforge.three.server.close
import space.kscience.visionforge.three.server.serve
import space.kscience.visionforge.three.server.show
import space.kscience.visionforge.visionManager
import java.nio.file.Path
public fun main() {
val context = Context("Numass") {
plugin(NumassProtoPlugin)
plugin(NumassCommonPlugin)
}
val pointPath = Path.of("C:\\Users\\altavir\\Desktop\\p20211122173034(20s).dat")
val point: NumassPoint = context.readNumassPointFile(pointPath)!!
val visionOfNumass = runBlocking {
point.toVision()
}
val server = context.visionManager.serve {
//use client library
useNumassWeb()
//use css
//useCss("css/styles.css")
page {
div("flex-column") {
h1 { +"Satellite detector demo" }
//vision(visionOfNumass)
}
}
}
server.show()
println("Enter 'exit' to close server")
while (readLine() != "exit") {
//
}
server.close()
}

View File

@ -0,0 +1,50 @@
package ru.inr.mass.data.server
import kotlinx.html.div
import kotlinx.html.h1
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.proto.NumassProtoPlugin
import ru.inr.mass.data.proto.readNumassPointFile
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.server.close
import space.kscience.visionforge.server.openInBrowser
import space.kscience.visionforge.server.serve
import space.kscience.visionforge.visionManager
import java.nio.file.Path
public suspend fun main() {
val context = Context("Numass") {
plugin(NumassProtoPlugin)
plugin(NumassCommonPlugin)
}
val numassProto = context.fetch(NumassProtoPlugin)
val pointPath = Path.of("D:\\Work\\Numass\\data\\test\\set_7\\p120(30s)(HV1=13300)")
val point: NumassPoint = numassProto.readNumassPointFile(pointPath)!!
val visionOfNumass = point.toVision()
val server = context.visionManager.serve {
header("numass", VisionPage.scriptHeader("js/numass-web.js"))
page {
div("flex-column") {
h1 { +"Visionforge file demo" }
vision { visionOfNumass }
}
}
}
server.openInBrowser()
println("Enter 'exit' to close server")
while (readLine() != "exit") {
//
}
server.close()
}

View File

@ -4,29 +4,26 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.html.HtmlVisionFragment
import space.kscience.visionforge.html.ResourceLocation
import space.kscience.visionforge.html.page
import space.kscience.visionforge.html.scriptHeader
import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.html.importScriptHeader
import space.kscience.visionforge.makeFile
import space.kscience.visionforge.three.server.VisionServer
import space.kscience.visionforge.three.server.useScript
import java.awt.Desktop
import java.nio.file.Path
public fun VisionServer.useNumassWeb(): Unit {
useScript("js/numass-web.js")
}
@DFExperimental
public fun Context.makeNumassWebFile(
content: HtmlVisionFragment,
path: Path? = null,
title: String = "VisionForge Numass page",
resourceLocation: ResourceLocation = ResourceLocation.SYSTEM,
show: Boolean = true,
content: HtmlVisionFragment,
): Unit {
val actualPath = page(title, content = content).makeFile(path) { actualPath ->
mapOf("numassWeb" to scriptHeader("js/numass-web.js", resourceLocation, actualPath))
val actualPath = VisionPage(this, content = content).makeFile(path) { actualPath: Path ->
mapOf(
"title" to VisionPage.title(title),
"numassWeb" to VisionPage.importScriptHeader("js/numass-web.js", resourceLocation, actualPath)
)
}
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
}

View File

@ -0,0 +1,28 @@
package ru.inr.mass.data.server
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.proto.NumassProtoPlugin
import ru.inr.mass.data.proto.readNumassPointFile
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import java.nio.file.Path
@Suppress("OPT_IN_USAGE")
public suspend fun main() {
val context = Context("Numass") {
plugin(NumassProtoPlugin)
plugin(NumassCommonPlugin)
}
val numassProto = context.fetch(NumassProtoPlugin)
val pointPath = Path.of("D:\\Work\\Numass\\data\\test\\set_7\\p120(30s)(HV1=13300)")
val point: NumassPoint = numassProto.readNumassPointFile(pointPath)!!
val visionOfNumass: VisionOfNumassPoint = point.toVision()
context.makeNumassWebFile {
vision { visionOfNumass }
}
}

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
id("space.kscience.gradle.jvm")
}
val dataforgeVersion: String by rootProject.extra

View File

@ -1,5 +1,5 @@
plugins {
id("ru.mipt.npm.gradle.mpp")
id("space.kscience.gradle.mpp")
`maven-publish`
}

View File

@ -1,6 +1,6 @@
plugins {
id("ru.mipt.npm.gradle.jvm")
id("com.github.johnrengelman.shadow") version "7.1.1"
id("space.kscience.gradle.jvm")
id("com.github.johnrengelman.shadow") version "7.1.2"
`maven-publish`
}
@ -9,7 +9,7 @@ kotlin {
}
val dataforgeVersion: String by rootProject.extra
val plotlyVersion: String by rootProject.extra("0.5.0")
val visionForgeVersion: String by rootProject.extra
val kmathVersion: String by rootProject.extra
val tablesVersion: String by rootProject.extra
@ -18,9 +18,10 @@ dependencies {
implementation(projects.numassModel)
implementation(projects.numassAnalysis)
implementation("space.kscience:dataforge-workspace:$dataforgeVersion")
implementation("space.kscience:plotlykt-jupyter:$plotlyVersion")
implementation("space.kscience:kmath-jupyter:$kmathVersion")
implementation("space.kscience:tables-kt:$tablesVersion")
implementation("space.kscience:visionforge-plotly:$visionForgeVersion")
}
kscience{

View File

@ -5,6 +5,7 @@ import kotlinx.coroutines.runBlocking
import kotlinx.html.*
import kotlinx.html.stream.createHTML
import org.jetbrains.kotlinx.jupyter.api.HTML
import org.jetbrains.kotlinx.jupyter.api.declare
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassFrame
@ -23,7 +24,8 @@ import space.kscience.plotly.toPage
internal class NumassJupyter : JupyterIntegration() {
override fun Builder.onLoaded() {
repositories(
"https://repo.kotlin.link"
"https://repo.kotlin.link",
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
)
import(
@ -39,6 +41,9 @@ internal class NumassJupyter : JupyterIntegration() {
import<Numass>()
onLoaded {
declare("Numass" to Numass, "workspace" to Numass.workspace)
}
render<NumassBlock> {
HTML(Plotly.plotNumassBlock(it).toPage().render())
@ -60,7 +65,7 @@ internal class NumassJupyter : JupyterIntegration() {
}
render<DataTree<NumassDirectorySet>> { tree ->
HTML(createHTML().div { numassTree(tree)})
HTML(createHTML().div { numassTree(tree) })
}
}
}
@ -68,7 +73,7 @@ internal class NumassJupyter : JupyterIntegration() {
private fun FlowContent.numassTree(tree: DataTree<NumassDirectorySet>) {
ul {
runBlocking {
tree.items().forEach { (token, treeItem) ->
tree.items.forEach { (token, treeItem) ->
li {
p { +token.toString() }
when (treeItem) {

View File

@ -5,13 +5,13 @@ import ru.inr.mass.workspace.Numass.readRepository
import ru.inr.mass.workspace.plotNumassSet
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.await
import space.kscience.dataforge.data.getData
import space.kscience.dataforge.data.get
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
suspend fun main() {
val repo: DataTree<NumassDirectorySet> = readRepository("D:\\Work\\Numass\\data\\2018_04")
val testSet = repo.getData("Adiabacity_19.set_3")?.await() ?: error("Not found")
val testSet = repo["Adiabacity_19.set_3"]?.await() ?: error("Not found")
Plotly.plotNumassSet(testSet).makeFile()
}

View File

@ -85,7 +85,7 @@ suspend fun main() {
val hv = 16900.0
//select point number 2 (U = 16900 V) from each directory
val points: Map<NameToken, NumassPoint?> = repo.items().mapValues {
val points: Map<NameToken, NumassPoint?> = repo.items.mapValues {
val directory = it.value.data?.await()
val point = directory?.points?.find { point -> point.voltage == hv }
point

View File

@ -1,20 +1,22 @@
package ru.inr.mass.scripts
import kotlinx.coroutines.flow.collect
import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.workspace.Numass.readRepository
import space.kscience.dataforge.data.DataSource
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.filter
import space.kscience.dataforge.data.forEach
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.string
suspend fun main() {
val repo: DataTree<NumassDirectorySet> = readRepository("D:\\Work\\Numass\\data\\2018_04")
val filtered = repo.filter { _, data ->
val operator by data.meta.string()
val filtered: DataSource<NumassDirectorySet> = repo.filter { _, meta: Meta ->
val operator by meta.string()
operator?.startsWith("Vas") ?: false
}
filtered.flowData().collect {
filtered.forEach{
println(it)
}
}

View File

@ -3,54 +3,41 @@ package ru.inr.mass.workspace
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.data.proto.readNumassDirectory
import ru.inr.mass.data.proto.readNumassPointFile
import space.kscience.dataforge.data.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import java.nio.file.Files
import ru.inr.mass.data.proto.*
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.workspace.Workspace
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.relativeTo
import kotlin.streams.toList
object Numass {
fun readDirectory(path: String): NumassDirectorySet = NUMASS.context.readNumassDirectory(path)
@OptIn(ExperimentalPathApi::class)
fun readRepository(path: Path): DataTree<NumassDirectorySet> = runBlocking {
ActiveDataTree {
@Suppress("BlockingMethodInNonBlockingContext")
withContext(Dispatchers.IO) {
Files.walk(path).filter {
it.isDirectory() && it.resolve("meta").exists()
}.toList().forEach { childPath ->
val name = Name(childPath.relativeTo(path).map { segment ->
NameToken(segment.fileName.toString())
})
val value = NUMASS.context.readNumassDirectory(childPath)
static(name, value, value.meta)
}
}
//TODO add file watcher
val workspace = Workspace {
context {
plugin(NumassWorkspacePlugin)
}
}
fun readRepository(path: String): DataTree<NumassDirectorySet> = readRepository(Path.of(path))
val context get() = workspace.context
fun readPoint(path: String): NumassPoint = NUMASS.context.readNumassPointFile(path)
?: error("Can't read numass point at $path")
}
val numassProto by lazy { context.fetch(NumassProtoPlugin) }
fun readPoint(path: Path): NumassPoint =
numassProto.readNumassPointFile(path) ?: error("Can't read numass point at $path")
fun readPoint(path: String): NumassPoint =
numassProto.readNumassPointFile(path) ?: error("Can't read numass point at $path")
fun readDirectory(path: Path): NumassDirectorySet = numassProto.readNumassDirectory(path)
fun readDirectory(path: String): NumassDirectorySet = numassProto.readNumassDirectory(path)
fun readRepository(path: Path): DataTree<NumassDirectorySet> =
runBlocking(Dispatchers.IO) { numassProto.readRepository(path) }
fun readRepository(path: String): DataTree<NumassDirectorySet> =
runBlocking(Dispatchers.IO) { numassProto.readRepository(path) }
operator fun DataSet<NumassSet>.get(name: String): NumassSet? = runBlocking {
getData(Name.parse(name))?.await()
}
fun NumassBlock.listFrames() = runBlocking { frames.toList() }

View File

@ -1,118 +0,0 @@
package ru.inr.mass.workspace
import ru.inr.mass.data.proto.NumassProtoPlugin
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.values.Value
import space.kscience.dataforge.workspace.TaskReference
import space.kscience.dataforge.workspace.WorkspacePlugin
import space.kscience.dataforge.workspace.task
import space.kscience.tables.Table
import kotlin.reflect.KClass
class NumassPlugin : WorkspacePlugin() {
override val tag: PluginTag get() = Companion.tag
val numassProtoPlugin by require(NumassProtoPlugin)
// val select by task<NumassSet>(
// descriptor = MetaDescriptor {
// info = "Select data from workspace data pool"
// value("forward", ValueType.BOOLEAN) {
// info = "Select only forward or only backward sets"
// }
// }
// ) {
// val forward = meta["forward"]?.boolean
// val filtered = workspace.data.select<NumassSet> { _, meta ->
// when (forward) {
// true -> meta["iteration_info.reverse"]?.boolean?.not() ?: false
// false -> meta["iteration_info.reverse"]?.boolean ?: false
// else -> true
// }
// }
//
// emit(Name.EMPTY, filtered)
// }
//
// val analyze by task<Table<Value>>(
// MetaDescriptor {
// info = "Count the number of events for each voltage and produce a table with the results"
// }
// ) {
// pipeFrom(select) { set, name, meta ->
// val res = SmartAnalyzer.analyzeSet(set, meta["analyzer"] ?: Meta.EMPTY)
// val outputMeta = meta.toMutableMeta().apply {
// "data" put set.meta
// }
// // context.output.render(res, stage = "numass.analyze", name = name, meta = outputMeta)
// res
// }
// }
val monitorTableTask: TaskReference<Table<Value>> by task {
// descriptor {
// value("showPlot", types = listOf(ValueType.BOOLEAN), info = "Show plot after complete")
// value("monitorPoint", types = listOf(ValueType.NUMBER), info = "The voltage for monitor point")
// }
// model { meta ->
// dependsOn(selectTask, meta)
//// if (meta.getBoolean("monitor.correctForThreshold", false)) {
//// dependsOn(subThresholdTask, meta, "threshold")
//// }
// configure(meta.getMetaOrEmpty("monitor"))
// configure {
// meta.useMeta("analyzer") { putNode(it) }
// setValue("@target", meta.getString("@target", meta.name))
// }
// }
// join<NumassSet, Table> { data ->
// val monitorVoltage = meta.getDouble("monitorPoint", 16000.0);
// val analyzer = SmartAnalyzer()
// val analyzerMeta = meta.getMetaOrEmpty("analyzer")
//
// //val thresholdCorrection = da
// //TODO add separator labels
// val res = ListTable.Builder("timestamp", "count", "cr", "crErr", "index", "set")
// .rows(
// data.values.stream().flatMap { set ->
// set.points.stream()
// .filter { it.voltage == monitorVoltage }
// .parallel()
// .map { point ->
// analyzer.analyzeParent(point, analyzerMeta).edit {
// "index" to point.index
// "set" to set.name
// }
// }
// }
//
// ).build()
//
// if (meta.getBoolean("showPlot", true)) {
// val plot = DataPlot.plot(name, res, Adapters.buildXYAdapter("timestamp", "cr", "crErr"))
// context.plot(plot, name, "numass.monitor") {
// "xAxis.title" to "time"
// "xAxis.type" to "time"
// "yAxis.title" to "Count rate"
// "yAxis.units" to "Hz"
// }
//
// ((context.output["numass.monitor", name] as? PlotOutput)?.frame as? JFreeChartFrame)?.addSetMarkers(data.values)
// }
//
// context.output.render(res, stage = "numass.monitor", name = name, meta = meta)
//
// return@join res;
// }
}
companion object : PluginFactory<NumassPlugin> {
override val tag: PluginTag = PluginTag("numass", "ru.mipt.npm")
override val type: KClass<out NumassPlugin> = NumassPlugin::class
override fun invoke(meta: Meta, context: Context): NumassPlugin = NumassPlugin()
}
}

View File

@ -0,0 +1,134 @@
package ru.inr.mass.workspace
import ru.inr.mass.data.analysis.NumassAnalyzerParameters
import ru.inr.mass.data.analysis.NumassEventExtractor
import ru.inr.mass.data.analysis.TimeAnalyzer
import ru.inr.mass.data.analysis.analyzeSet
import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.proto.NumassProtoPlugin
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.data.filterByType
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.value
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.workspace.WorkspacePlugin
import space.kscience.dataforge.workspace.pipeFrom
import space.kscience.dataforge.workspace.task
import space.kscience.tables.Table
import kotlin.reflect.KClass
class NumassWorkspacePlugin : WorkspacePlugin() {
override val tag: PluginTag get() = Companion.tag
val numassProtoPlugin by require(NumassProtoPlugin)
val selectSets by task<NumassSet>(
descriptor = MetaDescriptor {
info = "Select data from workspace data pool"
value("forward", ValueType.BOOLEAN) {
info = "Select only forward or only backward sets"
}
}
) {
val forward = meta["forward"]?.boolean
val filtered = workspace.data.filterByType<NumassSet> { _, meta ->
when (forward) {
true -> meta["iteration_info.reverse"]?.boolean?.not() ?: false
false -> meta["iteration_info.reverse"]?.boolean ?: false
else -> true
}
}
node(Name.EMPTY, filtered)
}
val analyzeSets by task<Table<Value>>(
MetaDescriptor {
info = "Count the number of events for each voltage and produce a table with the results"
}
) {
pipeFrom(selectSets) { set, name, meta ->
val res = TimeAnalyzer(NumassEventExtractor.EVENTS_ONLY).analyzeSet(
set,
NumassAnalyzerParameters.read(meta["analyzer"] ?: Meta.EMPTY)
)
val outputMeta = meta.toMutableMeta().apply {
"data" put set.meta
}
// context.output.render(res, stage = "numass.analyze", name = name, meta = outputMeta)
res
}
}
//
// val monitorTableTask: TaskReference<Table<Value>> by task(
// MetaDescriptor {
// value("showPlot", type = ValueType.BOOLEAN) {
// info = "Show plot after complete"
// }
// value("monitorPoint", type = ValueType.NUMBER) {
// info = "The voltage for monitor point"
// }
// }
// ) {
// val data = from(selectSets)
//// model { meta ->
//// dependsOn(selectTask, meta)
////// if (meta.getBoolean("monitor.correctForThreshold", false)) {
////// dependsOn(subThresholdTask, meta, "threshold")
////// }
//// configure(meta.getMetaOrEmpty("monitor"))
//// configure {
//// meta.useMeta("analyzer") { putNode(it) }
//// setValue("@target", meta.getString("@target", meta.name))
//// }
//// }
//
// val monitorVoltage = meta["monitorPoint"].double ?: 16000.0
// val analyzer = TimeAnalyzer()
// val analyzerMeta = meta["analyzer"]
//
// //val thresholdCorrection = da
// //TODO add separator labels
// val res = ListTable.Builder("timestamp", "count", "cr", "crErr", "index", "set")
// .rows(
// data.values.stream().flatMap { set ->
// set.points.stream()
// .filter { it.voltage == monitorVoltage }
// .parallel()
// .map { point ->
// analyzer.analyzeParent(point, analyzerMeta).edit {
// "index" to point.index
// "set" to set.name
// }
// }
// }
//
// ).build()
//
// if (meta["showPlot"].boolean ?: true) {
// val plot = DataPlot.plot(name, res, Adapters.buildXYAdapter("timestamp", "cr", "crErr"))
// context.plot(plot, name, "numass.monitor") {
// "xAxis.title" to "time"
// "xAxis.type" to "time"
// "yAxis.title" to "Count rate"
// "yAxis.units" to "Hz"
// }
//
// ((context.output["numass.monitor", name] as? PlotOutput)?.frame as? JFreeChartFrame)?.addSetMarkers(data.values)
// }
//
// context.output.render(res, stage = "numass.monitor", name = name, meta = meta)
//
// data(Name.EMPTY, res)
// }
companion object : PluginFactory<NumassWorkspacePlugin> {
override val tag: PluginTag = PluginTag("numass", "ru.mipt.npm")
override val type: KClass<out NumassWorkspacePlugin> = NumassWorkspacePlugin::class
override fun build(context: Context, meta: Meta): NumassWorkspacePlugin = NumassWorkspacePlugin()
}
}

View File

@ -10,8 +10,8 @@ import ru.inr.mass.data.analysis.timeHistogram
import ru.inr.mass.data.api.*
import ru.inr.mass.data.proto.HVData
import ru.inr.mass.data.proto.NumassDirectorySet
import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.double
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.double
import space.kscience.kmath.domains.center
import space.kscience.kmath.histogram.Histogram1D
import space.kscience.kmath.misc.UnstableKMathAPI

View File

@ -1,10 +0,0 @@
package ru.inr.mass.workspace
import ru.inr.mass.data.proto.NumassProtoPlugin
import space.kscience.dataforge.workspace.Workspace
val NUMASS = Workspace {
context{
plugin(NumassProtoPlugin)
}
}

View File

@ -15,10 +15,10 @@ pluginManagement {
}
plugins {
id("ru.mipt.npm.gradle.project") version toolsVersion
id("ru.mipt.npm.gradle.mpp") version toolsVersion
id("ru.mipt.npm.gradle.jvm") version toolsVersion
id("ru.mipt.npm.gradle.js") version toolsVersion
id("space.kscience.gradle.project") version toolsVersion
id("space.kscience.gradle.mpp") version toolsVersion
id("space.kscience.gradle.jvm") version toolsVersion
id("space.kscience.gradle.js") version toolsVersion
}
}
@ -34,7 +34,7 @@ dependencyResolutionManagement {
versionCatalogs {
create("npmlibs") {
from("ru.mipt.npm:version-catalog:$toolsVersion")
from("space.kscience:version-catalog:$toolsVersion")
}
}
}
@ -43,7 +43,7 @@ include(
":numass-data-model",
":numass-analysis",
":numass-data-proto",
//":numass-data-server",
":numass-data-server",
":numass-workspace",
":numass-model",
//":numass-detector-client"