Compare commits

...

34 Commits

Author SHA1 Message Date
daca7ec262 feat(tests): add trap and rear wall contribution graphs 2025-04-03 14:44:03 +03:00
73f615c51e feat(trap-plot): add Nozik trap function for comparison 2025-04-03 14:42:00 +03:00
fe6f5e4e01 feat(trap): relaxed range checking +200 V from upper border 2025-04-03 14:40:29 +03:00
1d164bca3c fix(fit-custom): display correct counts in fit output 2025-04-03 14:38:46 +03:00
0dded083ba merge with dev 2025-03-17 11:06:37 +03:00
1764eef183 Update code to be used with latest ecosystem versions. 2025-03-16 16:43:14 +03:00
f76de70cd2 [enh] updating kscience libs (intermediate commit) 2025-03-14 15:05:24 +03:00
1373bd73bd [enh] make SterileNeutrinoSpectrumFast with parallel integration 2025-03-14 13:25:20 +03:00
cb720ca89e [enh] update adiabacy 2025-03-13 15:58:55 +03:00
d1a7b5367d [enh] change trap/reartrap interpolation to bilinear (for speed) 2025-03-13 11:06:01 +03:00
21c5fd3a5c [enh] update rearwall to correct 2025-03-13 11:04:49 +03:00
5a33e191bd [fix] make linter happy 2025-03-11 13:30:28 +03:00
ebd3ab57b8 [enh] refactor + remove deprecated scripts 2025-03-11 13:27:45 +03:00
e60bcfc013 [fix] update rwall to 10+ keV 2025-03-10 12:06:49 +03:00
b136c3b6f4 [enh] add FitCustom (application.kt) that can work with GraalVM 2025-03-05 15:32:48 +03:00
9f88cf927e [enh] unstructured: save files to repo
- turn back application (binary for Vlad)
- make fit params configurable
- update wall simulation numbers
- update trapping
2025-03-03 15:21:16 +03:00
7d79fb977e [enh] big unstructured update
- add trapping 2024 table function
- add rear trapping table function
- add rear wall function
- add test plot scripts
- add adiabacity 2024 table function
- add custom fit with rear wall
2024-07-12 14:25:02 +03:00
6650353683 add cli parser to fit.kt 2023-11-29 12:57:15 +03:00
232669af80 Updates and fixes 2023-10-25 20:22:20 +03:00
bc77af263b merge with dev (update to Kotlin 1.9.0) 2023-10-09 15:29:00 +03:00
7659bc41a0 Merge remote-tracking branch 'origin/dev' into feature/fit-analysis
# Conflicts:
#	numass-data-proto/src/gen/kotlin/ru/inr/mass/data/proto/Point.kt
#	numass-workspace/src/main/kotlin/ru/inr/mass/scripts/fit.kt
2023-10-09 14:55:39 +03:00
b7618cc08f update build versions 2023-10-09 13:35:39 +03:00
f67157b953 optimization 2023-10-03 14:58:16 +03:00
5fcff41db6 model correction 2023-07-09 13:53:13 +03:00
bbfa0483b6 update version 2023-01-24 21:22:05 +03:00
047551fef7 update version 2023-01-24 21:10:16 +03:00
43d79db6bb Fix derivative for the spectrum and introduce fit example 2023-01-24 21:07:04 +03:00
26f5e7461c Merge branch 'feature/data-viewer' into dev
# Conflicts:
#	build.gradle.kts
#	gradle.properties
#	gradle/wrapper/gradle-wrapper.properties
#	kotlin-js-store/yarn.lock
#	numass-analysis/build.gradle.kts
#	numass-data-proto/build.gradle.kts
#	numass-data-server/build.gradle.kts
#	numass-workspace/build.gradle.kts
#	numass-workspace/src/main/kotlin/ru/inr/mass/workspace/Numass.kt
#	numass-workspace/src/main/kotlin/ru/inr/mass/workspace/NumassPlugin.kt
#	settings.gradle.kts
2023-01-24 15:34:40 +03:00
64bae18644 Add explicit path to repository in viewer 2023-01-24 15:27:14 +03:00
cf02b2d8ba Add fit demo (not working yet) 2023-01-24 13:05:38 +03:00
d9b4707da1 Update versions 2023-01-24 12:08:29 +03:00
17d681bd42
Add response type 2022-12-06 22:51:09 +03:00
e95f73d94d
Working on data viewer UI 2022-12-06 22:49:02 +03:00
4c67d8b0a0
Cloud read 2022-03-08 23:25:23 +03:00
69 changed files with 2665 additions and 1697 deletions
.gitignorebuild.gradle.ktsgradle.properties
gradle/wrapper
numass-analysis
numass-data-model
numass-data-proto
build.gradle.kts
src
gen/kotlin/ru/inr/mass/data/proto
main/kotlin/ru/inr/mass/data/proto
numass-data-server
build.gradle.kts
src
commonMain/kotlin/ru/inr/mass/data/server
jsMain/kotlin/ru/inr/mass/data/server
jvmMain/kotlin/ru/inr/mass/data/server
numass-model
numass-workspace
settings.gradle.kts

152
.gitignore vendored

@ -1,10 +1,154 @@
.kotlin
gradlew
gradlew.bat
.idea/
*.iws
out/
.gradle
build/
/notebooks/.ipynb_checkpoints
/kotlin-js-store/
!gradle-wrapper.jar
# Created by https://www.toptal.com/developers/gitignore/api/kotlin,intellij+all,gradle
# Edit at https://www.toptal.com/developers/gitignore?templates=kotlin,intellij+all,gradle
### Intellij+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij+all Patch ###
# Ignore everything but code style settings and run configurations
# that are supposed to be shared within teams.
.idea/*
!.idea/codeStyles
!.idea/runConfigurations
### Kotlin ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
### Gradle ###
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
# Cache of project
.gradletasknamecache
# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Gradle Patch ###
# Java heap dump
*.hprof
# End of https://www.toptal.com/developers/gitignore/api/kotlin,intellij+all,gradle

@ -1,3 +1,6 @@
import space.kscience.gradle.useApache2Licence
import space.kscience.gradle.useSPCTeam
plugins {
id("space.kscience.gradle.project")
}
@ -10,17 +13,22 @@ allprojects {
}
group = "ru.inr.mass"
version = "0.1.3"
version = "0.1.5"
}
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")
val dataforgeVersion by extra("0.10.1")
val tablesVersion: String by extra("0.4.1")
val kmathVersion by extra("0.4.2")
val visionForgeVersion: String by rootProject.extra("0.4.2")
ksciencePublish{
space("https://maven.pkg.jetbrains.space/mipt-npm/p/numass/maven")
ksciencePublish {
pom("https://spc.jetbrains.space/p/numass/repositories/numass/") {
useApache2Licence()
useSPCTeam()
}
//space("https://maven.pkg.jetbrains.space/spc/p/numass/maven")
//repository("spc","https://maven.sciprog.center/spc")
}
apiValidation {

@ -5,11 +5,11 @@
kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.jupyter.add.scanner=false
kotlin.js.compiler=ir
org.gradle.configureondemand=true
org.gradle.parallel=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G
toolsVersion=0.13.3-kotlin-1.7.20
toolsVersion=0.16.1-kotlin-2.1.0
compose.version=1.7.3

Binary file not shown.

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

@ -8,7 +8,9 @@ val dataforgeVersion: String by rootProject.extra
val kmathVersion: String by rootProject.extra
val tablesVersion: String by rootProject.extra
kotlin.sourceSets {
kscience {
jvm()
js()
commonMain {
dependencies {
api(projects.numass.numassDataModel)
@ -20,7 +22,7 @@ kotlin.sourceSets {
}
}
}
//
//kscience{
// useAtomic()
//}

@ -1,262 +0,0 @@
/*
* Copyright 2017 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 ru.inr.mass.data.analysis
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import ru.inr.mass.data.api.*
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.tables.ColumnHeader
import space.kscience.tables.MetaRow
import space.kscience.tables.RowTable
import space.kscience.tables.Table
import kotlin.properties.ReadWriteProperty
public fun MutableMetaProvider.uIntRange(
default: UIntRange = 0U..Int.MAX_VALUE.toUInt(),
key: Name? = null,
): ReadWriteProperty<Any?, UIntRange> = value(
key,
reader = { value ->
val (l, r) = value?.list ?: return@value default
l.int.toUInt()..r.int.toUInt()
},
writer = { range ->
ListValue(range.first.toInt(), range.last.toInt())
}
)
public class NumassAnalyzerResult : Scheme() {
public var count: Long by long(0L, NumassAnalyzer.count.name.asName())
public var countRate: Double by double(0.0, NumassAnalyzer.cr.name.asName())
public var countRateError: Double by double(0.0, NumassAnalyzer.crError.name.asName())
public var length: Double by double(0.0, NumassAnalyzer.length.name.asName())
public var voltage: Double? by double(HV_KEY.asName())
public var parameters: NumassAnalyzerParameters by spec(NumassAnalyzerParameters)
public companion object : SchemeSpec<NumassAnalyzerResult>(::NumassAnalyzerResult)
}
/**
* A general raw data analysis utility. Could have different implementations
* Created by darksnake on 06-Jul-17.
*/
public abstract class NumassAnalyzer {
public abstract val extractor: NumassEventExtractor
/**
* Perform analysis on block. The values for count rate, its error and point length in nanos must
* exist, but occasionally additional values could also be presented.
*
* @param block
* @return
*/
protected abstract suspend fun analyzeInternal(
block: NumassBlock,
parameters: NumassAnalyzerParameters,
): NumassAnalyzerResult
/**
* Analysis result for point including hv information
* @param point
* @param parameters
* @return
*/
public suspend fun analyze(
point: ParentBlock,
parameters: NumassAnalyzerParameters = NumassAnalyzerParameters.empty(),
): NumassAnalyzerResult {
val res = analyzeInternal(point, parameters)
if (point is NumassPoint) {
res.voltage = point.voltage
}
res.parameters = parameters
return res
}
protected suspend fun NumassBlock.flowFilteredEvents(
parameters: NumassAnalyzerParameters,
): Flow<NumassEvent> {
val window = parameters.window
return extractor.extract(this).filter { it.amplitude.toUInt() in window }
}
public companion object {
public val channel: ColumnHeader<Value> by ColumnHeader.value(ValueType.NUMBER)
public val count: ColumnHeader<Value> by ColumnHeader.value(ValueType.NUMBER)
public val length: ColumnHeader<Value> by ColumnHeader.value(ValueType.NUMBER)
public val cr: ColumnHeader<Value> by ColumnHeader.value(ValueType.NUMBER)
public val crError: ColumnHeader<Value> by ColumnHeader.value(ValueType.NUMBER)
public val window: ColumnHeader<Value> by ColumnHeader.value(ValueType.LIST)
public val timestamp: ColumnHeader<Value> by ColumnHeader.value(ValueType.NUMBER)
//
// val AMPLITUDE_ADAPTER: ValuesAdapter = Adapters.buildXYAdapter(CHANNEL_KEY, COUNT_RATE_KEY)
public val MAX_CHANNEL: UInt = 10000U
}
}
/**
* Analyze the whole set. And return results as a table
*
* @param set
* @param config
* @return
*/
public suspend fun NumassAnalyzer.analyzeSet(
set: NumassSet,
config: NumassAnalyzerParameters = NumassAnalyzerParameters.empty(),
): Table<Value> = RowTable(
NumassAnalyzer.length,
NumassAnalyzer.count,
NumassAnalyzer.cr,
NumassAnalyzer.crError,
// NumassAnalyzer.window,
// NumassAnalyzer.timestamp
) {
set.points.forEach { point ->
addRow(MetaRow(analyze(point, config).meta))
}
}
//
//public suspend fun NumassAnalyzer.getAmplitudeSpectrum(
// block: NumassBlock,
// range: UIntRange = 0U..MAX_CHANNEL,
// config: Meta = Meta.EMPTY,
//): Table<Value> {
// val seconds = block.getLength().inWholeMilliseconds.toDouble() / 1000.0
// return getEvents(block, config).getAmplitudeSpectrum(seconds, range)
//}
//
///**
// * Calculate number of counts in the given channel
// *
// * @param spectrum
// * @param loChannel
// * @param upChannel
// * @return
// */
//internal fun Table<Value>.countInWindow(loChannel: Short, upChannel: Short): Long = rows.filter { row ->
// row[channel]?.int in loChannel until upChannel
//}.sumOf { it[count]?.long ?: 0L }
//
///**
// * Calculate the amplitude spectrum for a given block. The s
// *
// * @param this@getAmplitudeSpectrum
// * @param length length in seconds, used for count rate calculation
// * @param config
// * @return
// */
//private suspend fun Flow<NumassEvent>.getAmplitudeSpectrum(
// length: Double,
// range: UIntRange = 0U..MAX_CHANNEL,
//): Table<Value> {
//
// //optimized for fastest computation
// val spectrum: MutableMap<UInt, LongCounter> = HashMap()
// collect { event ->
// val channel = event.amplitude
// spectrum.getOrPut(channel.toUInt()) {
// LongCounter()
// }.add(1L)
// }
//
// return RowTable<Value>(channel, count, cr, crError) {
// range.forEach { ch ->
// val countValue: Long = spectrum[ch]?.value ?: 0L
// valueRow(
// channel to ch,
// count to countValue,
// cr to (countValue.toDouble() / length),
// crError to sqrt(countValue.toDouble()) / length
// )
// }
// }
//}
//
///**
// * Apply window and binning to a spectrum. Empty bins are filled with zeroes
// */
//private fun Table<Value>.withBinning(
// binSize: UInt, range: UIntRange = 0U..MAX_CHANNEL,
//): Table<Value> = RowTable<Value>(channel, count, cr, crError) {
//// var chan = loChannel
//// ?: this.getColumn(NumassAnalyzer.CHANNEL_KEY).stream().mapToInt { it.int }.min().orElse(0)
////
//// val top = upChannel
//// ?: this.getColumn(NumassAnalyzer.CHANNEL_KEY).stream().mapToInt { it.int }.max().orElse(1)
//
// val binSizeColumn = newColumn<Value>("binSize")
//
// var chan = range.first
//
// while (chan < range.last - binSize) {
// val counter = LongCounter()
// val countRateCounter = Counter.real()
// val countRateDispersionCounter = Counter.real()
//
// val binLo = chan
// val binUp = chan + binSize
//
// rows.filter { row ->
// (row[channel]?.int ?: 0U) in binLo until binUp
// }.forEach { row ->
// counter.add(row[count]?.long ?: 0L)
// countRateCounter.add(row[cr]?.double ?: 0.0)
// countRateDispersionCounter.add(row[crError]?.double?.pow(2.0) ?: 0.0)
// }
// val bin = min(binSize, range.last - chan)
//
// valueRow(
// channel to (chan.toDouble() + bin.toDouble() / 2.0),
// count to counter.value,
// cr to countRateCounter.value,
// crError to sqrt(countRateDispersionCounter.value),
// binSizeColumn to bin
// )
// chan += binSize
// }
//}
//
///**
// * Subtract reference spectrum.
// */
//private fun subtractAmplitudeSpectrum(
// sp1: Table<Value>, sp2: Table<Value>,
//): Table<Value> = RowTable<Value>(channel, cr, crError) {
// sp1.rows.forEach { row1 ->
// val channelValue = row1[channel]?.double
// val row2 = sp2.rows.find { it[channel]?.double == channelValue } ?: MapRow(emptyMap())
//
// val value = max((row1[cr]?.double ?: 0.0) - (row2[cr]?.double ?: 0.0), 0.0)
// val error1 = row1[crError]?.double ?: 0.0
// val error2 = row2[crError]?.double ?: 0.0
// val error = sqrt(error1 * error1 + error2 * error2)
// valueRow(channel to channelValue, cr to value, crError to error)
// }
//}

@ -1,46 +0,0 @@
package ru.inr.mass.data.analysis
import space.kscience.dataforge.meta.*
public class TimeAnalyzerParameters : Scheme() {
public enum class AveragingMethod {
ARITHMETIC,
WEIGHTED,
GEOMETRIC
}
public var value: Int? by int()
/**
* The relative fraction of events that should be removed by time cut
*/
public var crFraction: Double? by double()
public var min: Double by double(0.0)
public var crMin: Double by double(0.0)
/**
* The number of events in chunk to split the chain into. If null, no chunks are used
*/
public var chunkSize: Int? by int()
public var inverted: Boolean by boolean(true)
public var sortEvents: Boolean by boolean(false)
/**
* Chunk averaging method
*/
public var averagingMethod: AveragingMethod by enum(AveragingMethod.WEIGHTED)
public companion object : SchemeSpec<TimeAnalyzerParameters>(::TimeAnalyzerParameters)
}
public class NumassAnalyzerParameters : Scheme() {
public var deadTime: Double by double(0.0)
public var window: UIntRange by uIntRange()
public var t0: TimeAnalyzerParameters by spec(TimeAnalyzerParameters)
public companion object : SchemeSpec<NumassAnalyzerParameters>(::NumassAnalyzerParameters)
}

@ -16,14 +16,12 @@
//
package ru.inr.mass.data.analysis
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
import ru.inr.mass.data.analysis.TimeAnalyzerParameters.AveragingMethod
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassEvent
import ru.inr.mass.data.api.ParentBlock
import space.kscience.kmath.streaming.asFlow
import space.kscience.kmath.streaming.chunked
import space.kscience.kmath.structures.Buffer
import kotlin.math.*
@ -31,6 +29,7 @@ import kotlin.math.*
* An analyzer which uses time information from events
* Created by darksnake on 11.07.2017.
*/
@OptIn(ExperimentalCoroutinesApi::class)
public open class TimeAnalyzer(
override val extractor: NumassEventExtractor = NumassEventExtractor.EVENTS_ONLY,
) : NumassAnalyzer() {
@ -60,7 +59,7 @@ public open class TimeAnalyzer(
// }
else -> block.flowFilteredEvents(parameters)
.byPairs(parameters.t0.inverted)
.chunked(chunkSize, Buffer.Companion::auto)
.chunked(chunkSize)
.map { it.asFlow().analyze(t0) }
.toList()
.combineResults(parameters.t0.averagingMethod)

@ -6,7 +6,11 @@ plugins {
val dataforgeVersion: String by rootProject.extra
kotlin.sourceSets {
kscience{
jvm()
js()
useSerialization()
commonMain {
dependencies {
api("space.kscience:dataforge-context:$dataforgeVersion")
@ -14,15 +18,14 @@ kotlin.sourceSets {
api("org.jetbrains.kotlinx:kotlinx-datetime:${space.kscience.gradle.KScienceVersions.dateTimeVersion}")
}
}
jvmMain{
}
kotlin.sourceSets{
getByName("jvmMain"){
dependencies{
api("ch.qos.logback:logback-classic:1.2.3")
}
}
}
kscience{
useSerialization()
}

@ -1,6 +1,6 @@
plugins {
id("space.kscience.gradle.jvm")
id("com.squareup.wire") version "4.4.1"
id("com.squareup.wire") version "5.3.1"
`maven-publish`
}

@ -1,5 +1,10 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source: ru.inr.mass.data.proto.Point in numass-proto.proto
@file:Suppress(
"DEPRECATION",
"RUNTIME_ANNOTATION_NOT_SUPPORTED",
)
package ru.inr.mass.`data`.proto
import com.squareup.wire.*
@ -19,6 +24,7 @@ public class Point(
tag = 1,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel#ADAPTER",
label = WireField.Label.REPEATED,
schemaIndex = 0,
)
public val channels: List<Channel> = immutableCopyOf("channels", channels)
@ -26,10 +32,9 @@ public class Point(
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")
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 {
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Point) return false
if (unknownFields != other.unknownFields) return false
@ -37,7 +42,7 @@ public class Point(
return true
}
public override fun hashCode(): Int {
override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
@ -47,14 +52,13 @@ public class Point(
return result
}
public override fun toString(): String {
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 fun copy(channels: List<Channel> = this.channels, unknownFields: ByteString = this.unknownFields): Point = Point(channels, unknownFields)
public companion object {
@JvmField
@ -66,23 +70,23 @@ public class Point(
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Point): Int {
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 {
override fun encode(writer: ProtoWriter, `value`: Point) {
Channel.ADAPTER.asRepeated().encodeWithTag(writer, 1, value.channels)
writer.writeBytes(value.unknownFields)
}
public override fun encode(writer: ReverseProtoWriter, `value`: Point): Unit {
override fun encode(writer: ReverseProtoWriter, `value`: Point) {
writer.writeBytes(value.unknownFields)
Channel.ADAPTER.asRepeated().encodeWithTag(writer, 1, value.channels)
}
public override fun decode(reader: ProtoReader): Point {
override fun decode(reader: ProtoReader): Point {
val channels = mutableListOf<Channel>()
val unknownFields = reader.forEachTag { tag ->
when (tag) {
@ -96,7 +100,7 @@ public class Point(
)
}
public override fun redact(`value`: Point): Point = value.copy(
override fun redact(`value`: Point): Point = value.copy(
channels = value.channels.redactElements(Channel.ADAPTER),
unknownFields = ByteString.EMPTY
)
@ -116,6 +120,7 @@ public class Point(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
schemaIndex = 0,
)
public val id: Long = 0L,
blocks: List<Block> = emptyList(),
@ -128,6 +133,7 @@ public class Point(
tag = 2,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel${'$'}Block#ADAPTER",
label = WireField.Label.REPEATED,
schemaIndex = 1,
)
public val blocks: List<Block> = immutableCopyOf("blocks", blocks)
@ -135,10 +141,9 @@ public class Point(
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")
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 {
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Channel) return false
if (unknownFields != other.unknownFields) return false
@ -147,7 +152,7 @@ public class Point(
return true
}
public override fun hashCode(): Int {
override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
@ -158,7 +163,7 @@ public class Point(
return result
}
public override fun toString(): String {
override fun toString(): String {
val result = mutableListOf<String>()
result += """id=$id"""
if (blocks.isNotEmpty()) result += """blocks=$blocks"""
@ -181,26 +186,32 @@ public class Point(
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Channel): Int {
override fun encodedSize(`value`: Channel): Int {
var size = value.unknownFields.size
if (value.id != 0L) size += ProtoAdapter.UINT64.encodedSizeWithTag(1, value.id)
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)
override fun encode(writer: ProtoWriter, `value`: Channel) {
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 {
override fun encode(writer: ReverseProtoWriter, `value`: Channel) {
writer.writeBytes(value.unknownFields)
Block.ADAPTER.asRepeated().encodeWithTag(writer, 2, value.blocks)
if (value.id != 0L) ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.id)
if (value.id != 0L) {
ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.id)
}
}
public override fun decode(reader: ProtoReader): Channel {
override fun decode(reader: ProtoReader): Channel {
var id: Long = 0L
val blocks = mutableListOf<Block>()
val unknownFields = reader.forEachTag { tag ->
@ -217,7 +228,7 @@ public class Point(
)
}
public override fun redact(`value`: Channel): Channel = value.copy(
override fun redact(`value`: Channel): Channel = value.copy(
blocks = value.blocks.redactElements(Block.ADAPTER),
unknownFields = ByteString.EMPTY
)
@ -237,6 +248,7 @@ public class Point(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
schemaIndex = 0,
)
public val time: Long = 0L,
frames: List<Frame> = emptyList(),
@ -247,6 +259,7 @@ public class Point(
tag = 3,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel${'$'}Block${'$'}Events#ADAPTER",
label = WireField.Label.OMIT_IDENTITY,
schemaIndex = 2,
)
public val events: Events? = null,
/**
@ -256,6 +269,7 @@ public class Point(
tag = 4,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
schemaIndex = 3,
)
public val length: Long = 0L,
/**
@ -266,6 +280,7 @@ public class Point(
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
jsonName = "binSize",
schemaIndex = 4,
)
public val bin_size: Long = 0L,
unknownFields: ByteString = ByteString.EMPTY,
@ -277,6 +292,7 @@ public class Point(
tag = 2,
adapter = "ru.inr.mass.data.proto.Point${'$'}Channel${'$'}Block${'$'}Frame#ADAPTER",
label = WireField.Label.REPEATED,
schemaIndex = 1,
)
public val frames: List<Frame> = immutableCopyOf("frames", frames)
@ -284,10 +300,9 @@ public class Point(
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")
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 {
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Block) return false
if (unknownFields != other.unknownFields) return false
@ -299,7 +314,7 @@ public class Point(
return true
}
public override fun hashCode(): Int {
override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
@ -313,7 +328,7 @@ public class Point(
return result
}
public override fun toString(): String {
override fun toString(): String {
val result = mutableListOf<String>()
result += """time=$time"""
if (frames.isNotEmpty()) result += """frames=$frames"""
@ -342,36 +357,59 @@ public class Point(
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Block): Int {
override fun encodedSize(`value`: Block): Int {
var size = value.unknownFields.size
if (value.time != 0L) size += ProtoAdapter.UINT64.encodedSizeWithTag(1, value.time)
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)
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)
override fun encode(writer: ProtoWriter, `value`: Block) {
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)
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 {
override fun encode(writer: ReverseProtoWriter, `value`: Block) {
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)
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)
if (value.time != 0L) {
ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.time)
}
}
public override fun decode(reader: ProtoReader): Block {
override fun decode(reader: ProtoReader): Block {
var time: Long = 0L
val frames = mutableListOf<Frame>()
var events: Events? = null
@ -397,7 +435,7 @@ public class Point(
)
}
public override fun redact(`value`: Block): Block = value.copy(
override fun redact(`value`: Block): Block = value.copy(
frames = value.frames.redactElements(Frame.ADAPTER),
events = value.events?.let(Events.ADAPTER::redact),
unknownFields = ByteString.EMPTY
@ -418,6 +456,7 @@ public class Point(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.OMIT_IDENTITY,
schemaIndex = 0,
)
public val time: Long = 0L,
/**
@ -428,6 +467,7 @@ public class Point(
adapter = "com.squareup.wire.ProtoAdapter#BYTES",
label = WireField.Label.OMIT_IDENTITY,
declaredName = "data",
schemaIndex = 1,
)
public val data_: ByteString = ByteString.EMPTY,
unknownFields: ByteString = ByteString.EMPTY,
@ -436,10 +476,9 @@ public class Point(
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")
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 {
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Frame) return false
if (unknownFields != other.unknownFields) return false
@ -448,7 +487,7 @@ public class Point(
return true
}
public override fun hashCode(): Int {
override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
@ -459,7 +498,7 @@ public class Point(
return result
}
public override fun toString(): String {
override fun toString(): String {
val result = mutableListOf<String>()
result += """time=$time"""
result += """data_=$data_"""
@ -482,29 +521,38 @@ public class Point(
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Frame): Int {
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_)
if (value.time != 0L) {
size += ProtoAdapter.UINT64.encodedSizeWithTag(1, value.time)
}
if (value.data_ != okio.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_)
override fun encode(writer: ProtoWriter, `value`: Frame) {
if (value.time != 0L) {
ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.time)
}
if (value.data_ != okio.ByteString.EMPTY) {
ProtoAdapter.BYTES.encodeWithTag(writer, 2, value.data_)
}
writer.writeBytes(value.unknownFields)
}
public override fun encode(writer: ReverseProtoWriter, `value`: Frame): Unit {
override fun encode(writer: ReverseProtoWriter, `value`: Frame) {
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)
if (value.data_ != okio.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 {
override fun decode(reader: ProtoReader): Frame {
var time: Long = 0L
var data_: ByteString = ByteString.EMPTY
val unknownFields = reader.forEachTag { tag ->
@ -521,7 +569,7 @@ public class Point(
)
}
public override fun redact(`value`: Frame): Frame = value.copy(
override fun redact(`value`: Frame): Frame = value.copy(
unknownFields = ByteString.EMPTY
)
}
@ -547,6 +595,7 @@ public class Point(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.PACKED,
schemaIndex = 0,
)
public val times: List<Long> = immutableCopyOf("times", times)
@ -557,6 +606,7 @@ public class Point(
tag = 2,
adapter = "com.squareup.wire.ProtoAdapter#UINT64",
label = WireField.Label.PACKED,
schemaIndex = 1,
)
public val amplitudes: List<Long> = immutableCopyOf("amplitudes", amplitudes)
@ -564,10 +614,9 @@ public class Point(
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")
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 {
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Events) return false
if (unknownFields != other.unknownFields) return false
@ -576,7 +625,7 @@ public class Point(
return true
}
public override fun hashCode(): Int {
override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
@ -587,7 +636,7 @@ public class Point(
return result
}
public override fun toString(): String {
override fun toString(): String {
val result = mutableListOf<String>()
if (times.isNotEmpty()) result += """times=$times"""
if (amplitudes.isNotEmpty()) result += """amplitudes=$amplitudes"""
@ -610,43 +659,61 @@ public class Point(
null,
"numass-proto.proto"
) {
public override fun encodedSize(`value`: Events): Int {
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 {
override fun encode(writer: ProtoWriter, `value`: Events) {
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 {
override fun encode(writer: ReverseProtoWriter, `value`: Events) {
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>()
override fun decode(reader: ProtoReader): Events {
var times: MutableList<Long>? = null
var amplitudes: MutableList<Long>? = null
val unknownFields = reader.forEachTag { tag ->
when (tag) {
1 -> times.add(ProtoAdapter.UINT64.decode(reader))
2 -> amplitudes.add(ProtoAdapter.UINT64.decode(reader))
1 -> {
if (times == null) {
val minimumByteSize = 1
val initialCapacity = (reader.nextFieldMinLengthInBytes() / minimumByteSize)
.coerceAtMost(Int.MAX_VALUE.toLong())
.toInt()
times = ArrayList(initialCapacity)
}
times!!.add(ProtoAdapter.UINT64.decode(reader))
}
2 -> {
if (amplitudes == null) {
val minimumByteSize = 1
val initialCapacity = (reader.nextFieldMinLengthInBytes() / minimumByteSize)
.coerceAtMost(Int.MAX_VALUE.toLong())
.toInt()
amplitudes = ArrayList(initialCapacity)
}
amplitudes!!.add(ProtoAdapter.UINT64.decode(reader))
}
else -> reader.readUnknownField(tag)
}
}
return Events(
times = times,
amplitudes = amplitudes,
times = times ?: listOf(),
amplitudes = amplitudes ?: listOf(),
unknownFields = unknownFields
)
}
public override fun redact(`value`: Events): Events = value.copy(
override fun redact(`value`: Events): Events = value.copy(
unknownFields = ByteString.EMPTY
)
}

@ -5,7 +5,7 @@ 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.Data
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.static
import space.kscience.dataforge.io.EnvelopeFormatFactory
@ -20,7 +20,6 @@ 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)
@ -35,7 +34,6 @@ public class NumassProtoPlugin : AbstractPlugin() {
public companion object : PluginFactory<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
}
}
@ -55,7 +53,8 @@ public fun NumassProtoPlugin.readNumassDirectory(path: Path): NumassDirectorySet
}
public fun NumassProtoPlugin.readNumassDirectory(path: String): NumassDirectorySet = readNumassDirectory(Path.of(path))
public suspend fun NumassProtoPlugin.readRepository(path: Path): DataTree<NumassDirectorySet> = DataSource {
public suspend fun NumassProtoPlugin.readRepository(path: Path): DataTree<NumassDirectorySet> = DataTree.static {
Files.walk(path).filter {
it.isDirectory() && it.resolve("meta").exists()
}.forEach { childPath ->
@ -63,7 +62,7 @@ public suspend fun NumassProtoPlugin.readRepository(path: Path): DataTree<Numass
NameToken(segment.fileName.toString())
})
val value = readNumassDirectory(childPath)
static(name, value, value.meta)
data(name, Data(value, value.meta))
}
//TODO add file watcher

@ -16,13 +16,14 @@
package ru.inr.mass.data.proto
import io.ktor.utils.io.core.readBytes
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import kotlinx.io.asInputStream
import kotlinx.io.readByteArray
import okio.ByteString
import org.slf4j.LoggerFactory
import ru.inr.mass.data.api.NumassBlock
@ -126,7 +127,7 @@ internal class ProtoNumassPoint(
val inflater = Inflater()
val array: ByteArray = data?.read {
readBytes()
readByteArray()
} ?: ByteArray(0)
inflater.setInput(array)

@ -16,7 +16,10 @@
package ru.inr.mass.data.proto
import io.ktor.utils.io.core.*
import kotlinx.io.*
import kotlinx.io.bytestring.encodeToByteString
import kotlinx.io.bytestring.endsWith
import kotlinx.io.bytestring.startsWith
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.invoke
import space.kscience.dataforge.io.*
@ -25,38 +28,21 @@ import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName
import java.util.*
public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeFormat {
private fun Tag.toBinary() = Binary {
writeRawString(START_SEQUENCE)
writeRawString("DFNU")
write(START_SEQUENCE.toByteArray())
writeString("DFNU")
writeShort(metaFormatKey)
writeUInt(metaSize)
writeUInt(dataSize.toUInt())
writeRawString(END_SEQUENCE)
write(END_SEQUENCE.toByteArray())
}
override fun writeEnvelope(
output: Output,
envelope: Envelope,
metaFormatFactory: MetaFormatFactory,
formatMeta: Meta,
) {
override fun writeTo(output: Sink, obj: Envelope) {
error("Don't write legacy formats")
// val metaFormat = metaFormatFactory.invoke(formatMeta, io.context)
// val metaBytes = metaFormat.toBinary(envelope.meta)
// val actualSize: ULong = (envelope.data?.size ?: 0).toULong()
// val tag = Tag(metaFormatFactory.key, metaBytes.size.toUInt() + 2u, actualSize)
// output.writeBinary(tag.toBinary())
// output.writeBinary(metaBytes)
// output.writeRawString("\r\n")
// envelope.data?.let {
// output.writeBinary(it)
// }
// output.flush()
}
/**
@ -65,34 +51,33 @@ public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeForm
* @param input an input to read from
* @param formats a collection of meta formats to resolve
*/
override fun readObject(input: Input): Envelope {
override fun readFrom(input: Source): Envelope {
val tag = input.readTag()
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey)
?: error("Meta format with key ${tag.metaFormatKey} not found")
val metaFormat = io.resolveMetaFormat(tag.metaFormatKey) ?: JsonMetaFormat
val meta: Meta = metaFormat.readObjectFrom(input.readBinary(tag.metaSize.toInt()))
val meta: Meta = metaFormat.readFrom(input.readBinary(tag.metaSize.toInt()))
val data = input.readBinary(tag.dataSize.toInt())
return SimpleEnvelope(meta, data)
}
override fun readPartial(input: Input): PartialEnvelope {
val tag = input.readTag()
val metaFormat = if (tag.metaFormatKey == 1.toShort()) {
JsonMetaFormat
} else {
io.resolveMetaFormat(tag.metaFormatKey)
?: error("Meta format with key ${tag.metaFormatKey} not found")
}
val meta: Meta = metaFormat.readObjectFrom(input.readBinary(tag.metaSize.toInt()))
return PartialEnvelope(meta, 30 + tag.metaSize.toInt(), tag.dataSize)
return Envelope(meta, data)
}
//
// override fun readPartial(input: Input): PartialEnvelope {
// val tag = input.readTag()
//
// val metaFormat = if (tag.metaFormatKey == 1.toShort()) {
// JsonMetaFormat
// } else {
// io.resolveMetaFormat(tag.metaFormatKey)
// ?: error("Meta format with key ${tag.metaFormatKey} not found")
// }
//
// val meta: Meta = metaFormat.readObjectFrom(input.readBinary(tag.metaSize.toInt()))
//
//
// return PartialEnvelope(meta, 30 + tag.metaSize.toInt(), tag.dataSize)
// }
private data class Tag(
val metaFormatKey: Short,
@ -105,8 +90,8 @@ public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeForm
// }
public companion object : EnvelopeFormatFactory {
private const val START_SEQUENCE = "#!"
private const val END_SEQUENCE = "!#\r\n"
private val START_SEQUENCE = "#!".encodeToByteString()
private val END_SEQUENCE = "!#\r\n".encodeToByteString()
override val name: Name = "envelope.numass".parseAsName()
@ -120,23 +105,23 @@ public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeForm
return TaggedNumassEnvelopeFormat(io)
}
private fun Input.readTag(): Tag {
val start = readRawString(2)
private fun Source.readTag(): Tag {
val start = readByteString(2)
if (start != START_SEQUENCE) error("The input is not an envelope")
val versionString = readRawString(4)
val versionString = readByteString(4)
val junk1 = readInt()
val metaFormatKey = readShort()
val junk2 = readShort()
val metaLength = readUInt()
val dataLength: ULong = readULong()
val end = readRawString(4)
val end = readByteString(4)
if (end != END_SEQUENCE) error("The input is not an envelope")
return Tag(metaFormatKey, metaLength, dataLength)
}
override fun peekFormat(io: IOPlugin, binary: Binary): EnvelopeFormat? = try {
binary.read {
val header = readRawString(30)
val header = readByteString(30)
if (header.startsWith(START_SEQUENCE) && header.endsWith(END_SEQUENCE)) {
TaggedNumassEnvelopeFormat(io)
} else {
@ -149,23 +134,11 @@ public class TaggedNumassEnvelopeFormat(private val io: IOPlugin) : EnvelopeForm
private val default by lazy { invoke() }
override fun readPartial(input: Input): PartialEnvelope =
default.run { readPartial(input) }
override fun writeEnvelope(
output: Output,
envelope: Envelope,
metaFormatFactory: MetaFormatFactory,
formatMeta: Meta,
): Unit = default.run {
writeEnvelope(
output,
envelope,
metaFormatFactory,
formatMeta
)
override fun writeTo(output: Sink, obj: Envelope) {
error("Don't write legacy formats")
}
override fun readObject(input: Input): Envelope = default.readObject(input)
override fun readFrom(input: Source): Envelope = default.readFrom(input)
}
}

@ -1,37 +1,37 @@
package ru.inr.mass.data.proto
import io.ktor.utils.io.core.*
import java.io.InputStream
import kotlinx.io.Source
// TODO move to dataforge-io
/**
* Sequentially read Utf8 lines from the input until it is exhausted
*/
public fun Input.lines(): Sequence<String> = sequence {
while (!endOfInput) {
readUTF8Line()?.let { yield(it) }
}
public fun Source.lines(): Sequence<String> = sequence {
do {
val line = readLine()
if (line != null) yield(line)
} while (line != null)
}
private class InputAsInputStream(val input: Input) : InputStream() {
override fun read(): Int = input.run {
if (endOfInput) {
-1
} else {
readUByte().toInt()
}
}
override fun readAllBytes(): ByteArray = input.readBytes()
override fun read(b: ByteArray): Int = input.readAvailable(b)
override fun close() {
input.close()
}
}
public fun Input.asInputStream(): InputStream = InputAsInputStream(this)
//private class InputAsInputStream(val input: Source) : InputStream() {
//
//
// override fun read(): Int = input.run {
// if (endOfInput) {
// -1
// } else {
// readUByte().toInt()
// }
// }
//
// override fun readAllBytes(): ByteArray = input.readBytes()
//
// override fun read(b: ByteArray): Int = input.readAvailable(b)
//
// override fun close() {
// input.close()
// }
//}
//
//public fun Source.asInputStream(): InputStream = InputAsInputStream(this)

@ -1,5 +1,7 @@
plugins {
id("space.kscience.gradle.mpp")
alias(spclibs.plugins.compose.compiler)
alias(spclibs.plugins.compose.jb)
`maven-publish`
}
@ -7,54 +9,45 @@ val visionForgeVersion: String by rootProject.extra
val production: Boolean by rootProject.extra(true)
kotlin {
js(IR) {
browser {
webpackTask {
this.outputFileName = "js/numass-web.js"
}
}
binaries.executable()
kscience {
fullStack("js/numass-web.js")
useSerialization {
json()
}
sourceSets {
useContextReceivers()
useKtor()
}
kotlin{
sourceSets{
commonMain {
dependencies {
api(compose.runtime)
implementation(project(":numass-data-model"))
implementation("space.kscience:visionforge-core:$visionForgeVersion")
implementation("space.kscience:visionforge-plotly:$visionForgeVersion")
}
}
jvmMain {
dependencies {
jvmMain{
dependencies{
implementation(project(":numass-data-proto"))
implementation("space.kscience:visionforge-server:$visionForgeVersion")
implementation("io.ktor:ktor-server-cio")
implementation("io.ktor:ktor-server-html-builder")
implementation("space.kscience:visionforge-plotly:$visionForgeVersion")
}
}
}
}
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")
jsMain{
dependencies{
implementation("org.jetbrains.kotlin-wrappers:kotlin-extensions:1.0.1-pre.823")
implementation(compose.html.core)
}
}
}
}
kscience {
useSerialization {
json()
}
withContextReceivers()
}
}

@ -9,7 +9,6 @@ import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionPlugin
import kotlin.reflect.KClass
public class NumassCommonPlugin(meta: Meta = Meta.EMPTY) : VisionPlugin(meta) {
override val tag: PluginTag get() = Companion.tag
@ -18,7 +17,6 @@ public class NumassCommonPlugin(meta: Meta = Meta.EMPTY) : VisionPlugin(meta) {
public companion object : PluginFactory<NumassCommonPlugin> {
override val tag: PluginTag = PluginTag("numass.common", "ru.inr.mass")
override val type: KClass<NumassCommonPlugin> = NumassCommonPlugin::class
override fun build(context: Context, meta: Meta): NumassCommonPlugin = NumassCommonPlugin()
@ -27,7 +25,6 @@ public class NumassCommonPlugin(meta: Meta = Meta.EMPTY) : VisionPlugin(meta) {
subclass(VisionOfNumassHv.serializer())
subclass(VisionOfNumassPoint.serializer())
subclass(VisionOfNumassSet.serializer())
subclass(VisionOfNumassSetRef.serializer())
subclass(VisionOfNumassRepository.serializer())
}
}

@ -3,12 +3,10 @@ package ru.inr.mass.data.server
import kotlinx.serialization.Serializable
import ru.inr.mass.data.api.NumassSet
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.DataTreeItem
import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.data.await
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.plus
import space.kscience.visionforge.AbstractVision
import space.kscience.visionforge.AbstractVisionGroup
@Serializable
@ -16,20 +14,15 @@ public class VisionOfNumassRepository : AbstractVisionGroup() {
override fun createGroup(): VisionOfNumassRepository = VisionOfNumassRepository()
}
@Serializable
public class VisionOfNumassSetRef(
override val name: Name,
) : Named, AbstractVision()
public suspend fun VisionOfNumassRepository(
repoName: Name,
tree: DataTree<NumassSet>,
): VisionOfNumassRepository = VisionOfNumassRepository().apply {
tree.items.forEach { (key: NameToken, value) ->
children[key] = when (value) {
is DataTreeItem.Leaf -> VisionOfNumassSetRef(repoName + key)
is DataTreeItem.Node -> VisionOfNumassRepository(repoName + key, value.tree)
}
tree.data?.let {
VisionOfNumassSet(repoName, it.await())
}
tree.items.forEach { (key: NameToken, subtree) ->
children[key] = VisionOfNumassRepository(repoName + key, subtree)
}
//TODO listen to changes
}

@ -12,16 +12,18 @@ 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.plotElement
import space.kscience.plotly.plotDiv
import space.kscience.plotly.scatter
import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.html.ElementVisionRenderer
import space.kscience.visionforge.html.JsVisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin
import kotlin.reflect.KClass
public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer {
public val client: VisionClient by require(VisionClient)
override fun toString(): String = "NumassJsPlugin"
public val client: VisionClient by require(JsVisionClient)
public val numassCommon: NumassCommonPlugin by require(NumassCommonPlugin)
public val plotly: PlotlyPlugin by require(PlotlyPlugin)
@ -37,7 +39,7 @@ public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer {
else -> super.content(target)
}
override fun render(element: Element, vision: Vision, meta: Meta) {
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
when (vision) {
is VisionOfNumassHv -> element.append {
h1 { +"HV" }
@ -60,11 +62,11 @@ public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer {
is VisionOfNumassPoint -> element.append {
h1 { +"Point" }
plotElement {
plotDiv {
vision.spectra.forEach { (channel, spectrum) ->
val pairs = spectrum.entries.sortedBy { it.key }
scatter {
name = channel
this.name = channel
mode = ScatterMode.lines
line {
shape = LineShape.hv
@ -83,8 +85,6 @@ 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 build(context: Context, meta: Meta): NumassJsPlugin = NumassJsPlugin()
}

@ -0,0 +1,27 @@
package ru.inr.mass.data.server
import org.jetbrains.compose.web.dom.Div
import org.jetbrains.compose.web.renderComposable
import org.w3c.dom.Document
import space.kscience.dataforge.context.Context
import space.kscience.visionforge.html.Application
public class NumassViewerApplication : Application {
private val context = Context("NumassViewer") {
plugin(NumassJsPlugin)
}
override fun start(document: Document, state: Map<String, Any>) {
renderComposable(rootElementId = "application") {
Div({ classes("container") }) {
Div({ classes("row") })
Div({ classes("col-md-3") }) {
}
Div({ classes("col-md-9") }) {
}
}
}
}
}

@ -1,7 +1,7 @@
package ru.inr.mass.data.server
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.visionforge.runVisionClient
import space.kscience.visionforge.html.runVisionClient
@DFExperimental

@ -1,132 +1,141 @@
package ru.inr.mass.data.server
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.URLBuilder
import io.ktor.server.application.call
import io.ktor.server.application.Application
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.ktor.server.html.respondHtml
import io.ktor.server.http.content.staticResources
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.html.*
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.data.proto.NumassProtoPlugin
import ru.inr.mass.data.proto.readRepository
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.fetch
import space.kscience.dataforge.context.request
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.await
import space.kscience.dataforge.data.get
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.cutLast
import space.kscience.dataforge.names.lastOrNull
import space.kscience.visionforge.server.close
import space.kscience.visionforge.server.openInBrowser
import space.kscience.visionforge.server.visionServer
public suspend fun main() {
public fun main() {
val port = 7777
val host = "localhost"
embeddedServer(CIO, port, host, module = Application::numassModule).start()
}
public fun Application.numassModule(repositoryName: String = "D:\\Work\\Numass\\data\\test") {
val context = Context("Numass") {
plugin(NumassProtoPlugin)
plugin(NumassCommonPlugin)
}
val numassProto = context.fetch(NumassProtoPlugin)
val numassCommon = context.fetch(NumassCommonPlugin)
val numassProto = context.request(NumassProtoPlugin)
val numassCommon = context.request(NumassCommonPlugin)
val visionManager = numassCommon.visionManager
val repository: DataTree<NumassDirectorySet> = runBlocking { numassProto.readRepository(repositoryName) }
val repositroyName = "D:\\Work\\Numass\\data\\test"
val port = 7777
val host = "localhost"
val url = URLBuilder(host = host, port = port).build()
val repository: DataTree<NumassDirectorySet> = numassProto.readRepository(repositroyName)
val visionOfNumassRepository = VisionOfNumassRepository(Name.EMPTY, repository)
val server = context.embeddedServer(CIO, port, host) {
routing {
get("/repository") {
call.respondText {
visionManager.encodeToString(visionOfNumassRepository)
routing {
staticResources("/","")
get("/") {
call.respondHtml {
head {
meta { charset = "utf-8" }
meta {
name = "viewport"
content = "width=device-width, initial-scale=1"
}
title("Numass Data Viewer")
link {
href = "https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
rel = "stylesheet"
attributes["integrity"] =
"sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
attributes["crossorigin"] = "anonymous"
}
}
}
get("/sets/{name...}") {
val setName: Name? = call.parameters.getAll("name")
?.map { NameToken.parse(it) }?.let(::Name)
if (setName == null) {
call.respondText(status = HttpStatusCode.BadRequest) { "Set name is empty" }
return@get
}
val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() }
if (set == null) {
call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" }
return@get
}
call.respondText {
visionManager.encodeToString(VisionOfNumassSet(setName, set))
}
}
get("/points/{name...}") {
val fullName: Name? = call.parameters.getAll("name")
?.map { NameToken.parse(it) }?.let(::Name)
if (fullName == null) {
call.respondText(status = HttpStatusCode.BadRequest) { "Point name is empty" }
return@get
}
val setName = fullName.cutLast()
val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() }
if (set == null) {
call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" }
return@get
}
val pointIndex: Int? = fullName.lastOrNull()?.body?.toIntOrNull()
val point: NumassPoint? = set.points.find { it.index == pointIndex }
if (point == null) {
call.respondText(status = HttpStatusCode.NotFound) { "A point with name $setName/$pointIndex not found in the repository" }
return@get
}
call.respondText {
visionManager.encodeToString(point.toVision())
body {
div {
id = "application"
}
script {
src = "js/numass-web.js"
}
script {
src = "https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
integrity = "sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
attributes["crossorigin"] = "anonymous"
}
}
}
}
visionServer(numassCommon.visionManager, url)
}.start()
// val server = context.visionManager.serve {
// header("numass", VisionPage.scriptHeader("js/numass-web.js"))
// page {
// div("flex-column") {
// h1 { +"Visionforge file demo" }
// vision { visionOfNumass }
// }
// }
// }
get("/repository") {
call.respondText(ContentType.Application.Json) {
visionManager.encodeToString(VisionOfNumassRepository(Name.EMPTY, repository))
}
}
server.openInBrowser()
get("/sets/{name...}") {
val setName: Name? = call.parameters.getAll("name")
?.map { NameToken.parse(it) }?.let(::Name)
if (setName == null) {
call.respondText(status = HttpStatusCode.BadRequest) { "Set name is empty" }
return@get
}
println("Enter 'exit' to close server")
while (readLine() != "exit") {
//
val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() }
if (set == null) {
call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" }
return@get
}
call.respondText(ContentType.Application.Json) {
visionManager.encodeToString(VisionOfNumassSet(setName, set))
}
}
get("/points/{name...}") {
val fullName: Name? = call.parameters.getAll("name")
?.map { NameToken.parse(it) }?.let(::Name)
if (fullName == null) {
call.respondText(status = HttpStatusCode.BadRequest) { "Point name is empty" }
return@get
}
val setName = fullName.cutLast()
val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() }
if (set == null) {
call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" }
return@get
}
val pointIndex: Int? = fullName.lastOrNull()?.body?.toIntOrNull()
val point: NumassPoint? = set.points.find { it.index == pointIndex }
if (point == null) {
call.respondText(status = HttpStatusCode.NotFound) { "A point with name $setName/$pointIndex not found in the repository" }
return@get
}
call.respondText(ContentType.Application.Json) {
visionManager.encodeToString(point.toVision())
}
}
}
server.close()
//serveVisionData(VisionRoute("/visions", visionManager))
}

@ -2,11 +2,8 @@ package ru.inr.mass.data.server
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.VisionPage
import space.kscience.visionforge.html.importScriptHeader
import space.kscience.visionforge.makeFile
import space.kscience.visionforge.html.*
import space.kscience.visionforge.visionManager
import java.awt.Desktop
import java.nio.file.Path
@ -19,7 +16,7 @@ public fun Context.makeNumassWebFile(
show: Boolean = true,
content: HtmlVisionFragment,
): Unit {
val actualPath = VisionPage(this, content = content).makeFile(path) { actualPath: Path ->
val actualPath = VisionPage(visionManager, content = content).makeFile(path) { actualPath: Path ->
mapOf(
"title" to VisionPage.title(title),
"numassWeb" to VisionPage.importScriptHeader("js/numass-web.js", resourceLocation, actualPath)

@ -4,7 +4,7 @@ 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.dataforge.context.request
import java.nio.file.Path
@ -15,7 +15,7 @@ public suspend fun main() {
plugin(NumassCommonPlugin)
}
val numassProto = context.fetch(NumassProtoPlugin)
val numassProto = context.request(NumassProtoPlugin)
val pointPath = Path.of("D:\\Work\\Numass\\data\\test\\set_7\\p120(30s)(HV1=13300)")
val point: NumassPoint = numassProto.readNumassPointFile(pointPath)!!

@ -7,7 +7,9 @@ plugins {
val dataforgeVersion: String by rootProject.extra
val kmathVersion: String by rootProject.extra
kotlin.sourceSets {
kscience{
jvm()
js()
commonMain {
dependencies {
api("space.kscience:dataforge-context:$dataforgeVersion")
@ -15,7 +17,10 @@ kotlin.sourceSets {
api("space.kscience:kmath-functions:$kmathVersion")
}
}
jvmMain {
}
kotlin.sourceSets{
getByName("jvmMain"){
dependencies {
api("space.kscience:kmath-commons:$kmathVersion")
api("ch.qos.logback:logback-classic:1.2.3")

@ -18,11 +18,9 @@ package ru.inr.mass.models
import space.kscience.kmath.data.ColumnarData
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.structures.Buffer
@OptIn(UnstableKMathAPI::class)
public class FSS(public val es: Buffer<Double>, public val ps: Buffer<Double>) : ColumnarData<Double> {
override val size: Int get() = ps.size

@ -32,8 +32,8 @@ public class NBkgSpectrum(public val source: Spectrum) : DifferentiableSpectrum
override fun derivativeOrNull(symbols: List<Symbol>): Spectrum? = when {
symbols.isEmpty() -> this
symbols.size == 1 -> when (symbols.first()) {
norm -> Spectrum { x, arguments -> source(x, arguments) + (arguments[bkg] ?: 0.0) }
bkg -> Spectrum { x, arguments -> (arguments[norm] ?: 1.0) * source(x, arguments) }
norm -> Spectrum { x, arguments -> source(x, arguments) }
bkg -> Spectrum { _, _ -> 1.0 }
else -> (source as? DifferentiableSpectrum)?.derivativeOrNull(symbols)?.let { NBkgSpectrum(it) }
}
else -> null
@ -48,4 +48,4 @@ public class NBkgSpectrum(public val source: Spectrum) : DifferentiableSpectrum
/**
* Apply transformation adding norming-factor and the background
*/
public fun Spectrum.withNBkg(): NBkgSpectrum = NBkgSpectrum(this)
public fun Spectrum.withNBkg(): NBkgSpectrum = NBkgSpectrum(this)

@ -3,6 +3,8 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
@file:Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
package ru.inr.mass.models
import space.kscience.kmath.expressions.Symbol

@ -12,10 +12,13 @@ import kotlin.math.sqrt
/**
* @author [Alexander Nozik](mailto:altavir@gmail.com)
*/
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
public class NumassResolution(
public val resA: Double = 8.3e-5,
public val resA: Double = 1.7e-4,
public val resB: Double = 0.0,
public val tailFunction: (Double, Double) -> Double = { _, _ -> 1.0 },
// Recent formula for adiabacity
public val tailFunction: (Double, Double) -> Double = { e, u -> -1.75559e-13 * (e - u) * (e - u) * (e - u) - 5.97479e-11 * (e - u) * (e - u) + 3.26473e-7 * (e - u) + 1.0 },
) : DifferentiableKernel {
// private val tailFunction: Kernel = when {
@ -43,12 +46,12 @@ public class NumassResolution(
// else -> ResolutionFunction.getConstantTail()
// }
private fun getValueFast(E: Double, U: Double): Double {
val delta = resA * E
private fun getValueFast(e: Double, u: Double): Double {
val delta = resA * e
return when {
E - U < 0 -> 0.0
E - U > delta -> tailFunction(E, U)
else -> (E - U) / delta
e - u < 0 -> 0.0
e - u > delta -> tailFunction(e, u)
else -> (e - u) / delta
}
}
@ -57,15 +60,15 @@ public class NumassResolution(
override val x: Symbol get() = e
override val y: Symbol get() = u
override fun invoke(E: Double, U: Double, arguments: Map<Symbol, Double>): Double {
override fun invoke(e: Double, u: Double, arguments: Map<Symbol, Double>): Double {
if (resB <= 0) {
return this.getValueFast(E, U)
return this.getValueFast(e, u)
}
val delta = resA * E
val delta = resA * e
return when {
E - U < 0 -> 0.0
E - U > delta -> tailFunction(E, U)
else -> (1 - sqrt(1 - (E - U) / E * resB)) / (1 - sqrt(1 - resA * resB))
e - u < 0 -> 0.0
e - u > delta -> tailFunction(e, u)
else -> (1 - sqrt(1 - (e - u) / e * resB)) / (1 - sqrt(1 - resA * resB))
}
}

@ -5,23 +5,27 @@
*/
package ru.inr.mass.models
import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.functions.Function1D
import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.asFunction
import space.kscience.kmath.integration.*
import space.kscience.kmath.integration.IntegrandMaxCalls
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.simpsonIntegrator
import space.kscience.kmath.integration.value
import space.kscience.kmath.operations.DoubleField
import kotlin.jvm.Synchronized
import kotlin.math.*
import kotlin.math.exp
import kotlin.math.ln
/**
* @author [Alexander Nozik](mailto:altavir@gmail.com)
*/
public class NumassTransmission(
public val trapFunc: Kernel = defaultTrapping,
// private val adjustX: Boolean = false,
public val trapFunc: Kernel = trapFunction,
public val adjustX: Boolean = false,
) : DifferentiableKernel {
// private val trapFunc: Kernel = if (meta.hasValue("trapping")) {
// val trapFuncStr = meta.getString("trapping")
@ -54,8 +58,10 @@ public class NumassTransmission(
}
sum
}
else -> null
}
else -> null
}
@ -63,6 +69,7 @@ public class NumassTransmission(
// loss part
val thickness = arguments[thickness] ?: 0.0
val loss = getTotalLossValue(thickness, ei, ef)
//val loss = 0.0
// double loss;
//
// if(eIn-eOut >= 300){
@ -76,7 +83,9 @@ public class NumassTransmission(
// }
//trapping part
//
val trap = (arguments[trap] ?: 1.0) * trapFunc(ei, ef, arguments)
//val trap = 0.0
return loss + trap
}
@ -86,7 +95,7 @@ public class NumassTransmission(
private val cache = HashMap<Int, Function1D<Double>>()
private const val ION_POTENTIAL = 15.4//eV
private const val ION_POTENTIAL = 13.6//eV
private fun getX(arguments: Map<Symbol, Double>, eIn: Double, adjustX: Boolean = false): Double {
@ -131,6 +140,7 @@ public class NumassTransmission(
}
private fun getCachedSpectrum(order: Int): Function1D<Double> {
//println("-------------------ORDER $order ------------------------")
return when {
order <= 0 -> error("Non-positive loss cache order")
order == 1 -> singleScatterFunction
@ -259,10 +269,13 @@ public class NumassTransmission(
* @param loss
* @return
*/
@Synchronized
@ThreadSafe
private fun getNextLoss(margin: Double, loss: Function1D<Double>): PiecewisePolynomial<Double> {
val res = { x: Double ->
DoubleField.simpsonIntegrator.integrate(5.0..margin, IntegrandMaxCalls(200)) { y ->
DoubleField.simpsonIntegrator.integrate(
5.0..margin,
attributeBuilder = { IntegrandMaxCalls(200) }
) { y ->
loss(x - y) * singleScatterFunction(y)
}.value
}
@ -274,13 +287,13 @@ public class NumassTransmission(
* Значение полной производной функции потерь с учетом всех неисчезающих
* порядков
*
* @param X
* @param thickness
* @param eIn
* @param eOut
* @return
*/
private fun getTotalLossDeriv(X: Double, eIn: Double, eOut: Double): Double {
val probs = getLossProbDerivs(X)
private fun getTotalLossDeriv(thickness: Double, eIn: Double, eOut: Double): Double {
val probs = getLossProbDerivs(thickness)
var sum = 0.0
for (i in 1 until probs.size) {
@ -331,6 +344,7 @@ public class NumassTransmission(
val z = eps - pos1
A1 * exp(-2.0 * z * z / w1 / w1)
}
else -> {
val z = 4.0 * (eps - pos2) * (eps - pos2)
A2 / (1 + z / w2 / w2)
@ -399,8 +413,8 @@ public class NumassTransmission(
// return getSingleScatterFunction(exPos, ionPos, exW, ionW, exIonRatio)
// }
public val trapFunction: (Double, Double) -> Double = { Ei: Double, Ef: Double ->
val eps = Ei - Ef
public val trapFunction: Kernel = Kernel { ei: Double, ef: Double, _ ->
val eps = ei - ef
if (eps > 10) {
1.86e-04 * exp(-eps / 25.0) + 5.5e-05
} else {

@ -1,10 +1,14 @@
package ru.inr.mass.models
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.expressions.Expression
import space.kscience.kmath.expressions.SpecialDifferentiableExpression
import space.kscience.kmath.expressions.Symbol
public fun interface Spectrum : Expression<Double> {
override val type: SafeType<Double> get() = safeTypeOf<Double>()
public val abscissa: Symbol get() = Symbol.x
public operator fun invoke(x: Double, arguments: Map<Symbol, Double>): Double
@ -16,6 +20,7 @@ public fun interface Spectrum : Expression<Double> {
public interface DifferentiableSpectrum : SpecialDifferentiableExpression<Double, Spectrum>, Spectrum
public fun interface Kernel : Expression<Double> {
override val type: SafeType<Double> get() = safeTypeOf<Double>()
public val x: Symbol get() = Symbol.x
public val y: Symbol get() = Symbol.y
@ -38,6 +43,6 @@ public fun Kernel.withFixedY(y: Double): Spectrum = Spectrum { x, arguments ->
invoke(x, y, arguments)
}
public fun <T> Expression<T>.withDefault(default: Map<Symbol, T>): Expression<T> = Expression { args ->
public fun <T> Expression<T>.withDefault(default: Map<Symbol, T>): Expression<T> = Expression(type) { args ->
invoke(default + args)
}

@ -12,12 +12,11 @@ import ru.inr.mass.models.NumassBeta.msterile2
import ru.inr.mass.models.NumassBeta.u2
import ru.inr.mass.models.NumassTransmission.Companion.thickness
import ru.inr.mass.models.NumassTransmission.Companion.trap
import space.kscience.attributes.AttributesBuilder
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.integration.UnivariateIntegrandRanges
import space.kscience.kmath.integration.gaussIntegrator
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.value
import space.kscience.kmath.integration.*
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.real.step
import space.kscience.kmath.structures.toDoubleArray
@ -28,6 +27,7 @@ import space.kscience.kmath.structures.toDoubleArray
* @param transmission variables:Ein,Eout; parameters: "A"
* @param resolution variables:Eout,U; parameters: "X", "trap"
*/
@OptIn(UnstableKMathAPI::class)
public class SterileNeutrinoSpectrum(
public val source: DifferentiableKernel = NumassBeta,
public val transmission: DifferentiableKernel = NumassTransmission(),
@ -54,9 +54,11 @@ public class SterileNeutrinoSpectrum(
u2, msterile2, mnu2, e0 -> Spectrum { u, arguments ->
convolute(u, source.derivative(symbols), transRes, arguments)
}
thickness, trap -> Spectrum { u, arguments ->
convolute(u, source, transRes.derivative(symbols), arguments)
}
else -> null
}
}
@ -94,14 +96,17 @@ public class SterileNeutrinoSpectrum(
// }
return DoubleField.gaussIntegrator.integrate(
u..eMax, generateRanges(
u..eMax,
u + 2.0,
u + 7.0,
u + 15.0,
u + 30.0,
*((u + 50)..(u + 6000) step 25.0).toDoubleArray()
)
range = u..eMax,
attributeBuilder = {
multiRange(
u..eMax,
u + 2.0,
u + 7.0,
u + 15.0,
u + 30.0,
*((u + 50)..(u + 6000) step 25.0).toDoubleArray()
)
}
) { eIn ->
sumByFSS(eIn, sourceFunction, arguments) * transResFunction(eIn, u, arguments)
}.value
@ -138,14 +143,17 @@ public class SterileNeutrinoSpectrum(
u: Double,
arguments: Map<Symbol, Double>,
): Double = DoubleField.gaussIntegrator.integrate(
u..eIn, generateRanges(
u..eIn,
u + 2.0,
u + 7.0,
u + 15.0,
u + 30.0,
*((u + 50)..(u + 6000) step 30.0).toDoubleArray()
)
range = u..eIn,
attributeBuilder = {
multiRange(
u..eIn,
u + 2.0,
u + 7.0,
u + 15.0,
u + 30.0,
*((u + 50)..(u + 6000) step 30.0).toDoubleArray()
)
}
) { eOut: Double ->
transFunc(eIn, eOut, arguments) * resolution(eOut, u, arguments)
}.value
@ -154,19 +162,25 @@ public class SterileNeutrinoSpectrum(
public companion object
}
internal fun generateRanges(
internal fun AttributesBuilder<UnivariateIntegrand<*>>.multiRange(
range: ClosedFloatingPointRange<Double>,
vararg borders: Double,
points: Int = 5,
): UnivariateIntegrandRanges {
if (borders.isEmpty() || borders.first() > range.endInclusive) return UnivariateIntegrandRanges(range to points)
val ranges = listOf(
range.start,
*borders.filter { it in range }.sorted().toTypedArray(),
range.endInclusive
).zipWithNext { l, r ->
l..r to points
) {
val ranges: UnivariateIntegrandRanges = if (borders.isEmpty() || borders.first() > range.endInclusive) {
UnivariateIntegrandRanges(range to points)
} else {
UnivariateIntegrandRanges(
listOf(
range.start,
*borders.filter { it in range }.sorted().toTypedArray(),
range.endInclusive
).zipWithNext { l, r ->
l..r to points
}
)
}
return UnivariateIntegrandRanges(ranges)
UnivariateIntegrandRanges.invoke(
ranges
)
}

@ -6,7 +6,7 @@ import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.interpolation.SplineInterpolator
import space.kscience.kmath.interpolation.interpolatePolynomials
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.Float64Buffer
import kotlin.math.abs
public fun Function1D<Double>.cache(
@ -14,8 +14,8 @@ public fun Function1D<Double>.cache(
numCachePoints: Int,
): PiecewisePolynomial<Double> {
val length = abs(range.endInclusive - range.start)
val grid: DoubleBuffer = DoubleBuffer(numCachePoints) { range.start + length / (numCachePoints - 1) * it }
val vals = DoubleBuffer(grid.size) { invoke(grid[it]) }
val interpolator = SplineInterpolator(DoubleField, ::DoubleBuffer)
val grid = Float64Buffer(numCachePoints) { range.start + length / (numCachePoints - 1) * it }
val vals = Float64Buffer(grid.size) { invoke(grid[it]) }
val interpolator = SplineInterpolator(DoubleField)
return interpolator.interpolatePolynomials(grid, vals)
}

@ -1,12 +1,18 @@
package ru.inr.mass.models
import space.kscience.attributes.Attributes
import space.kscience.kmath.integration.UnivariateIntegrand
import space.kscience.kmath.integration.UnivariateIntegrandRanges
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestGenerateRanges {
@Test
fun simpleRanges() {
val ranges = generateRanges(0.0..100.0, 10.0, 55.0, 120.0)
val attributes = Attributes<UnivariateIntegrand<*>>{
multiRange(0.0..100.0, 10.0, 55.0, 120.0)
}
val ranges = attributes[UnivariateIntegrandRanges]!!
assertEquals(3, ranges.ranges.size)
assertEquals(55.0..100.0, ranges.ranges.last().first)
assertEquals(10.0..55.0, ranges.ranges[1].first)

@ -0,0 +1,238 @@
package ru.inr.mass.models
import kotlinx.coroutines.*
import ru.inr.mass.models.NumassBeta.e0
import ru.inr.mass.models.NumassBeta.mnu2
import ru.inr.mass.models.NumassBeta.msterile2
import ru.inr.mass.models.NumassBeta.u2
import ru.inr.mass.models.NumassTransmission.Companion.thickness
import ru.inr.mass.models.NumassTransmission.Companion.trap
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.derivative
import kotlin.math.max
/**
* @param source variables:Eo offset,Ein; parameters: "mnu2", "msterile2", "U2"
* @param transmission variables:Ein,Eout; parameters: "A"
* @param resolution variables:Eout,U; parameters: "X", "trap"
*/
public open class SterileNeutrinoSpectrumFast(
public val source: DifferentiableKernel = NumassBeta,
public val transmission: DifferentiableKernel = NumassTransmission(),
public val resolution: DifferentiableKernel = NumassResolution(),
public val fss: FSS? = null,
) : DifferentiableSpectrum {
/**
* auxiliary function for trans-res convolution
*/
private val transRes: DifferentiableKernel = TransRes()
// private boolean useMC;
//private val fast: Boolean = configuration.getBoolean("fast", true)
override fun invoke(u: Double, arguments: Map<Symbol, Double>): Double {
return convolute(u, source, transRes, arguments)
}
override fun derivativeOrNull(symbols: List<Symbol>): Spectrum? {
if (symbols.isEmpty()) return this
return when (symbols.singleOrNull() ?: TODO("First derivatives only")) {
u2, msterile2, mnu2, e0 -> Spectrum { u, arguments ->
convolute(u, source.derivative(symbols), transRes, arguments)
}
thickness, trap -> Spectrum { u, arguments ->
convolute(u, source, transRes.derivative(symbols), arguments)
}
else -> null
}
}
/**
* Direct Gauss-Legendre integration
*
* @param u
* @param sourceFunction
* @param transResFunction
* @param arguments
* @return
*/
private fun convolute(
u: Double,
sourceFunction: Kernel,
transResFunction: Kernel,
arguments: Map<Symbol, Double>,
): Double {
val eMax = arguments.getValue(e0) + 5.0
if (u >= eMax) {
return 0.0
}
val xs = createRange(u, eMax)
return runBlocking(Dispatchers.Default) {
parallelIntegrate(xs) { eIn ->
sumByFSS(eIn, sourceFunction, arguments) * transResFunction(eIn, u, arguments)
}
}
}
private fun sumByFSS(eIn: Double, sourceFunction: Kernel, arguments: Map<Symbol, Double>): Double {
return if (fss == null) {
sourceFunction(0.0, eIn, arguments)
} else {
(0 until fss.size).sumOf { fss.ps[it] * sourceFunction(fss.es[it], eIn, arguments) }
}
}
private inner class TransRes : DifferentiableKernel {
override fun invoke(eIn: Double, u: Double, arguments: Map<Symbol, Double>): Double {
val p0 = NumassTransmission.p0(eIn, arguments)
return p0 * resolution(eIn, u, arguments) + lossRes(transmission, eIn, u, arguments)
}
override fun derivativeOrNull(symbols: List<Symbol>): Kernel? {
if (symbols.isEmpty()) return this
return when (symbols.singleOrNull() ?: TODO("First derivatives only")) {
thickness -> null//TODO implement p0 derivative
trap -> Kernel { eIn, u, arguments -> lossRes(transmission.derivative(symbols), eIn, u, arguments) }
else -> null
}
}
private fun lossRes(
transFunc: Kernel,
eIn: Double,
u: Double,
arguments: Map<Symbol, Double>,
): Double {
val xs = createRange(u, eIn)
return runBlocking {
parallelIntegrate(xs) { eOut: Double ->
transFunc(eIn, eOut, arguments) * resolution(eOut, u, arguments)
}
}
}
}
public companion object
}
/**
* Создание границ, с шагами такими же, как в оригинальной функции [SterileNeutrinoSpectrum.convolute]
*/
private fun createRange(x1: Double, x2: Double): DoubleArray {
val result = mutableListOf<Double>()
var currentValue = x1
val steps = listOf(2.0, 5.0, 8.0, 15.0, 20.0)
var stepIndex = 0
while (currentValue <= x2) {
result.add(currentValue)
currentValue += if (stepIndex < steps.size) {
steps[stepIndex++]
} else {
25.0
}
}
// Ensure the last element is exactly x2 if possible
if (result.isNotEmpty() && result.last() != x2) {
if (result.last() < x2) {
result.add(x2)
} else {
result[result.lastIndex] = x2
}
}
return result.toDoubleArray()
}
/**
* Параллельный интегратор одномерной функции методом трапеций.
*
* @param x Сетка координат.
* @param f Функция, которую нужно интегрировать.
* @return Значение интеграла.
*/
private suspend fun parallelIntegrate(
x: DoubleArray,
f: (Double) -> Double,
): Double = coroutineScope {
val numThreads = Runtime.getRuntime().availableProcessors()
val chunkSize = max(9, x.size / numThreads)
val results = mutableListOf<Deferred<Double>>()
x.asSequence().windowed(chunkSize+1, chunkSize, partialWindows=true).forEach {
results.add(async {
gaussQuadrature(it.toDoubleArray(), f)
})
}
val partialResults = results.awaitAll()
return@coroutineScope partialResults.sum()
}
/**
* Интегрирование одномерной функции методом трапеций.
*
* @param x Сетка координат.
* @param f Функция, которую нужно интегрировать.
* @return Значение интеграла или null, если функция не определена в какой-то точке.
*/
private fun integrateTrapezoidal(x: DoubleArray, f: (Double) -> Double): Double {
if (x.size < 2) {
return 0.0 // Так как parallelIntegrate передает куски внахлест, то остаток размера 1 дает 0,
// Так как он уже был просуммирован в предыдущем куске
}
var integral = 0.0
for (i in 0 until x.size - 1) {
val y1 = f(x[i])
val y2 = f(x[i + 1])
integral += (y1 + y2) * (x[i + 1] - x[i]) / 2.0
}
return integral
}
// Коэффициенты и узлы Гаусса-Лежандра для 5 точек
private val gaussPoints = doubleArrayOf(
-0.9061798459,
-0.5384693101,
0.0,
0.5384693101,
0.9061798459
)
private val gaussWeights = doubleArrayOf(
0.2369268851,
0.4786286705,
0.5688888889,
0.4786286705,
0.2369268851
)
private fun gaussQuadrature(grid: DoubleArray, func: (Double) -> Double): Double {
var integral = 0.0
for (i in 0 until grid.size - 1) {
val a = grid[i]
val b = grid[i + 1]
val h = (b - a) / 2.0
val mid = (a + b) / 2.0
for (j in gaussPoints.indices) {
val x = mid + h * gaussPoints[j]
integral += h * gaussWeights[j] * func(x)
}
}
return integral
}

@ -2,7 +2,7 @@ package ru.inr.mass.models
import space.kscience.kmath.real.div
import space.kscience.kmath.real.sum
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.Float64Buffer
private val defaultFss: FSS by lazy {
val stream = FSS::class.java.getResourceAsStream("/data/FS.txt") ?: error("Default FS resource not found")
@ -11,8 +11,8 @@ private val defaultFss: FSS by lazy {
val (e, p) = it.split("\t")
e.toDouble() to p.toDouble()
}.toList()
val es = DoubleBuffer(data.size) { data[it].first }
val ps = DoubleBuffer(data.size) { data[it].second }
val es = Float64Buffer(data.size) { data[it].first }
val ps = Float64Buffer(data.size) { data[it].second }
FSS(es, ps / ps.sum())
}
}

@ -1,29 +1,42 @@
plugins {
id("space.kscience.gradle.jvm")
kotlin("plugin.serialization")
id("com.github.johnrengelman.shadow") version "7.1.2"
id("org.graalvm.buildtools.native") version "0.10.5"
`maven-publish`
application
}
kotlin {
explicitApi = null
}
graalvmNative {
toolchainDetection.set(true)
}
val dataforgeVersion: String by rootProject.extra
val visionForgeVersion: String by rootProject.extra
val kmathVersion: String by rootProject.extra
val tablesVersion: String by rootProject.extra
dependencies {
implementation(projects.numassDataProto)
implementation(projects.numassModel)
implementation(projects.numassAnalysis)
implementation("space.kscience:dataforge-workspace:$dataforgeVersion")
implementation("space.kscience:kmath-jupyter:$kmathVersion")
implementation("space.kscience:tables-kt:$tablesVersion")
implementation("space.kscience:kmath-jupyter:$kmathVersion")
implementation("space.kscience:tables-kt-csv:$tablesVersion")
implementation("space.kscience:visionforge-plotly:$visionForgeVersion")
implementation("com.charleskorn.kaml:kaml:0.45.0")
implementation("com.github.ajalt.clikt:clikt:4.2.1")
implementation("org.apache.commons:commons-csv:1.10.0")
}
kscience{
jupyterLibrary("ru.inr.mass.notebook.NumassJupyter")
}
application {
// mainClass.set("ru.inr.mass.scripts.ApplicationKt")
mainClass.set("ru.inr.mass.scripts.Fit_customKt")
}

@ -1,87 +0,0 @@
package ru.inr.mass.notebook
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
import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.workspace.Numass
import ru.inr.mass.workspace.plotNumassBlock
import ru.inr.mass.workspace.plotNumassSet
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.DataTreeItem
import space.kscience.plotly.Plotly
import space.kscience.plotly.scatter
import space.kscience.plotly.toHTML
import space.kscience.plotly.toPage
internal class NumassJupyter : JupyterIntegration() {
override fun Builder.onLoaded() {
repositories(
"https://repo.kotlin.link",
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
)
import(
"ru.inr.mass.models.*",
"ru.inr.mass.data.analysis.*",
"ru.inr.mass.workspace.*",
"ru.inr.mass.data.api.*",
"ru.inr.mass.data.proto.*",
"space.kscience.dataforge.data.*",
"kotlinx.coroutines.*",
"kotlinx.coroutines.flow.*",
)
import<Numass>()
onLoaded {
declare("Numass" to Numass, "workspace" to Numass.workspace)
}
render<NumassBlock> {
HTML(Plotly.plotNumassBlock(it).toPage().render())
}
render<NumassFrame> { numassFrame ->
HTML(
Plotly.plot {
scatter {
x.numbers = numassFrame.signal.indices.map { numassFrame.tickSize.times(it).inWholeNanoseconds }
y.numbers = numassFrame.signal.toList()
}
}.toHTML()
)
}
render<NumassSet> { numassSet ->
HTML(Plotly.plotNumassSet(numassSet).toPage().render())
}
render<DataTree<NumassDirectorySet>> { tree ->
HTML(createHTML().div { numassTree(tree) })
}
}
}
private fun FlowContent.numassTree(tree: DataTree<NumassDirectorySet>) {
ul {
runBlocking {
tree.items.forEach { (token, treeItem) ->
li {
p { +token.toString() }
when (treeItem) {
is DataTreeItem.Leaf -> {}
is DataTreeItem.Node -> numassTree(treeItem.tree)
}
}
}
}
}
}

@ -0,0 +1,62 @@
/// generated by https://gemini.google.com/app/7627cdc6341c5973 (вроде правильно)
package ru.inr.mass.scripts
class BilinearInterpolator(
private val x: DoubleArray,
private val y: DoubleArray,
private val value: Array<DoubleArray>
) {
private val xSize: Int = x.size
private val ySize: Int = y.size
init {
if (value.size != xSize) {
throw IllegalArgumentException("Размерность value по x должна быть равна размерности x")
}
if (value[0].size != ySize) {
throw IllegalArgumentException("Размерность value по y должна быть равна размерности y")
}
if (xSize < 2 || ySize < 2) {
throw IllegalArgumentException("Размерность x и y должна быть как минимум 2 для билинейной интерполяции")
}
}
fun value(xQuery: Double, yQuery: Double): Double {
if (xQuery < x.first() || xQuery > x.last() || yQuery < y.first() || yQuery > y.last()) {
throw IllegalArgumentException("Точка запроса находится вне границ сетки")
}
var xIndex = -1
for (i in 0 until xSize - 1) {
if (xQuery >= x[i] && xQuery <= x[i + 1]) {
xIndex = i
break
}
}
if (xIndex == -1) xIndex = xSize - 2 // На случай, если xQuery == x.last()
var yIndex = -1
for (i in 0 until ySize - 1) {
if (yQuery >= y[i] && yQuery <= y[i + 1]) {
yIndex = i
break
}
}
if (yIndex == -1) yIndex = ySize - 2 // На случай, если yQuery == y.last()
val xWeight = (xQuery - x[xIndex]) / (x[xIndex + 1] - x[xIndex])
val yWeight = (yQuery - y[yIndex]) / (y[yIndex + 1] - y[yIndex])
val v00 = value[xIndex][yIndex]
val v10 = value[xIndex + 1][yIndex]
val v01 = value[xIndex][yIndex + 1]
val v11 = value[xIndex + 1][yIndex + 1]
return (1 - xWeight) * (1 - yWeight) * v00 +
xWeight * (1 - yWeight) * v10 +
(1 - xWeight) * yWeight * v01 +
xWeight * yWeight * v11
}
}

@ -0,0 +1,28 @@
package ru.inr.mass.scripts
import ru.inr.mass.workspace.buffer
import space.kscience.kmath.real.map
import space.kscience.kmath.real.step
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
fun main() {
val e = 18600.0
val u = WALL_L..18600.0 step 10.0
Plotly.page {
plot {
scatter {
name = "Adiabacity Function"
mode = ScatterMode.lines
x.buffer = u.map {
e - it
}
y.buffer = u.map {
adiabacity(e, it)
}
}
}
}.makeFile()
}

@ -0,0 +1,31 @@
package ru.inr.mass.scripts
import org.apache.commons.math3.analysis.interpolation.LinearInterpolator
// Таблички дал Влад
private val TABLE_X = arrayOf<Double>(
0.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 1100.0, 1200.0, 1300.0, 1400.0, 1500.0, 1600.0, 1700.0, 1800.0, 1900.0, 2000.0, 2100.0, 2200.0, 2300.0, 2400.0, 2500.0, 2600.0, 2700.0, 2800.0, 2900.0, 3000.0, 3100.0, 3200.0, 3300.0, 3400.0, 3500.0, 3600.0, 3700.0, 3800.0, 3900.0, 4000.0, 4100.0, 4200.0, 4210.0, 4400.0, 4500.0, 4600.0, 4700.0, 4800.0, 4900.0, 5000.0, 5100.0, 5200.0, 5300.0, 5400.0, 5500.0, 5600.0, 5700.0, 5800.0, 5850.0, 5900.0, 5950.0, 6000.0, 6050.0, 6100.0, 6150.0, 6200.0, 6250.0, 6300.0, 6350.0, 6400.0, 6450.0, 6500.0, 6550.0, 6600.0, 6650.0, 6700.0, 6750.0, 6800.0, 6850.0, 6900.0, 6950.0, 7000.0, 7050.0, 7100.0, 7150.0, 7200.0, 7250.0, 7300.0, 7350.0, 7400.0, 7450.0, 7500.0, 7550.0, 7600.0, 7650.0, 7700.0, 7750.0, 7800.0, 7850.0, 7900.0, 7950.0, 8000.0, 8050.0, 8100.0, 8150.0, 8200.0, 8250.0, 8300.0, 8350.0, 8400.0, 8450.0, 8500.0, 8550.0, 8600.0, 8650.0, 8700.0, 8750.0, 8800.0, 8850.0, 8900.0, 8950.0, 9000.0,
).toDoubleArray()
private val TABLE_Y = arrayOf<Double>(
1.00240290164948, 1.00017845630646, 1.00203716754913, 1.00221610069275, 1.00038015842438, 0.994577169418335, 1.00515520572662, 0.999377489089966, 1.00087404251099, 0.996169149875641, 0.998798131942749, 0.998405337333679, 1.00339663028717, 0.99450033903122, 0.997694253921509, 0.994965016841888, 0.995169341564179, 0.998219728469849, 0.997945725917816, 1.0012059211731, 1.00025320053101, 0.999431014060974, 1.00128185749054, 1.00263059139252, 0.995539963245392, 1.00312459468842, 1.00555884838104, 0.993147969245911, 0.999567568302155, 1.00013864040375, 0.99311101436615, 0.990257203578949, 0.994479060173035, 0.992072880268097, 0.990162968635559, 0.989075183868408, 0.99011492729187, 0.983498156070709, 0.991690993309021, 0.985046207904816, 0.983466565608978, 0.981356799602509, 0.984025597572327, 0.981970727443695, 0.977014005184174, 0.973981201648712, 0.97092479467392, 0.965949237346649, 0.967343509197235, 0.969820857048035, 0.97280490398407, 0.964862942695618, 0.96708345413208, 0.968482375144959, 0.96562671661377, 0.96340423822403, 0.955135881900787, 0.950935482978821, 0.935285091400147, 0.921773135662079, 0.927967965602875, 0.924734711647034, 0.906031787395477, 0.905169427394867, 0.897284090518951, 0.883931875228882, 0.87497353553772, 0.862376809120178, 0.845500528812408, 0.823084533214569, 0.814878404140472, 0.794394135475159, 0.783127129077911, 0.7618847489357, 0.744905948638916, 0.72154700756073, 0.69835764169693, 0.675829291343689, 0.659660696983337, 0.637992024421692, 0.612448275089264, 0.592042982578278, 0.570101141929627, 0.537925243377686, 0.523792922496796, 0.498814582824707, 0.479436606168747, 0.461632758378983, 0.441303879022598, 0.425816267728806, 0.402952134609222, 0.383262157440186, 0.374637126922607, 0.354630798101425, 0.342853039503098, 0.328158438205719, 0.312913507223129, 0.298821419477463, 0.2295962, 0.2083628, 0.1871294, 0.165896, 0.1446626, 0.1234292, 0.1021958, 0.0809623999999998, 0.0597289999999999, 0.0384956000000001, 0.0172621999999998, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
).toDoubleArray()
private val ADIABACITY_INTERPOLATOR = LinearInterpolator().interpolate(
TABLE_X,
TABLE_Y
)
fun adiabacity(e: Double, u: Double): Double {
val delta = e - u
if (delta > TABLE_X.last() || delta < 0.0) {
error("adiabacity: delta ($delta) out of [0:${TABLE_X.last()}]")
}
if (delta < 3000.0) {
return 1.0
}
return ADIABACITY_INTERPOLATOR.value(delta)
}

@ -0,0 +1,84 @@
package ru.inr.mass.scripts
import com.charleskorn.kaml.Yaml
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.Serializable
import ru.inr.mass.models.*
import space.kscience.kmath.expressions.Symbol
import java.io.File
import kotlin.io.path.Path
import kotlin.io.path.exists
@Serializable
data class FitParams(
val norm: Double = 254159.0,
val bkg: Double = 0.2,
val mnu2: Double = 0.0,
val e0: Double = 18569.0,
val msterile2: Double = 36e6,
val u2: Double = 0.0,
val thickness: Double = 0.3,
val trap: Double = 1.0,
val rearWall: Double = 0.01
)
@Serializable
data class FitCustomParams(
val spectrum: String = "TABLE_SLICE.tsv",
val full: String = "TABLE_FULL.tsv",
val postfix: String = "sample",
val fitParams: FitParams = FitParams(),
val fixBkg: Boolean = false,
val fixU2: Boolean = false,
val fixTrap: Boolean = false,
val fixRWall: Boolean = false
)
fun main (args: Array<String>) {
val usage = """
Usage:
application CONFIG_PATH # start fitting with configuration from CONFIG_PATH
application sample # prints configuration template
""".trimIndent()
if(args.size != 1) {
println(usage)
return
}
if(args[0] == "sample") {
val yaml = Yaml.default.encodeToString(FitCustomParams.serializer(), FitCustomParams())
println(yaml)
return
}
if (!Path(args[0]).exists()) {
println(usage)
return
}
val config = Yaml.default.decodeFromStream(FitCustomParams.serializer(), File(args[0]).inputStream())
val fitParams: Map<Symbol, Double> = mapOf(
NBkgSpectrum.norm to config.fitParams.norm,
NBkgSpectrum.bkg to config.fitParams.bkg,
NumassBeta.mnu2 to config.fitParams.mnu2,
NumassBeta.e0 to config.fitParams.e0,
NumassBeta.msterile2 to config.fitParams.msterile2,
NumassBeta.u2 to config.fitParams.u2,
NumassTransmission.thickness to config.fitParams.thickness,
NumassTransmission.trap to config.fitParams.trap,
rearWall to config.fitParams.rearWall
)
runBlocking {
processCustom(
config.spectrum,
config.full,
config.postfix,
fitParams,
config.fixBkg,
config.fixU2,
config.fixTrap,
config.fixRWall
)
}
}

@ -1,17 +0,0 @@
package ru.inr.mass.scripts
import ru.inr.mass.data.proto.NumassDirectorySet
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.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["Adiabacity_19.set_3"]?.await() ?: error("Not found")
Plotly.plotNumassSet(testSet).makeFile()
}

@ -1,40 +0,0 @@
package ru.inr.mass.scripts
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.channels
import ru.inr.mass.workspace.Numass
import ru.inr.mass.workspace.listFrames
import space.kscience.dataforge.io.write
import space.kscience.dataforge.io.writeUtf8String
import java.nio.file.Files
import kotlin.io.path.createDirectories
import kotlin.io.path.writeText
fun main() {
val point = Numass.readPoint("D:\\Work\\Numass\\data\\test\\set_7\\p59(30s)(HV1=14000)")
val channels: Map<Int, NumassBlock> = point.channels
//Initialize and create target directory
val targetDir = Files.createTempDirectory("numass_p101(30s)(HV1=14150)")
targetDir.createDirectories()
//dumping meta
targetDir.resolve("meta").writeText(point.meta.toString())
val pointTime = point.startTime
channels.forEach { (key, block) ->
targetDir.resolve("channel-$key.csv").write {
block.listFrames().forEach { frame ->
// val frameTime = pointTime.plus(frame.timeOffset, DateTimeUnit.NANOSECOND)
// writeUtf8String("$frameTime,")
writeUtf8String("${frame.timeOffset},")
val line = frame.signal.joinToString(",", postfix = "\n" )
writeUtf8String(line)
}
}
}
println("Exported to $targetDir")
}

@ -0,0 +1,340 @@
package ru.inr.mass.scripts
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.context
import com.github.ajalt.clikt.output.MordantHelpFormatter
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.help
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.help
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.double
import kotlinx.coroutines.runBlocking
import kotlinx.html.*
import ru.inr.mass.models.*
import ru.inr.mass.workspace.buffer
import ru.inr.mass.workspace.fitWith
import ru.inr.mass.workspace.freeParameters
import ru.inr.mass.workspace.iterations
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.data.XYErrorColumnarData
import space.kscience.kmath.data.indices
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.misc.Loggable
import space.kscience.kmath.optimization.*
import space.kscience.kmath.structures.toDoubleArray
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
import java.io.File
import kotlin.io.path.Path
import kotlin.io.path.nameWithoutExtension
import kotlin.math.pow
val rearWall: Symbol by symbol
class CustomSterileNeutrinoSpectrum(
source: DifferentiableKernel = NumassBeta,
transmission: DifferentiableKernel = NumassTransmission(),
resolution: DifferentiableKernel = NumassResolution(),
fss: FSS? = null
): SterileNeutrinoSpectrumFast(source, transmission, resolution, fss) {
override fun invoke(u: Double, arguments: Map<Symbol, Double>): Double {
val rearWall = arguments[rearWall]!!
return super.invoke(u, arguments) * (1.0 + rearWall * wallStep(u))
}
override fun derivativeOrNull(symbols: List<Symbol>): Spectrum? {
if (symbols.isEmpty()) return this
return when (symbols.singleOrNull() ?: TODO("First derivatives only")) {
rearWall -> Spectrum { u, arguments ->
wallStep(u) * super.invoke(u, arguments)
}
else -> super.derivativeOrNull(symbols)
}
}
}
class CustomArgs : CliktCommand() {
init {
context {
helpFormatter = { MordantHelpFormatter(it, showDefaultValues = true) }
}
}
val spectrum: String by argument().help("path to spectrum TSV file")
val full: String? by option().help("path to full spectrum (for test)")
val postfix: String? by option().help("save file postfix")
val norm: Double by option().double().default(8.311751921319484E8).help("NBkgSpectrum.norm")
val bkg: Double by option().double().default(1612.626961212948).help("NBkgSpectrum.bkg")
val fixBkg: Boolean by option().flag().help("Don't fit bkg variable")
val mnu2: Double by option().double().default(0.0).help("NumassBeta.mnu2")
val e0: Double by option().double().default(18572.0).help("NumassBeta.e0")
val msterile2: Double by option().double().default(0.0.pow(2)).help("NumassBeta.msterile2")
val u2: Double by option().double().default(1e-2).help("NumassBeta.u2")
val fixU2: Boolean by option().flag().help("Don't fit u2 variable")
val thickness: Double by option().double().default(0.3).help("NumassTransmission.thickness")
val trap: Double by option().double().default(1.0).help("NumassTransmission.trap")
val fixTrap: Boolean by option().flag().help("Don't fit trap variable")
val rwall: Double by option().double().default(0.17).help("rear wall")
val fixRwall: Boolean by option().flag().help("Don't fit rwall variable")
@UnstableKMathAPI
override fun run() {
val fitParams: Map<Symbol, Double> = mapOf(
NBkgSpectrum.norm to norm,
NBkgSpectrum.bkg to bkg,
NumassBeta.mnu2 to mnu2,
NumassBeta.e0 to e0,
NumassBeta.msterile2 to msterile2,
NumassBeta.u2 to u2,
NumassTransmission.thickness to thickness,
NumassTransmission.trap to trap,
rearWall to rwall
)
runBlocking {
processCustom(
spectrum,
full,
postfix,
fitParams,
fixBkg,
fixU2,
fixTrap,
fixRwall
)
}
}
}
fun main(args: Array<String>) = CustomArgs().main(args)
suspend fun fitNumassSpectrumCustom(
spectrum: NBkgSpectrum,
data: XYErrorColumnarData<Double, Double, Double>,
fitParams: List<Symbol>,
initial: Map<Symbol, Double>,
logger: Loggable
): XYFit {
return data.fitWith(
optimizer = QowOptimizer,
modelExpression = spectrum,
startingPoint = initial,
attributesBuilder = {
freeParameters(*fitParams.toTypedArray())
iterations(30)
OptimizationLog(logger)
}
)
}
@UnstableKMathAPI
suspend fun processCustom(
spectrumFile: String,
full: String?,
postfix: String?,
fitParams: Map<Symbol, Double>,
fixBkg: Boolean,
fixU2: Boolean,
fixTrap: Boolean,
fixRwall: Boolean
) {
val data = parse(spectrumFile)
val testData = if (full != null) parse(full) else data
val trapInterpolator = TrapInterpolator()
val spectrum: NBkgSpectrum = CustomSterileNeutrinoSpectrum(
// fss = FSS.default,
transmission = NumassTransmission(
// NumassTransmission.trapFunction,
trapFunc = { ei, ef, _ ->
val delta = ei - ef
trapInterpolator.value(ei, delta)
},
adjustX = false,
),
resolution = NumassResolution(1.7e-4, tailFunction = {e,u -> adiabacity(e,u) })
).withNBkg()
val logMessages = emptyList<String>().toMutableList()
val dumpLogger = Loggable { tag, block ->
logMessages += "[$tag] ${block()}"
println("[$tag] ${block()}")
}
val fitVars = mutableListOf(
NumassBeta.e0,
NBkgSpectrum.norm,
// NBkgSpectrum.bkg,
// rearWall,
// NumassBeta.u2,
// NumassBeta.mnu2,
// NumassBeta.msterile2,
// NumassTransmission.trap,
)
if (!fixBkg) {
fitVars += NBkgSpectrum.bkg
}
if (!fixU2) {
fitVars += NumassBeta.u2
}
if (!fixTrap) {
fitVars += NumassTransmission.trap
}
if (!fixRwall) {
fitVars += rearWall
}
val fit = fitNumassSpectrumCustom(spectrum, data, fitVars, fitParams, dumpLogger)
val dataPath = Path(spectrumFile)
Plotly.page {
h3 {
+"Fit for $spectrumFile ($postfix)"
}
plot {
scatter {
name = "Data"
mode = ScatterMode.markers
x.buffer = data.x
y.buffer = data.y
}
scatter {
name = "Initial"
mode = ScatterMode.lines
x.buffer = data.x
y.numbers = x.doubles.map { spectrum(it, fitParams + fit.result) }
}
scatter {
name = "Fit"
mode = ScatterMode.lines
x.buffer = data.x
y.numbers = data.x.toDoubleArray().map { spectrum(it, fitParams + fit.result) }
}
}
plot{
layout {
title = "Residuals"
}
scatter {
name = "Residuals"
mode = ScatterMode.markers
x.buffer = testData.x
y.numbers = testData.indices.map{
val value = spectrum(testData.x[it], fitParams + fit.result)
val dif = testData.y[it] - value
dif/testData.yErr[it]
}
File(dataPath.parent.toString(), dataPath.nameWithoutExtension + postfix + ".fit.tsv")
.printWriter().use {
out -> out.println("U_sp\tcounts\tresidials")
testData.indices.forEach{
val value = spectrum(testData.x[it], fitParams + fit.result)
val dif = testData.y[it] - value
val residial = dif/testData.yErr[it]
out.println("${testData.x[it]}\t${value}\t$residial")
}
}
}
}
plot {
layout {
title = "Residuals distribution"
}
histogram {
x.numbers = data.indices.map{
val value = spectrum(data.x[it], fitParams + fit.result)
val dif = data.y[it] - value
dif/data.yErr[it]
}
name = "Res histo"
}
}
p {
+"initial params = $fitParams"
}
br()
p {
+"fit result = ${fit.result}"
}
h4 {
+"Fit log:"
}
pre {
logMessages.forEach {
+it
+"\n"
}
}
h4 {
+"Residuals:"
}
table {
tr {
th { +"U_sp" }
th { +"Counts" }
th { +"residials" }
}
testData.indices.forEach {
tr {
td { +testData.x[it].toString() }
td {
val value = spectrum(testData.x[it], fitParams + fit.result)
+value.toString()
}
td {
val value = spectrum(testData.x[it], fitParams + fit.result)
val dif = testData.y[it] - value
+(dif/testData.yErr[it]).toString()
}
}
}
}
h4 {
+"Data:"
}
table {
tr {
th { +"U_sp" }
th { +"counts" }
th { +"residials" }
}
data.indices.forEach {
tr {
td { +data.x[it].toString() }
td { +data.y[it].toString() }
td { +data.yErr[it].toString() }
}
}
}
}.makeFile(path = Path(
dataPath.parent.toString(),
dataPath.nameWithoutExtension + postfix + ".html"
))
}

@ -0,0 +1,291 @@
package ru.inr.mass.scripts
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.context
import com.github.ajalt.clikt.output.MordantHelpFormatter
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.help
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.help
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.double
import kotlinx.coroutines.runBlocking
import kotlinx.html.*
import ru.inr.mass.models.*
import ru.inr.mass.workspace.buffer
import ru.inr.mass.workspace.fitWith
import ru.inr.mass.workspace.freeParameters
import ru.inr.mass.workspace.iterations
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.data.XYErrorColumnarData
import space.kscience.kmath.data.indices
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.misc.Loggable
import space.kscience.kmath.optimization.*
import space.kscience.kmath.structures.asBuffer
import space.kscience.kmath.structures.toDoubleArray
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
import java.io.File
import kotlin.io.path.Path
import kotlin.io.path.nameWithoutExtension
import kotlin.math.pow
@OptIn(UnstableKMathAPI::class)
fun parse(filename: String): XYErrorColumnarData<Double, Double, Double> {
val x: MutableList<Double> = mutableListOf()
val y: MutableList<Double> = mutableListOf()
val errors: MutableList<Double> = mutableListOf()
File(filename).forEachLine {
val array = it.split("\t").map { it.toDouble() }
x.add(array[0])
y.add(array[1])
errors.add(array[2])
//errors.add(array[1] / 100)
}
return XYErrorColumnarData.of(
x.asBuffer(),
y.asBuffer(),
errors.map { it }.asBuffer()
)
}
private class Args : CliktCommand() {
init {
context {
helpFormatter = { MordantHelpFormatter(it, showDefaultValues = true) }
}
}
val spectrum: String by argument().help("path to spectrum TSV file")
val full: String? by option().help("path to full spectrum (for test)")
val postfix: String? by option().help("save file postfix")
val norm: Double by option().double().default(8.311751921319484E8).help("NBkgSpectrum.norm")
val bkg: Double by option().double().default(1612.626961212948).help("NBkgSpectrum.bkg")
val mnu2: Double by option().double().default(0.0).help("NumassBeta.mnu2")
val e0: Double by option().double().default(18572.0).help("NumassBeta.e0")
val msterile2: Double by option().double().default(0.0.pow(2)).help("NumassBeta.msterile2")
val u2: Double by option().double().default(1e-2).help("NumassBeta.u2")
val thickness: Double by option().double().default(0.3).help("NumassTransmission.thickness")
val trap: Double by option().double().default(1.0).help("NumassTransmission.trap")
@UnstableKMathAPI
override fun run() {
val fitParams: Map<Symbol, Double> = mapOf(
NBkgSpectrum.norm to norm,
NBkgSpectrum.bkg to bkg,
NumassBeta.mnu2 to mnu2,
NumassBeta.e0 to e0,
NumassBeta.msterile2 to msterile2,
NumassBeta.u2 to u2,
NumassTransmission.thickness to thickness,
NumassTransmission.trap to trap
)
runBlocking {
process(spectrum, full, postfix, fitParams)
}
}
}
private fun main(args: Array<String>) = Args().main(args)
//fun main() {
// val fitParams = mapOf(
// NBkgSpectrum.norm to 8.499104797244802E8,
// NBkgSpectrum.bkg to 3996.411979640289,
// NumassBeta.mnu2 to 0.00,
// NumassBeta.e0 to 18571.862544620915,
// NumassBeta.msterile2 to 0.0,
// NumassBeta.u2 to -0.00,
// NumassTransmission.thickness to 0.3,
// NumassTransmission.trap to 1.0
// )
//
// runBlocking {
// process(
// "/home/chernov/data/fits/GEANT.tsv",
// "/home/chernov/data/fits/GEANT.tsv",
// "(no-kev)",
// fitParams
// )
// }
//}
private suspend fun fitNumassSpectrum(
spectrum: NBkgSpectrum,
data: XYErrorColumnarData<Double, Double, Double>,
initial: Map<Symbol, Double>,
logger: Loggable): XYFit {
return data.fitWith(
optimizer = QowOptimizer,
modelExpression = spectrum,
startingPoint = initial,
attributesBuilder = {
freeParameters(NumassBeta.e0,
NBkgSpectrum.norm,
NBkgSpectrum.bkg)
iterations(30)
OptimizationLog(logger)
}
)
}
@UnstableKMathAPI
private suspend fun process(spectrumFile: String, full: String?, postfix: String?, fitParams: Map<Symbol, Double>) {
val data = parse(spectrumFile)
val testData = if (full != null) parse(full) else data
val trapInterpolator = TrapInterpolator()
val spectrum: NBkgSpectrum = SterileNeutrinoSpectrum(
// fss = FSS.default,
transmission = NumassTransmission(
// NumassTransmission.trapFunction,
trapFunc = { ei, ef, _ ->
val delta = ei - ef
trapInterpolator.value(ei, delta)
},
adjustX = false,
),
resolution = NumassResolution(1.7e-4, tailFunction = {e,u -> adiabacity(e,u) })
).withNBkg()
val logMessages = emptyList<String>().toMutableList()
val dumpLogger = Loggable { tag, block ->
logMessages += "[$tag] ${block()}"
println("[$tag] ${block()}")
}
val fit = fitNumassSpectrum(spectrum, data, fitParams, dumpLogger)
val dataPath = Path(spectrumFile)
Plotly.page {
h3 {
+"Fit for $spectrumFile"
}
plot {
scatter {
name = "Data"
mode = ScatterMode.markers
x.buffer = data.x
y.buffer = data.y
}
scatter {
name = "Initial"
mode = ScatterMode.lines
x.buffer = data.x
y.numbers = x.doubles.map { spectrum(it, fitParams + fit.result) }
File(dataPath.parent.toString(), dataPath.nameWithoutExtension + postfix + ".fit")
.printWriter().use {
out -> out.println("U_sp\tcounts\tresidials")
data.indices.map{
val value = spectrum(data.x[it], fitParams + fit.result)
val dif = data.y[it] - value
out.println("${data.x[it]}\t${data.y[it]}\t${dif/data.yErr[it]}")
}
}
}
scatter {
name = "Fit"
mode = ScatterMode.lines
x.buffer = data.x
y.numbers = data.x.toDoubleArray().map { spectrum(it, fitParams + fit.result) }
}
}
plot{
layout {
title = "Residuals"
}
scatter {
name = "Residuals"
mode = ScatterMode.markers
x.buffer = testData.x
y.numbers = testData.indices.map{
val value = spectrum(testData.x[it], fitParams + fit.result)
val dif = testData.y[it] - value
dif/testData.yErr[it]
}
}
}
plot {
layout {
title = "Residuals distribution"
}
histogram {
x.numbers = data.indices.map{
val value = spectrum(data.x[it], fitParams + fit.result)
val dif = data.y[it] - value
dif/data.yErr[it]
}
name = "Res histo"
}
}
p {
+"initial params = $fitParams"
}
br()
p {
+"fit result = ${fit.result}"
}
h4 {
+"Fit log:"
}
pre {
logMessages.forEach {
+it
+"\n"
}
}
h4 {
+"Residuals:"
}
table {
tr {
th { +"U_sp" }
th { +"residials" }
}
testData.indices.forEach {
tr {
td { +testData.x[it].toString() }
td {
val value = spectrum(testData.x[it], fitParams + fit.result)
val dif = testData.y[it] - value
+(dif/testData.yErr[it]).toString()
}
}
}
}
h4 {
+"Data:"
}
table {
tr {
th { +"U_sp" }
th { +"counts" }
th { +"residials" }
}
data.indices.forEach {
tr {
td { +data.x[it].toString() }
td { +data.y[it].toString() }
td { +data.yErr[it].toString() }
}
}
}
}.makeFile(path = Path(
dataPath.parent.toString(),
dataPath.nameWithoutExtension + postfix + ".html"
))
}

@ -0,0 +1,85 @@
package ru.inr.mass.scripts
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.context
import com.github.ajalt.clikt.output.MordantHelpFormatter
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.help
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.help
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.double
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import ru.inr.mass.models.*
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.operations.toTypedArray
import kotlin.math.pow
private class CalcSpectrum : CliktCommand() {
init {
context {
helpFormatter = { MordantHelpFormatter(it, showDefaultValues = true) }
}
}
val spectrum: String by argument().help("path to spectrum TSV file")
val norm: Double by option().double().default(8.84e8).help("NBkgSpectrum.norm")
val bkg: Double by option().double().default(-1.702).help("NBkgSpectrum.bkg")
val mnu2: Double by option().double().default(0.0).help("NumassBeta.mnu2")
val e0: Double by option().double().default(18572.0).help("NumassBeta.e0")
val msterile2: Double by option().double().default(0.0.pow(2)).help("NumassBeta.msterile2")
val u2: Double by option().double().default(1e-2).help("NumassBeta.u2")
val thickness: Double by option().double().default(0.3).help("NumassTransmission.thickness")
val trap: Double by option().double().default(1.0).help("NumassTransmission.trap")
@UnstableKMathAPI
override fun run() {
val fitParams: Map<Symbol, Double> = mapOf(
NBkgSpectrum.norm to norm,
NBkgSpectrum.bkg to bkg,
NumassBeta.mnu2 to mnu2,
NumassBeta.e0 to e0,
NumassBeta.msterile2 to msterile2,
NumassBeta.u2 to u2,
NumassTransmission.thickness to thickness,
NumassTransmission.trap to trap
)
runBlocking {
calcSpectrum(spectrum, fitParams)
}
}
}
fun main(args: Array<String>) = CalcSpectrum().main(args)
suspend fun calcSpectrum(spectrumFile: String, fitParams: Map<Symbol, Double>) {
val data = parse(spectrumFile)
val range = data.x.toTypedArray();
runBlocking(Dispatchers.Default) {
val handles = range.map {
async(Dispatchers.Default) {
val spectrum: NBkgSpectrum = SterileNeutrinoSpectrum(
transmission = NumassTransmission(NumassTransmission.trapFunction),
).withNBkg()
val res = spectrum.invoke(it, fitParams)
return@async res
}
}
val out = handles.map { it.await() }
println(out.joinToString("\n"))
}
}

@ -1,144 +0,0 @@
package ru.inr.mass.scripts
import ru.inr.mass.data.analysis.NumassEventExtractor
import ru.inr.mass.data.analysis.energySpectrum
import ru.inr.mass.data.api.NumassEvent
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.api.channel
import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.models.*
import ru.inr.mass.workspace.Numass
import ru.inr.mass.workspace.Numass.readRepository
import ru.inr.mass.workspace.buffer
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.await
import space.kscience.dataforge.data.data
import space.kscience.dataforge.names.NameToken
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.asFunction
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.splineIntegrator
import space.kscience.kmath.integration.value
import space.kscience.kmath.interpolation.LinearInterpolator
import space.kscience.kmath.interpolation.interpolatePolynomials
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.real.step
import space.kscience.kmath.structures.asBuffer
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.scatter
import kotlin.math.pow
fun Spectrum.cutFrom(lowerCut: Double): Spectrum = Spectrum { x, arguments ->
if (x < lowerCut) 0.0 else this@cutFrom.invoke(x, arguments)
}
fun Spectrum.convolve(range: ClosedRange<Double>, function: (Double) -> Double): Spectrum = Spectrum { x, arguments ->
DoubleField.splineIntegrator.integrate(range) { y ->
this@convolve.invoke(y, arguments) * function(x - y)
}.value
}
/**
* E = A * ADC +B
* Channel A B
* 0 0.01453 1.3
* 2 0.01494 -4.332
* 3 0.01542 -5.183
* 4 0.01573 -2.115
* 5 0.0152 -3.808
* 6 0.0155 -3.015
* 7 0.01517 -0.5429
*/
val calibration: (NumassEvent) -> Double = {
when (it.channel) {
0 -> 0.01453 * it.amplitude + 1.3
2 -> 0.01494 * it.amplitude - 5.183
3 -> 0.01542 * it.amplitude - 5.183
4 -> 0.01573 * it.amplitude - 2.115
5 -> 0.0152 * it.amplitude - 3.808
6 -> 0.0155 * it.amplitude - 3.015
7 -> 0.01517 * it.amplitude - 0.5429
else -> error("Unrecognized channel ${it.channel}")
} * 1000.0
}
private val neutrinoSpectrum = NumassBeta.withFixedX(0.0)
private val args: Map<Symbol, Double> = mapOf(
NBkgSpectrum.norm to 8e5,
NBkgSpectrum.bkg to 2.0,
NumassBeta.mnu2 to 0.0,
NumassBeta.e0 to 18575.0,
NumassBeta.msterile2 to 1000.0.pow(2),
NumassBeta.u2 to 0.0,
NumassTransmission.thickness to 1.0,
NumassTransmission.trap to 1.0
)
suspend fun main() {
val repo: DataTree<NumassDirectorySet> = readRepository("D:\\Work\\Numass\\data\\2021_11\\Adiabacity_17\\")
val gunEnergy = 17000.0
val hv = 16900.0
//select point number 2 (U = 16900 V) from each directory
val points: Map<NameToken, NumassPoint?> = repo.items.mapValues {
val directory = it.value.data?.await()
val point = directory?.points?.find { point -> point.voltage == hv }
point
}
val spectrum: Map<Double, Long> = points.values.first()!!
.energySpectrum(NumassEventExtractor.TQDC, calibration)
.filter { it.key > 9000.0 }
.toSortedMap()
// //the channel of spectrum peak position
// val argmax = spectrum.maxByOrNull { it.value }!!.key
//
// // convert channel to energy
// fun Short.toEnergy(): Double = toDouble() / argmax * gunEnergy
val norm = spectrum.values.sum().toDouble()
val interpolated: PiecewisePolynomial<Double> = LinearInterpolator(DoubleField).interpolatePolynomials(
spectrum.keys.map { it - gunEnergy }.asBuffer(),
spectrum.values.map { it.toDouble() / norm }.asBuffer()
)
//convolve neutrino model with the gun spectrum
val model: Spectrum = neutrinoSpectrum
.cutFrom(14000.0)
.convolve(0.0..18500.0, interpolated.asFunction(DoubleField, 0.0))
val tritiumData = Numass.readPoint("D:\\Work\\Numass\\data\\2021_11\\Tritium_2\\set_11\\p0(30s)(HV1=14000)")
Plotly.plot {
scatter {
name = "gun"
x.numbers = spectrum.keys
y.numbers = spectrum.values.map { it.toDouble() / norm }
}
scatter {
name = "convoluted"
x.buffer = 0.0..19000.0 step 100.0
y.numbers = x.doubles.map { model(it, args) }
val yNorm = y.doubles.maxOrNull()!!
y.numbers = y.doubles.map { it / yNorm }
}
scatter {
name = "tritium"
val tritiumSpectrum = tritiumData.energySpectrum(NumassEventExtractor.TQDC, calibration).toSortedMap()
x.numbers = tritiumSpectrum.keys
y.numbers = tritiumSpectrum.values.map { it.toDouble() }
val yNorm = y.doubles.maxOrNull()!!
y.numbers = y.doubles.map { it / yNorm }
}
}.makeFile()
}

@ -1,63 +0,0 @@
package ru.inr.mass.scripts
import ru.inr.mass.workspace.buffer
import space.kscience.kmath.functions.asFunction
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.splineIntegrator
import space.kscience.kmath.integration.value
import space.kscience.kmath.interpolation.interpolatePolynomials
import space.kscience.kmath.interpolation.splineInterpolator
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.real.step
import space.kscience.plotly.Plotly
import space.kscience.plotly.layout
import space.kscience.plotly.makeFile
import space.kscience.plotly.models.AxisType
import space.kscience.plotly.scatter
import kotlin.math.PI
import kotlin.math.exp
import kotlin.math.pow
import kotlin.math.sqrt
fun main() {
val backScatteringSpectrum: List<Pair<Double, Double>> = {}.javaClass
.getResource("/simulation/Gun19_E_back_scatt.dat")!!.readText()
.lineSequence().drop(2).mapNotNull {
if (it.isBlank()) return@mapNotNull null
val (e, p) = it.split('\t')
Pair(e.toDouble(), p.toDouble())
}.toList()
val interpolated = DoubleField.splineInterpolator
.interpolatePolynomials(backScatteringSpectrum)
.asFunction(DoubleField, 0.0)
val sigma = 0.3
val detectorResolution: (Double) -> Double = { x ->
1.0 / sqrt(2 * PI) / sigma * exp(-(x / sigma).pow(2) / 2.0)
}
val convoluted: (Double) -> Double = { x ->
DoubleField.splineIntegrator.integrate(-2.0..2.0) { y ->
detectorResolution(y) * interpolated(x - y)
}.value
}
Plotly.plot {
// scatter {
// name = "simulation"
// x.numbers = backScatteringSpectrum.map { 19.0 - it.first }
// y.numbers = backScatteringSpectrum.map { it.second }
// }
scatter {
name = "smeared"
x.buffer = 0.0..20.0 step 0.1
y.numbers = x.doubles.map { convoluted(19.0 - it) * 0.14/0.01 + 0.86 * detectorResolution(it - 19.0) }
println(y.doubles.sum()*0.1)//Norm check
}
layout {
yaxis.type = AxisType.log
}
}.makeFile()
}

@ -0,0 +1,117 @@
package ru.inr.mass.scripts
import ru.inr.mass.models.*
import ru.inr.mass.models.NBkgSpectrum.Companion.bkg
import ru.inr.mass.models.NBkgSpectrum.Companion.norm
import ru.inr.mass.models.NumassBeta.e0
import ru.inr.mass.models.NumassBeta.mnu2
import ru.inr.mass.models.NumassBeta.msterile2
import ru.inr.mass.models.NumassBeta.u2
import ru.inr.mass.models.NumassTransmission.Companion.thickness
import ru.inr.mass.models.NumassTransmission.Companion.trap
import ru.inr.mass.workspace.buffer
import space.kscience.dataforge.meta.Value
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.real.step
import space.kscience.kmath.structures.asBuffer
import space.kscience.kmath.structures.toDoubleArray
import space.kscience.plotly.*
import space.kscience.plotly.models.AxisType
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.TraceType
import kotlin.math.pow
fun main() {
val maxDelta = (WALL_R - WALL_L)
val rearTrapInterpolator = RearTrapInterpolator()
val range = (WALL_L - 10.0)..18600.0 step 10.0
val spectrum: NBkgSpectrum = SterileNeutrinoSpectrum(
fss = null,
transmission = NumassTransmission(
trapFunc = { ei, ef, _ ->
val delta = ei - ef
rearTrapInterpolator.value(ei, delta)
},
adjustX = false,
),
resolution = NumassResolution(1.7e-4, tailFunction = {
e,u -> adiabacity(e,u)
})
).withNBkg()
val args: Map<Symbol, Double> = mapOf(
norm to 1000.0,
bkg to 0.0,
mnu2 to 0.0,
e0 to 18575.0,
msterile2 to 0000.0.pow(2),
u2 to 0e-2,
thickness to 0.0,
trap to 0.521
)
Plotly.page {
plot {
layout {
title = "Sterile neutrino spectrum"
yaxis.type = AxisType.log
}
scatter {
name = "NumassBeta + RearTrap"
mode = ScatterMode.lines
x.buffer = range
y.numbers = x.doubles.map {
val value = spectrum(it, args)
println("${it}\t${value}")
value
}
}
scatter {
name = "(NumassBeta + RearTrap) / NumassBeta"
mode = ScatterMode.lines
x.buffer = range
y.numbers = x.doubles.map { spectrum(it, args) / NumassBeta(0.0, it, args) }
}
scatter {
name = "NumassBeta"
mode = ScatterMode.lines
x.buffer = range
y.numbers = x.doubles.map { NumassBeta(0.0, it, args) }
}
}
plot {
val eis = (WALL_L..WALL_R step 100.0).toDoubleArray()
val deltas = (0.0..maxDelta step 10.0).toDoubleArray()
val values = eis.map { ei ->
deltas.map { rearTrapInterpolator.value(ei, it) }.toList()
}
layout {
}
trace {
type = TraceType.surface
x.numbers = deltas.toList()
y.numbers = eis.toList()
z.value = Value.of(values)
}
}
plot {
for (HV in (WALL_L..WALL_R step 1000.0)) {
scatter {
name = "${HV / 1000.0} keV"
mode = ScatterMode.lines
x.buffer = (0.0..90.0 step 1.0).toDoubleArray().plus((100.0..maxDelta step 10.0).toDoubleArray()).asBuffer()
y.numbers = x.doubles.map {
rearTrapInterpolator.value(HV, it)
}
}
}
}
}.makeFile()
}

@ -0,0 +1,76 @@
// Code generated by trap-spectrum-2024-11.jl Julia notebook 2025-03-11T12:56:45.212
package ru.inr.mass.scripts
import org.apache.commons.math3.analysis.interpolation.PiecewiseBicubicSplineInterpolator
class RearTrapInterpolator {
private val x = arrayOf(10000.0, 12000.0, 14000.0, 16000.0, 18000.0, 19000.0, ).toDoubleArray()
private val yCoarse = arrayOf(
100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 1100.0, 1200.0, 1300.0, 1400.0, 1500.0, 1600.0, 1700.0, 1800.0, 1900.0, 2000.0, 2100.0, 2200.0, 2300.0, 2400.0, 2500.0, 2600.0, 2700.0, 2800.0, 2900.0, 3000.0, 3100.0, 3200.0, 3300.0, 3400.0, 3500.0, 3600.0, 3700.0, 3800.0, 3900.0, 4000.0, 4100.0, 4200.0, 4300.0, 4400.0, 4500.0, 4600.0, 4700.0, 4800.0, 4900.0, 5000.0, 5100.0, 5200.0, 5300.0, 5400.0, 5500.0, 5600.0, 5700.0, 5800.0, 5900.0, 6000.0, 6100.0, 6200.0, 6300.0, 6400.0, 6500.0, 6600.0, 6700.0, 6800.0, 6900.0, 7000.0, 7100.0, 7200.0, 7300.0, 7400.0, 7500.0, 7600.0, 7700.0, 7800.0, 7900.0, 8000.0, 8100.0, 8200.0, 8300.0, 8400.0, 8500.0, 8600.0, 8700.0, 8800.0, 8900.0, 9000.0,
).toDoubleArray()
private val gridCoarse = arrayOf(
arrayOf(
0.0007805053872790702, 0.0007805053872790702, 0.0006731202450986702, 0.0006030148166265464, 0.0005485627486065162, 0.0005170758080918605, 0.00048803470514784445, 0.00047186643152298443, 0.0004569082038541251, 0.0004377791794858592, 0.000428690961986535, 0.0004096906659114607, 0.00041252268836167497, 0.00040492771906337294, 0.0003952988427326442, 0.00038561847508463885, 0.0003876008907997889, 0.00037786903183450695, 0.00037395569172148346, 0.00036957892975297043, 0.00036816291852786326, 0.00036504769383262744, 0.00036504769383262744, 0.0003645842719771379, 0.0003670301095477775, 0.00035459495642547274, 0.0003630395324588391, 0.0003555475457950903, 0.0003678797162828418, 0.0003508618359229175, 0.0003503984140674279, 0.0003611858450368806, 0.0003564228981887929, 0.00035951237722539034, 0.0003600530360567949, 0.0003601045273740716, 0.0003600272903981566, 0.0003626276019206261, 0.0003601045273740716, 0.00035904895536990075, 0.0003607224231813911, 0.0003733635415728023, 0.0003702998081948432, 0.0003704027908293964, 0.00037913056910778416, 0.00037568065085025036, 0.000378538418959103, 0.00037931078871825244, 0.00038518079888778757, 0.0003882445322657467, 0.0003951443687808143, 0.00039313620740702595, 0.000406910134778523, 0.0003992636741629443, 0.0004118275555784406, 0.0004128573819239731, 0.00041656475676789, 0.00042853648803470513, 0.00042645108968500183, 0.00043196066063360067, 0.00043685233577487996, 0.0004486438474312269, 0.00045881338259336023, 0.0004621860638749791, 0.00046846800458272725, 0.0004760887195396676, 0.00048504820874580024, 0.0004977923097717647, 0.0005093006191830902, 0.0005208604199116924, 0.0005250569622697373, 0.0005362048324601264, 0.000546400113280898, 0.0005621822020261834, 0.0005776810885264473, 0.0005902192242833053, 0.000602165209891482, 0.0006229677020712383, 0.0006481469562195075, 0.0006624357967637707, 0.000684731537144549, 0.0007208269505554626, 0.0007359396521761519, 0.0007688940952331912, 0.0007981669091049521, 0.0008345970160781638, 0.0008811194212375938, 0.0009320958253414518, 0.0009804204266055637, 0.0010394037305459368,
).toDoubleArray(),
arrayOf(
0.000710792137318904, 0.000710792137318904, 0.0005979900532347581, 0.0005400702245744824, 0.0004930135815562672, 0.0004664219446646828, 0.00043769370964918605, 0.00042062666680395814, 0.00041002090262260983, 0.00039449838854165595, 0.00038327481285459805, 0.0003749086153814471, 0.0003615226994244056, 0.00035184365250162176, 0.00034530514739952836, 0.0003384577365445802, 0.00034054285037635017, 0.00033094102989178004, 0.00032782623021716074, 0.00032623021716074425, 0.0003208501086318564, 0.00031912538484508377, 0.0003138225027544096, 0.00031464625142868914, 0.00031613929590082067, 0.0003140541820690507, 0.00030918891646158756, 0.00031091364024836025, 0.00030460681446090797, 0.0003082364570569519, 0.0003030108014044915, 0.00030084846113450785, 0.0003042206822698395, 0.00029595745338097346, 0.00030164646766271615, 0.00030198111556164217, 0.00029701288136989404, 0.000303062285696634, 0.0002989692844713078, 0.00030445236158448054, 0.00029799108292060094, 0.00030658895970839294, 0.00030249595848306685, 0.0003076443876973136, 0.0003111968038551438, 0.00031353933914762605, 0.00030386029222484223, 0.0003005138132355818, 0.0003068721233151765, 0.0003152125786422563, 0.0003072067712141026, 0.000312870043349774, 0.0003158561322940371, 0.0003207471400475715, 0.00031490367288940143, 0.0003222916688118455, 0.0003210560458004263, 0.0003274915823182347, 0.00032324412821648114, 0.0003382517993760104, 0.000326307443598958, 0.00033511125755531987, 0.00033570332691495823, 0.00034491901520845993, 0.0003381230886456542, 0.0003475961983998682, 0.00034847143136629017, 0.0003533881812658958, 0.0003546752885694575, 0.0003588455162329973, 0.000362887033166181, 0.0003628355488740385, 0.0003678037830657866, 0.00037609275410072383, 0.00038183325267460903, 0.00038546289527065296, 0.0003925934697323846, 0.00039617162803628613, 0.00040214380592481233, 0.0004039200140037275, 0.0004150148789604292, 0.0004234325607257226, 0.0004234583028717938, 0.00043622640732312576, 0.000441658000144156, 0.00044227581164986565, 0.00045772109929260584, 0.0004633071449900635, 0.0004745049785310502, 0.0004873245672745245,
).toDoubleArray(),
arrayOf(
0.0006538233855815509, 0.0006538233855815509, 0.0005522610866599747, 0.0004885079659228374, 0.00045018402697346406, 0.0004202506884925231, 0.00040277456052299694, 0.0003840115306411345, 0.0003655830952564795, 0.0003564203536406455, 0.0003445036419324119, 0.00033593287519625254, 0.00032689882377165213, 0.0003192031503358814, 0.0003121509278562788, 0.00030880498288420456, 0.00030159833217512165, 0.00030226752116953645, 0.000295858749646102, 0.00028983604869636836, 0.0002898617867346151, 0.000284817131238257, 0.00028188299487813035, 0.0002778678609116413, 0.0002752940570869688, 0.0002745733920160606, 0.00027254008699456925, 0.00026940004632846883, 0.00026808740637788585, 0.000266491648006589, 0.00026659460015957583, 0.0002667490283890562, 0.00026463850925282473, 0.0002649473657117854, 0.0002642781767173706, 0.00026237356188711295, 0.00025689135974056056, 0.00026296553676678763, 0.0002610866599747767, 0.00026373767791418936, 0.0002576892389262091, 0.0002592077831827658, 0.00026098370782178985, 0.000258718760456078, 0.000260494685095102, 0.000259001878876792, 0.0002643811288703575, 0.0002653076982472396, 0.0002595166396417265, 0.0002656165547062003, 0.0002645870331763313, 0.00026070058940107585, 0.0002663114817388619, 0.00026432965279386405, 0.0002639693202584099, 0.000263403083416982, 0.0002672637891539907, 0.00026847347695158676, 0.0002738269889069055, 0.00026855069106632693, 0.0002706612102025584, 0.00026808740637788585, 0.00027501093866625487, 0.0002734923944096981, 0.00027513962885748847, 0.0002741615834041129, 0.0002795665714359252, 0.00028239775564306487, 0.00027902607263274393, 0.00028870357501351246, 0.00028721076879520245, 0.00028785421975137057, 0.00028679896018325485, 0.0002892698118549404, 0.0002937482305098705, 0.00029199804390909323, 0.00029827812524129413, 0.0002978405785910998, 0.0003058193704475845, 0.0003060252747535583, 0.0003067459398244666, 0.00030847038838699713, 0.00031377242426582243, 0.0003133606156538749, 0.00032422206779399274, 0.0003189457699534142, 0.0003293696754433377, 0.0003299616503230123, 0.00033760584768228964, 0.00033531516227833116,
).toDoubleArray(),
arrayOf(
0.0006080969826699049, 0.0006080969826699049, 0.000510383649610999, 0.00045429753426913104, 0.0004250710081093319, 0.00038305787675462063, 0.0003740532252089079, 0.00035426871938418474, 0.00033721133659902027, 0.0003207456880582884, 0.00031171530893673075, 0.00030088399950603057, 0.0003023247437533446, 0.00029445210554480717, 0.0002894352282550529, 0.0002831576997488989, 0.0002753622442678961, 0.0002718375663771457, 0.0002669750545424608, 0.00026646050302556293, 0.0002600800642160293, 0.0002589223233030091, 0.0002549860041987404, 0.0002557835590499321, 0.0002490172066027251, 0.0002549602766228955, 0.00024461779113324825, 0.00024441197052648913, 0.0002453638908327502, 0.0002421479438521385, 0.0002379543489894208, 0.00023653933231795166, 0.00023911208990244103, 0.0002392407277816655, 0.0002329374716996666, 0.00023579323261844977, 0.00023466121928127442, 0.0002320112789692504, 0.0002332204750339604, 0.000233554933519944, 0.00023412094018853167, 0.00023113654139052402, 0.00022876960441279383, 0.00023044189684271187, 0.0002319855513934055, 0.00022869242168525912, 0.0002268657638002717, 0.0002303904416910221, 0.00022735458774132466, 0.00022601675379739017, 0.00022606820894908, 0.00022897542501955297, 0.00022943852138476107, 0.00022967006956736507, 0.0002328088338204421, 0.00023424957806775614, 0.0002280492322891368, 0.00022727740501379, 0.00023383793685423785, 0.0002367451529247108, 0.000231625365331577, 0.0002336063886716338, 0.00023530440867739676, 0.0002355874120116906, 0.00023090499320791997, 0.00023661651504548636, 0.00023828880747540446, 0.00023219137200016467, 0.00024222512657967317, 0.00023705388383484955, 0.00024322850203762402, 0.00023589614292182933, 0.0002464959041699255, 0.0002440775120405055, 0.00024698472811097847, 0.00024582698719795824, 0.00024780801053801504, 0.0002447978841641625, 0.00024747355205203143, 0.0002515642366113695, 0.0002476021899312559, 0.00025516609722965464, 0.0002547544560161363, 0.0002544714526818425, 0.0002624470011937595, 0.0002573786687523155, 0.0002638620178652287, 0.00025925678178899273, 0.0002595397851232865, 0.0002673609681801342,
).toDoubleArray(),
arrayOf(
0.0005667653424597744, 0.0005667653424597744, 0.00047295059449383944, 0.00042668508386586596, 0.0003962094117707469, 0.0003662215558254234, 0.0003392376203814722, 0.00032776110359417803, 0.0003106875383513355, 0.00030265140914680956, 0.0002929721097534988, 0.00028380630104418334, 0.00028111047495320816, 0.000278311950725434, 0.00026557738176235135, 0.00026601384884374736, 0.0002577209742972238, 0.00024994159043469555, 0.000245987712167932, 0.00024460128732114474, 0.00024116089973837652, 0.00023938935687859282, 0.00023705297426641436, 0.00023214913823425959, 0.00022893982145928918, 0.00022593590095791686, 0.00022896549599348896, 0.00022069829598116513, 0.00021795112082179048, 0.00022246983884094884, 0.0002155633891412125, 0.0002210834139941616, 0.00021641064876980472, 0.0002151525965940163, 0.00021810516802698906, 0.00021597418168840872, 0.00021540934193601394, 0.00021112169472465347, 0.00021797679535599026, 0.0002123540723662421, 0.0002096839208094667, 0.00020942717546746907, 0.0002066286512396949, 0.00020770698167608495, 0.00020806642515488165, 0.00020809209968908137, 0.00020678269844489347, 0.00020288016924652943, 0.00020827182142847973, 0.0002115068127376499, 0.00020549897173490533, 0.0002057043680085034, 0.00020385580154612046, 0.00020501115558510977, 0.00020526790092710744, 0.00020544762266650577, 0.00020632055682929772, 0.00020637190589769725, 0.0002070394437868911, 0.0002069624201842918, 0.00020593543881630125, 0.00020205858415213703, 0.0002052935754613072, 0.00020857991583887687, 0.00020896503385187335, 0.00020840019409947857, 0.00020829749596267948, 0.000211712209011248, 0.0002063462313634975, 0.000210736576711657, 0.0002070137692526913, 0.0002077326562102847, 0.00020852856677047737, 0.00021225137422944306, 0.00021484450218361916, 0.00021107034565625391, 0.00021194327981904586, 0.0002173862810693957, 0.00021335537920003284, 0.00021615390342780705, 0.00021327835559743357, 0.00021625660156460614, 0.00021599985622260847, 0.00022069829598116513, 0.00021607687982520778, 0.000214536407773222, 0.00021920917299757888, 0.0002214942065413578, 0.00022390761275613557, 0.00022701423139430695,
).toDoubleArray(),
arrayOf(
0.0005479427438980562, 0.0005479427438980562, 0.0004632291784324396, 0.00041283744236910466, 0.0003757945105609578, 0.00035376898353989755, 0.0003343105342602195, 0.0003201916066826168, 0.00030807499974329225, 0.0002923131424112048, 0.0002849456292934375, 0.00027234127758325033, 0.00027123743415445595, 0.0002654358384589319, 0.00025855607011202725, 0.00025011038434287947, 0.0002467475125016686, 0.00024341031143787156, 0.0002383274975099346, 0.00023488761333648227, 0.00023740334952303697, 0.00022924004230544118, 0.00022456796081612537, 0.00022931705463768263, 0.00022189819996508772, 0.0002218468584102601, 0.000220409294875086, 0.00021219464610266258, 0.00021902307289473953, 0.00021571154260835635, 0.00021450501606990667, 0.0002095762268064526, 0.0002132214771992155, 0.00020975592224834936, 0.00020654707507162146, 0.00020824134638093382, 0.00020341524022713504, 0.00020521219464610265, 0.00020113054103730477, 0.00020292749545627238, 0.00019941059895057863, 0.0001968435212091963, 0.0002035949356690318, 0.00019512357912247015, 0.00020338956944972124, 0.00019876882951523305, 0.00019992401449885508, 0.0001958423608900572, 0.00019496955445798722, 0.00019566266544816043, 0.000195868031667471, 0.00019535461611919455, 0.00019550864078367747, 0.0001990512080667851, 0.0001990512080667851, 0.00019170936572643167, 0.0001937373571421237, 0.00019450748046453837, 0.00019740827831230042, 0.00019702321665109306, 0.00019014344830418843, 0.00019476418823867662, 0.00019740827831230042, 0.0001972029120929898, 0.00019753663219936954, 0.00019571400700298808, 0.00019481552979350427, 0.00019876882951523305, 0.00019522626223212542, 0.00019933358661833716, 0.0002011562118147186, 0.00019712589976074836, 0.0002039286557754115, 0.00019812706007988747, 0.0002015926150307536, 0.00019869181718299158, 0.0001990768788441989, 0.00020231139679834065, 0.00020174663969523655, 0.0002046987790978262, 0.00020264511690472033, 0.0002039029849979977, 0.00020346658178196269, 0.00020297883701110003, 0.00020462176676558472, 0.00020503249920420592, 0.00020187499358230565, 0.00020939653136455583, 0.0002041340219947221, 0.00020811299249386467,
).toDoubleArray(),
)
// private val coarseInterpolator = PiecewiseBicubicSplineInterpolator().interpolate(x, yCoarse, gridCoarse)
private val coarseInterpolator = BilinearInterpolator(x, yCoarse, gridCoarse)
private val yFine = arrayOf(
0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0,
).toDoubleArray()
private val gridFine = arrayOf(
arrayOf(
0.009824543336379903, 0.009824543336379903, 0.0002754785474299396, 0.00011585546387240451, 6.436414659578028e-5, 4.1193053821299383e-5, 1.802196104681848e-5, 2.5745658638312115e-5, 1.2872829319156057e-5, 5.149131727662423e-6, 7.723697591493634e-6, 0.0, 0.0010555720041707968, 0.004997232341696381, 0.003480813047899798, 0.0024561358340949757, 0.0021265914035245807, 0.002059652691064969, 0.001704362601856262, 0.0015318666889795709, 0.001289857497779437, 0.0012203442194559943, 0.0010967650579920961, 0.0009036726182047552, 0.0008882252230217679, 0.0012924320636432682, 0.0015241429913880771, 0.0012409407463666439, 0.0014546297130646345, 0.001397989264060348, 0.0014546297130646345, 0.0014057129616518414, 0.0011456818094048892, 0.0012563881415496312, 0.001155980072860214, 0.0010916159262644336, 0.0009577385013452107, 0.0009397165402983922, 0.0010993396238559274, 0.0010324009113963158, 0.0010246772138048223, 0.0011173615849027457, 0.0011353835459495642, 0.0010529974383069656, 0.0012538135756858, 0.0012332170487751504, 0.0010324009113963158, 0.001107063321447421, 0.0011019141897197584, 0.0009963569893026787, 0.0010710193993537839, 0.0011147870190389147, 0.0010324009113963158, 0.001047848306579303, 0.000937141974434561, 0.0009731858965281979, 0.0010298263455324845, 0.0010401246089878095, 0.0010324009113963158, 0.0010143789503494973, 0.0009886332917111852, 0.0010066552527580037, 0.0009525893696175483, 0.0009834841599835227, 0.000962887633072873, 0.0008727778278387806, 0.0009577385013452107, 0.001011804384485666, 0.000924269145115405, 0.0009165454475239113, 0.0009036726182047552, 0.0010272517796686533, 0.0009036726182047552, 0.0009551639354813794, 0.0008753523937026119, 0.0009525893696175483, 0.0010864667945367711, 0.000950014803753717, 0.000924269145115405, 0.000950014803753717, 0.0009165454475239113, 0.0009294182768430673, 0.0008624795643834559, 0.000986058725847354, 0.0008985234864770928, 0.0008727778278387806, 0.0009834841599835227, 0.0008058391153791691, 0.001009229818621835, 0.0009577385013452107, 0.0009345674085707297, 0.0009113963157962488, 0.000937141974434561, 0.0009036726182047552, 0.0009680367648005355, 0.000816137378834494, 0.0008135628129706628, 0.0008187119446983253, 0.0008624795643834559, 0.0008779269595664431, 0.0008367339057451437,
).toDoubleArray(),
arrayOf(
0.008929950472110959, 0.008929950472110959, 0.0003011831090334339, 0.0001081170134991814, 4.1187433713973865e-5, 2.5742146071233666e-5, 1.8019502249863567e-5, 2.31679314641103e-5, 7.7226438213701e-6, 5.148429214246733e-6, 5.148429214246733e-6, 5.148429214246733e-6, 0.0009035493271003017, 0.004481707631001782, 0.0033027173409392796, 0.0024249101599102115, 0.001964125745235129, 0.0016861105676658052, 0.0015187866182027863, 0.0013154236642400404, 0.0011480997147770215, 0.0010348342720635933, 0.001003943696778113, 0.0008443423911364642, 0.000849490820350711, 0.0011043380664559244, 0.0014570054676318256, 0.0011455255001698982, 0.0013102752350257936, 0.001397798531667988, 0.0011326544271342814, 0.0012021582215266122, 0.001109486495670171, 0.001052853774313457, 0.0010708732765633206, 0.000947310975421399, 0.0008649361079934512, 0.0008958266832789315, 0.0009370141169929055, 0.0010065179113852363, 0.0010425569158849634, 0.0009833499799211261, 0.0009061235417074251, 0.0010065179113852363, 0.0010631506327419505, 0.00103226005745647, 0.0010785959203846907, 0.0010065179113852363, 0.000996221052956743, 0.0008932524686718083, 0.0009009751124931783, 0.0009061235417074251, 0.0009782015507068793, 0.0009653304776712625, 0.0008829556102433148, 0.0009086977563145484, 0.0009241430439572886, 0.0009679046922783859, 0.0009884984091353727, 0.0009421625462071522, 0.0008469166057435876, 0.0008134518158509839, 0.0009936468383496195, 0.0009447367608142756, 0.0008932524686718083, 0.0008829556102433148, 0.0008314713181008474, 0.0008211744596723539, 0.000926717258564412, 0.0007954323136011203, 0.0008803813956361914, 0.0008520650349578343, 0.0008829556102433148, 0.000800580742815367, 0.0009318656877786587, 0.0008572134641720811, 0.0008108776012438605, 0.0008391939619222176, 0.0008855298248504381, 0.0008057291720296138, 0.0007748385967441334, 0.0008186002450652306, 0.0009061235417074251, 0.0008263228888866007, 0.0008855298248504381, 0.0008186002450652306, 0.0008057291720296138, 0.0008237486742794773, 0.0008546392495649577, 0.0007182058753874193, 0.0008417681765293408, 0.0008443423911364642, 0.0008057291720296138, 0.0008726587518148213, 0.000870084537207698, 0.0008211744596723539, 0.0007619675237085166, 0.0007799870259583801, 0.0007671159529227632, 0.0007696901675298866, 0.0008469166057435876,
).toDoubleArray(),
arrayOf(
0.008295369726919414, 0.008295369726919414, 0.00024193755951921344, 8.236172238951947e-5, 5.147607649344967e-5, 2.5738038246724835e-5, 1.8016626772707386e-5, 3.08856458960698e-5, 1.0295215298689933e-5, 7.72141147401745e-6, 1.0295215298689933e-5, 2.5738038246724833e-6, 0.0007875839703497799, 0.003948215067047589, 0.0027385272694515224, 0.0020101407870692094, 0.0016317916248423546, 0.0015005276297840578, 0.0014155921035698658, 0.001186523563174015, 0.0010784238025377706, 0.0008905361233366792, 0.0008853885156873343, 0.0007618459321030551, 0.0007335340900316578, 0.0009497336113041464, 0.0013126399505829665, 0.001011504903096286, 0.0012328520320181195, 0.0011788021516999975, 0.001101588036959823, 0.001101588036959823, 0.0010526857642910456, 0.0010501119604663732, 0.0008750933003886444, 0.0009214217692327491, 0.0008442076544925745, 0.0008339124391938846, 0.0009239955730574215, 0.000947159807479474, 0.0009548812189534914, 0.0010089310992716135, 0.0009137003577587316, 0.0009291431807067665, 0.0009600288266028363, 0.0009059789462847142, 0.000926569376882094, 0.0009188479654080766, 0.0008184696162458498, 0.0008545028697912646, 0.0008158958124211773, 0.0008596504774406095, 0.0007798625588757625, 0.0008699456927392994, 0.0009188479654080766, 0.0008879623195120068, 0.0008828147118626618, 0.0008802409080379893, 0.0008004529894731423, 0.0008931099271613517, 0.0008030267932978148, 0.0008339124391938846, 0.0008107482047718323, 0.0007335340900316578, 0.000926569376882094, 0.0009445860036548015, 0.0008493552621419196, 0.000782436362700435, 0.0008107482047718323, 0.0008519290659665921, 0.000862224281265282, 0.0007489769129796927, 0.0007669935397524001, 0.0008056005971224874, 0.0008313386353692121, 0.0007669935397524001, 0.0007901577741744524, 0.0007386816976810027, 0.0008364862430185571, 0.0007747149512264175, 0.0007618459321030551, 0.000782436362700435, 0.000782436362700435, 0.0008056005971224874, 0.0007721411474017451, 0.0007978791856484698, 0.0006717627982395182, 0.0007798625588757625, 0.0007335340900316578, 0.0007850101665251074, 0.0007258126785576404, 0.0008416338506679021, 0.0006872056211875531, 0.000702648444135588, 0.00077728875505109, 0.0007155174632589504, 0.0007232388747329679, 0.0007412555015056752, 0.0007077960517849329, 0.0006666151905901733, 0.0007180912670836229,
).toDoubleArray(),
arrayOf(
0.007659099329024822, 0.007659099329024822, 0.00024441197052648913, 0.0001132013337175318, 4.8882394105297825e-5, 4.37368789363191e-5, 2.058206067591487e-5, 1.2863787922446796e-5, 1.0291030337957436e-5, 1.0291030337957436e-5, 7.718272753468077e-6, 7.718272753468077e-6, 0.0007563907298398716, 0.0034500679208002306, 0.002534166220722019, 0.0018678220063392747, 0.001649137611657679, 0.0014536080352364879, 0.0012709422467377435, 0.0011783229736961264, 0.0010779854279010415, 0.0008412917301280204, 0.0006869262750586588, 0.0006792080023051908, 0.0005917342444325526, 0.0008721648211418927, 0.001168031943358169, 0.0010908492158234883, 0.0010985674885769564, 0.0010857037006545096, 0.0011294405795908287, 0.0010136664882888075, 0.000939056518338616, 0.0008876013666488289, 0.0008695920635574034, 0.0008001276087761907, 0.0007075083357345737, 0.0007435269419174248, 0.0008515827604659779, 0.0008593010332194459, 0.0007615362450088503, 0.0008850286090643395, 0.0008927468818178076, 0.0007924093360227226, 0.0008284279422055736, 0.0009442020335075948, 0.0007718272753468077, 0.0008052731239451694, 0.000831000699790063, 0.0008258551846210843, 0.0008284279422055736, 0.0008284279422055736, 0.0007718272753468077, 0.000794982093607212, 0.0007846910632692545, 0.000766681760177829, 0.0006869262750586588, 0.0008284279422055736, 0.0008001276087761907, 0.0008078458815296588, 0.0007100810933190631, 0.0007975548511917013, 0.0007512452146708928, 0.0007538179722553822, 0.0007744000329312971, 0.0006766352447207015, 0.0007718272753468077, 0.0007126538509035524, 0.0006714897295517227, 0.000766681760177829, 0.0007744000329312971, 0.0007049355781500844, 0.0007512452146708928, 0.0007100810933190631, 0.0006689169719672333, 0.0008181369118676162, 0.0007846910632692545, 0.0007460996995019141, 0.0007538179722553822, 0.0006972173053966163, 0.0006637714567982547, 0.0006894990326431483, 0.0006972173053966163, 0.0007332359115794673, 0.0006509076688758079, 0.0007795455481002758, 0.0006714897295517227, 0.0006406166385378504, 0.0006354711233688717, 0.0006200345778619355, 0.000738381426748446, 0.0007203721236570205, 0.0006997900629811056, 0.0005917342444325526, 0.0007460996995019141, 0.0006843535174741695, 0.0006534804264602972, 0.0006817807598896801, 0.0007358086691639567, 0.0007589634874243609, 0.0006740624871362121,
).toDoubleArray(),
arrayOf(
0.007024552557055233, 0.007024552557055233, 0.00025161043515768017, 0.00010783304363900578, 5.6483975239479214e-5, 3.337689445969227e-5, 2.8241987619739607e-5, 7.702360259928983e-6, 2.567453419976328e-6, 1.0269813679905312e-5, 5.134906839952656e-6, 5.134906839952656e-6, 0.000626458634474224, 0.003450657396448185, 0.0024570529229173458, 0.0017201937913841397, 0.0015764163998654654, 0.001329940871547738, 0.001222107827908732, 0.000955092672231194, 0.0009294181380314308, 0.0008087478272925433, 0.0007548313054730405, 0.0007137520507534192, 0.000611053913954366, 0.000836989814912283, 0.0011117073308497501, 0.000962795032491123, 0.0010192790077306023, 0.0010372511816704366, 0.0010064417406307207, 0.0009730648461710284, 0.0008395572683322593, 0.0008036129204525907, 0.0007753709328328511, 0.0007882081999327327, 0.0007240218644333245, 0.0007111845973334429, 0.0007214544110133482, 0.0007394265849531825, 0.0008036129204525907, 0.0007856407465127564, 0.0008010454670326143, 0.0007933431067726854, 0.0008523945354321409, 0.0008472596285921882, 0.0008498270820121646, 0.0007471289452131115, 0.0007676685725729221, 0.0007188869575933719, 0.0007342916781132298, 0.0007933431067726854, 0.0006726727960337979, 0.0007419940383731589, 0.0007651011191529458, 0.0006598355289339163, 0.0007291567712732771, 0.0007651011191529458, 0.0007265893178533009, 0.0006855100631336796, 0.0007188869575933719, 0.0007805058396728037, 0.0007599662123129931, 0.00065726807551394, 0.000790775653352709, 0.000626458634474224, 0.0006829426097137033, 0.0007445614917931351, 0.0006392959015741056, 0.0007009147836535375, 0.0007060496904934902, 0.0007599662123129931, 0.0006752402494537743, 0.000641863354994082, 0.0006829426097137033, 0.0007163195041733955, 0.000626458634474224, 0.0007368591315332062, 0.0007959105601926617, 0.00065726807551394, 0.0006829426097137033, 0.0006906449699736323, 0.000634160994734153, 0.0006701053426138216, 0.000641863354994082, 0.000680375156293727, 0.0006444308084140583, 0.0007548313054730405, 0.000500653416895384, 0.0006213237276342714, 0.0005982166468544844, 0.0006469982618340347, 0.0006855100631336796, 0.0006469982618340347, 0.0006469982618340347, 0.0006187562742142951, 0.0005879468331745791, 0.000611053913954366, 0.0005674072058147685, 0.0005930817400145318, 0.0006238911810542478,
).toDoubleArray(),
arrayOf(
0.006774518159507943, 0.006774518159507943, 0.00017199420867261545, 8.214648772423425e-5, 2.823785515520552e-5, 4.107324386211712e-5, 1.28353887069116e-5, 1.540246644829392e-5, 7.70123322414696e-6, 7.70123322414696e-6, 5.13415548276464e-6, 2.56707774138232e-6, 0.0006725743682421679, 0.003586207604711101, 0.0024566933985028802, 0.001732777475433066, 0.0013939232135705998, 0.0013194779590705126, 0.0011500508281392793, 0.001019129863328781, 0.0008394344214320186, 0.0007547208559664021, 0.0006956780679146088, 0.0005647571031041104, 0.0005801595695524043, 0.0008471356546561656, 0.001034532329777075, 0.0008445685769147833, 0.001034532329777075, 0.0010935751178288682, 0.0009267150646390175, 0.0008574039656216949, 0.0008651051988458418, 0.0008368673436906363, 0.0007932270220871369, 0.0007110805343629027, 0.0007085134566215204, 0.0006623060572766386, 0.0007906599443457546, 0.0007726904001560783, 0.0007547208559664021, 0.0008574039656216949, 0.000842001499173401, 0.0007957940998285192, 0.0008445685769147833, 0.0007290500785525789, 0.0007675562446733137, 0.000777824555638843, 0.0007239159230698143, 0.000649470668569727, 0.0007033793011387557, 0.0006982451456559911, 0.0006469035908283447, 0.0007547208559664021, 0.0006751414459835502, 0.0006520377463111093, 0.0007675562446733137, 0.0008163307217595778, 0.0007187817675870496, 0.0007033793011387557, 0.0006828426792076972, 0.0007547208559664021, 0.0006931109901732264, 0.0006597389795352563, 0.0006725743682421679, 0.0007239159230698143, 0.0006597389795352563, 0.0007803916333802253, 0.0006854097569490795, 0.0006725743682421679, 0.0007008122233973734, 0.000649470668569727, 0.0007624220891905491, 0.000713647612104285, 0.0006674402127594032, 0.0007341842340353435, 0.0006366352798628154, 0.0006725743682421679, 0.00064176943534558, 0.0005929949582593159, 0.0006160986579317569, 0.0006520377463111093, 0.0006135315801903745, 0.0006443365130869624, 0.000649470668569727, 0.0006160986579317569, 0.0006725743682421679, 0.000569891258586875, 0.0006982451456559911, 0.0006186657356731392, 0.0006597389795352563, 0.0006854097569490795, 0.0006469035908283447, 0.0006109645024489922, 0.0005878608027765512, 0.0006469035908283447, 0.0005929949582593159, 0.0006135315801903745, 0.0005673241808454927, 0.0006520377463111093, 0.0006828426792076972,
).toDoubleArray(),
)
// private val fineInterpolator = PiecewiseBicubicSplineInterpolator().interpolate(x, yFine, gridFine)
private val fineInterpolator = BilinearInterpolator(x, yFine, gridFine)
fun value(ei: Double, delta: Double): Double {
if (ei < x.first() || ei > x.last())
error("trap: ei ($ei) not in [${x.first()}..${x.last()}]")
if (delta < yFine.first())
error("trap: delta < ${yFine.first()}")
if (delta > yCoarse.last())
error("trap: delta > ${yCoarse.last()}")
return if (delta < yFine.last()) {
fineInterpolator.value(ei, delta)
} else {
coarseInterpolator.value(ei, delta)
}
}
}

@ -1,9 +0,0 @@
package ru.inr.mass.scripts
import kotlinx.coroutines.flow.toList
import ru.inr.mass.workspace.Numass.readPoint
suspend fun main() {
val point = readPoint("D:\\Work\\Numass\\data\\2019_11\\Fill_3\\set_2\\p2(30s)(HV1=14000)")
val events = point.events.toList()
}

@ -1,22 +0,0 @@
package ru.inr.mass.scripts
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: DataSource<NumassDirectorySet> = repo.filter { _, meta: Meta ->
val operator by meta.string()
operator?.startsWith("Vas") ?: false
}
filtered.forEach{
println(it)
}
}

@ -1,125 +0,0 @@
package ru.inr.mass.scripts
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import kotlinx.html.code
import kotlinx.html.h2
import kotlinx.html.p
import kotlinx.html.unsafe
import kotlinx.serialization.json.Json
import ru.inr.mass.data.analysis.NumassEventExtractor
import ru.inr.mass.data.analysis.amplitudeSpectrum
import ru.inr.mass.data.api.NumassFrame
import ru.inr.mass.data.api.channels
import ru.inr.mass.workspace.Numass.readDirectory
import ru.inr.mass.workspace.Numass.readPoint
import ru.inr.mass.workspace.listFrames
import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.plotly.*
//fun NumassFrame.tqdcAmplitude(): Short {
// var max = Short.MIN_VALUE
// var min = Short.MAX_VALUE
//
// signal.forEach { sh: Short ->
// if (sh >= max) {
// max = sh
// }
// if (sh <= min) {
// min = sh
// }
// }
//
// return (max - min).toShort()
//}
//fun Flow<NumassFrame>.tqdcAmplitudes(): List<Short> = runBlocking {
// map { it.tqdcAmplitude() }.toList()
//}
val IntRange.center: Double get() = (endInclusive + start).toDouble() / 2.0
suspend fun main() {
//val repo: DataTree<NumassDirectorySet> = readNumassRepository("D:\\Work\\numass-data\\")
//val directory = readDirectory("D:\\Work\\Numass\\data\\2021_11\\Tritium_2\\set_11\\")
val point = readPoint("D:\\Work\\Numass\\data\\2021_11\\Tritium_2\\set_11\\p0(30s)(HV1=14000)")
val channel = point.channels[4]!!
val binning = 16U
val frames: List<NumassFrame> = channel.listFrames()
Plotly.page {
p { +"${frames.size} frames" }
h2 { +"Random frames" }
plot {
val random = kotlin.random.Random(1234)
repeat(10) {
val frame = frames.random(random)
scatter {
y.numbers = frame.signal.toList()
}
}
}
h2 { +"Analysis" }
plot {
scatter {
name = "max"
val spectrum = runBlocking {
channel.amplitudeSpectrum(NumassEventExtractor.EVENTS_ONLY)
}.binned(binning)
x.numbers = spectrum.keys.map { it.center }
y.numbers = spectrum.values.map { it }
}
scatter {
name = "max-min"
val spectrum = runBlocking {
channel.amplitudeSpectrum(NumassEventExtractor.TQDC)
}.binned(binning)
x.numbers = spectrum.keys.map { it.center }
y.numbers = spectrum.values.map { it}
}
scatter {
name = "max-baseline + filter"
val spectrum = runBlocking {
channel.amplitudeSpectrum(NumassEventExtractor.TQDC_V2)
}.binned(binning)
x.numbers = spectrum.keys.map { it.center }
y.numbers = spectrum.values.map { it }
}
histogram {
name = "events"
xbins {
size = 2.0
}
x.numbers = runBlocking { point.events.map { it.amplitude.toInt() }.toList() }
}
}
h2 { +"Meta" }
code {
unsafe {
+Json { prettyPrint = true }.encodeToString(MetaSerializer, point.meta)
}
}
}.makeFile()
// val point = Numass.readPoint("D:\\Work\\Numass\\data\\test\\set_7\\p0(30s)(HV1=14000)")
//
// Plotly.plot {
// histogram {
// xbins.size = 2
// x.numbers = point.frames.map { it.tqdcAmplitude() }.toList()
// }
//
// histogram {
// x.numbers = point.flowBlocks().flatMapMerge { it.frames.map { it.tqdcAmplitude() } }.toList()
// }
//
// histogram {
// x.numbers = point.getChannels().values.flatMap { it.listFrames().map { it.tqdcAmplitude() } }
// }
// }.makeFile()
}

@ -1,22 +0,0 @@
package ru.inr.mass.scripts
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.workspace.Numass
import space.kscience.plotly.Plotly
import space.kscience.plotly.makeFile
import space.kscience.plotly.scatter
fun main() {
val directory = Numass.readDirectory("D:\\Work\\Numass\\data\\test\\set_7\\")
val monitorPoints: List<NumassPoint> = directory.filter { it.voltage == 14000.0 }.sortedBy { it.startTime }
Plotly.plot {
scatter {
x.numbers = monitorPoints.map {
it.startTime.toEpochMilliseconds()
}
y.numbers = monitorPoints.map { it.framesCount }
}
}.makeFile()
}

@ -1,95 +0,0 @@
package ru.inr.mass.scripts
import kotlinx.html.code
import ru.inr.mass.models.*
import ru.inr.mass.models.NBkgSpectrum.Companion.bkg
import ru.inr.mass.models.NBkgSpectrum.Companion.norm
import ru.inr.mass.models.NumassBeta.e0
import ru.inr.mass.models.NumassBeta.mnu2
import ru.inr.mass.models.NumassBeta.msterile2
import ru.inr.mass.models.NumassBeta.u2
import ru.inr.mass.models.NumassTransmission.Companion.thickness
import ru.inr.mass.models.NumassTransmission.Companion.trap
import ru.inr.mass.workspace.buffer
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.real.step
import space.kscience.plotly.*
import space.kscience.plotly.models.AxisType
import space.kscience.plotly.models.ScatterMode
import space.kscience.plotly.models.appendXY
import kotlin.math.pow
import kotlin.system.measureTimeMillis
fun main() {
val spectrum: NBkgSpectrum = SterileNeutrinoSpectrum(fss = FSS.default).withNBkg()
val args: Map<Symbol, Double> = mapOf(
norm to 8e5,
bkg to 2.0,
mnu2 to 0.0,
e0 to 18575.0,
msterile2 to 1000.0.pow(2),
u2 to 1e-2,
thickness to 0.1,
trap to 1.0
)
Plotly.page {
plot {
scatter {
name = "Computed spectrum"
mode = ScatterMode.lines
x.buffer = 14000.0..18600.0 step 10.0
y.numbers = x.doubles.map { spectrum(it, args) }
}
layout {
title = "Sterile neutrino spectrum"
yaxis.type = AxisType.log
}
}
val spectrumTime = measureTimeMillis {
plot {
scatter {
mode = ScatterMode.markers
javaClass.getResource("/old-spectrum.dat").readText().lines().map {
val (u, w) = it.split("\t").map { it.toDouble() }
appendXY(u, w / spectrum(u, args) - 1.0)
}
}
layout {
title = "Sterile neutrino old/new ratio"
}
}
}
println("Spectrum with 460 points computed in $spectrumTime millis")
plot {
val resolution = NumassResolution()
scatter {
name = "resolution"
x.buffer = 14000.0..14015.0 step 0.1
y.numbers = x.doubles.map { resolution(it, 14005.0, args) }
}
layout {
title = "Resolution, U = 14005.0"
}
}
plot {
val transmission = NumassTransmission()
scatter {
name = "transmission"
x.buffer = 14000.0..14100.0 step 0.2
y.numbers = x.doubles.map { transmission(it, 14005.0, args) }
}
layout {
title = "Resolution, U = 14005.0"
}
}
code {
+args.toString()
}
}.makeFile()
}

@ -0,0 +1,85 @@
package ru.inr.mass.scripts
import ru.inr.mass.models.*
import ru.inr.mass.models.NBkgSpectrum.Companion.bkg
import ru.inr.mass.models.NBkgSpectrum.Companion.norm
import ru.inr.mass.models.NumassBeta.e0
import ru.inr.mass.models.NumassBeta.mnu2
import ru.inr.mass.models.NumassBeta.msterile2
import ru.inr.mass.models.NumassBeta.u2
import ru.inr.mass.models.NumassTransmission.Companion.thickness
import ru.inr.mass.models.NumassTransmission.Companion.trap
import ru.inr.mass.workspace.buffer
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.real.step
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
fun main() {
val trapInterpolator = TrapInterpolator()
val range = 10000.0..18600.0 step 50.0
val args: Map<Symbol, Double> = mapOf(
norm to 231296.31435970013,
bkg to 1.156996613764463,
mnu2 to 0.0,
e0 to 18553.267180007213,
msterile2 to 16e6,
u2 to -0.006326658267906115,
thickness to 0.1,
trap to 0.0,
rearWall to 0.04192630322035539
)
val argsTrap1 = args.toMutableMap();
argsTrap1[trap] = 1.0
val argsTrap2 = args.toMutableMap();
argsTrap2[trap] = 2.0
val argsTrap3 = args.toMutableMap();
argsTrap3[trap] = 3.0
val spectrumC: NBkgSpectrum = CustomSterileNeutrinoSpectrum(
fss = null,
transmission = NumassTransmission(
trapFunc = { ei, ef, _ ->
val delta = ei - ef
trapInterpolator.value(ei, delta)
},
adjustX = false,
),
resolution = NumassResolution(1.7e-4, tailFunction = {
e,u -> adiabacity(e,u)
})
).withNBkg()
Plotly.page {
plot {
scatter {
name = "CustomSterileNeutrinoSpectrum (trap=${args[trap]})"
mode = ScatterMode.lines
x.buffer = range
y.numbers = x.doubles.map { spectrumC(it, args) }
}
listOf(argsTrap1, argsTrap2, argsTrap3).forEach { argsTrap ->
scatter {
name = "CustomSterileNeutrinoSpectrum (trap=${argsTrap[trap]})"
mode = ScatterMode.lines
x.buffer = range
y.numbers = x.doubles.map { spectrumC(it, argsTrap) }
}
}
layout {
title = "Compare Trap"
// yaxis.type = AxisType.log
}
}
}.makeFile()
println("HV\ttrap=${args[trap]}\ttrap=${argsTrap3[trap]}")
range.iterator().forEach {
println("${it}\t${spectrumC(it, args)}\t${spectrumC(it, argsTrap3)}")
}
}

@ -0,0 +1,63 @@
package ru.inr.mass.scripts
import ru.inr.mass.workspace.buffer
import space.kscience.kmath.real.step
import space.kscience.kmath.structures.toDoubleArray
import space.kscience.plotly.*
import space.kscience.plotly.models.TraceType
import space.kscience.dataforge.meta.Value
import space.kscience.kmath.structures.asBuffer
import space.kscience.plotly.models.ScatterMode
import kotlin.math.exp
fun main() {
val maxDelta = (WALL_R - WALL_L)
val interpolator = TrapInterpolator()
Plotly.page {
plot {
val eis = (WALL_L..WALL_R step 100.0).toDoubleArray()
val deltas = (0.0..maxDelta step 10.0).toDoubleArray()
val values = eis.map { ei ->
deltas.map { interpolator.value(ei, it) }.toList()
}
layout {
}
trace {
type = TraceType.surface
x.numbers = deltas.toList()
y.numbers = eis.toList()
z.value = Value.of(values)
}
}
plot {
scatter {
name = "Nozik Trap"
mode = ScatterMode.lines
x.buffer = (0.0..90.0 step 1.0).toDoubleArray().plus((100.0..maxDelta step 10.0).toDoubleArray()).asBuffer()
y.numbers = x.doubles.map {
if (it > 10) {
1.86e-04 * exp(-it / 25.0) + 5.5e-05
} else {
0.0
}
}
}
for (HV in (WALL_L..WALL_R step 1000.0)) {
scatter {
name = "${HV / 1000.0} keV"
mode = ScatterMode.lines
x.buffer = (0.0..90.0 step 1.0).toDoubleArray().plus((100.0..maxDelta step 10.0).toDoubleArray()).asBuffer()
y.numbers = x.doubles.map {
interpolator.value(HV, it)
}
}
}
}
}.makeFile()
}

@ -0,0 +1,83 @@
// Code generated by trap-spectrum-2024-11.jl Julia notebook 2025-03-11T12:54:54.833
package ru.inr.mass.scripts
import org.apache.commons.math3.analysis.interpolation.PiecewiseBicubicSplineInterpolator
class TrapInterpolator {
private val x = arrayOf(10000.0, 12000.0, 14000.0, 16000.0, 18000.0, 19000.0, ).toDoubleArray()
private val yCoarse = arrayOf(
100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 1100.0, 1200.0, 1300.0, 1400.0, 1500.0, 1600.0, 1700.0, 1800.0, 1900.0, 2000.0, 2100.0, 2200.0, 2300.0, 2400.0, 2500.0, 2600.0, 2700.0, 2800.0, 2900.0, 3000.0, 3100.0, 3200.0, 3300.0, 3400.0, 3500.0, 3600.0, 3700.0, 3800.0, 3900.0, 4000.0, 4100.0, 4200.0, 4300.0, 4400.0, 4500.0, 4600.0, 4700.0, 4800.0, 4900.0, 5000.0, 5100.0, 5200.0, 5300.0, 5400.0, 5500.0, 5600.0, 5700.0, 5800.0, 5900.0, 6000.0, 6100.0, 6200.0, 6300.0, 6400.0, 6500.0, 6600.0, 6700.0, 6800.0, 6900.0, 7000.0, 7100.0, 7200.0, 7300.0, 7400.0, 7500.0, 7600.0, 7700.0, 7800.0, 7900.0, 8000.0, 8100.0, 8200.0, 8300.0, 8400.0, 8500.0, 8600.0, 8700.0, 8800.0, 8900.0, 9000.0,
).toDoubleArray()
private val gridCoarse = arrayOf(
arrayOf(
5.615033575679756e-5, 5.615033575679756e-5, 5.1326543006368104e-5, 4.780066283770888e-5, 4.6863667123596676e-5, 4.363623744165466e-5, 4.285193732539779e-5, 4.219256997102254e-5, 4.294910725130572e-5, 4.237302840485155e-5, 4.2622893928614806e-5, 4.2546546129687144e-5, 4.3650118859641514e-5, 4.485780222449723e-5, 4.5655983758740955e-5, 4.67803786156756e-5, 4.780760354670229e-5, 4.81615797053669e-5, 5.027155523936771e-5, 4.9785705609828045e-5, 5.1264076625427285e-5, 5.296455032881609e-5, 5.22635387204803e-5, 5.411670802172442e-5, 5.392236816990856e-5, 5.635161631760684e-5, 5.6643126095330635e-5, 5.805209002099565e-5, 5.8357481216706284e-5, 6.006489562908852e-5, 6.0876958581319076e-5, 6.120317190401e-5, 6.268154291960925e-5, 6.248026235879995e-5, 6.541618226301817e-5, 6.638094081310406e-5, 6.670715413579497e-5, 6.765803126789402e-5, 6.87963075428155e-5, 6.952508198712498e-5, 7.064947684405962e-5, 7.12324963995072e-5, 7.20515000607312e-5, 7.470979160521247e-5, 7.514011556280474e-5, 7.672259721330534e-5, 7.672953792229876e-5, 7.945029584772084e-5, 8.065797921257655e-5, 8.18726032864257e-5, 8.335791501101837e-5, 8.525966927521647e-5, 8.723777133834222e-5, 8.844545470319793e-5, 9.015286911558015e-5, 9.190192778192292e-5, 9.405354756988425e-5, 9.430341309364751e-5, 9.864135621453731e-5, 9.979351390744565e-5, 0.00010263226388575593, 0.00010631083965227047, 0.00010805989831861324, 0.00011087782616994326, 0.00011441064704759592, 0.00011835991046485399, 0.00012221200395620414, 0.00012382224844267843, 0.00012899307664277905, 0.00013194287796498413, 0.00013747462303274278, 0.0001425413405979421, 0.00014516492859745623, 0.00015167531363328765, 0.00015731116933594767, 0.00016321771268935123, 0.00017163679269837414, 0.00017935486109906128, 0.00018681612326699174, 0.00019667193003765335, 0.00020842949107251308, 0.0002195762697159515, 0.00023067446339643596, 0.0002446530513091912, 0.00025819437455536085, 0.0002810154257257379, 0.0002993597195953567, 0.00032471412954833336, 0.0003525463726119623, 0.0003836060453575333,
).toDoubleArray(),
arrayOf(
4.732839988268437e-5, 4.732839988268437e-5, 4.18370297234277e-5, 3.909134464379936e-5, 3.828705305481732e-5, 3.6720071165938527e-5, 3.527789314431557e-5, 3.480641186801575e-5, 3.369704415907501e-5, 3.334343320185015e-5, 3.448746865169529e-5, 3.402292092357635e-5, 3.328796481640311e-5, 3.407145576084251e-5, 3.426559510990714e-5, 3.6102985377840244e-5, 3.585337764332857e-5, 3.6865675677737e-5, 3.6720071165938527e-5, 3.841185692207316e-5, 3.885560400564946e-5, 3.95905601128227e-5, 4.0540456213603206e-5, 4.008284203366515e-5, 4.168449166344834e-5, 4.190636520523649e-5, 4.274532453512293e-5, 4.281466001693173e-5, 4.364668579863728e-5, 4.424990449037381e-5, 4.465205028486483e-5, 4.5393939940218944e-5, 4.6191297981020106e-5, 4.6829184413661034e-5, 4.774441277353714e-5, 4.7598808261738674e-5, 4.836149856163543e-5, 4.9623404330555517e-5, 4.992154690233335e-5, 4.983834432416279e-5, 5.0046350769589185e-5, 5.2237351994747147e-5, 5.312484616189974e-5, 5.2993108746463026e-5, 5.3325919059145244e-5, 5.442835321990511e-5, 5.5301980290695946e-5, 5.578039511517664e-5, 5.546838544703705e-5, 5.7569250545843584e-5, 5.779805763581261e-5, 5.811700085213307e-5, 5.9385840169234045e-5, 5.928183694652085e-5, 6.0308002077291036e-5, 6.201365492978742e-5, 6.283874716331209e-5, 6.409371938405131e-5, 6.405211809496603e-5, 6.502974838847007e-5, 6.666606575915766e-5, 6.75050250890441e-5, 6.898880439975233e-5, 6.946721922423302e-5, 7.029924500593858e-5, 7.197023011753057e-5, 7.255958171290535e-5, 7.297559460375812e-5, 7.574901387610997e-5, 7.75448028549578e-5, 7.918805377382627e-5, 7.940299376743353e-5, 8.228041626249858e-5, 8.365325880231276e-5, 8.476262651125349e-5, 8.756377997632887e-5, 8.788965674083021e-5, 9.106522180767308e-5, 9.338796044826776e-5, 9.67437977678135e-5, 9.833851384941582e-5, 0.00010061271765274434, 0.00010221436728252752, 0.00010541073299391304, 0.00010916178255976892, 0.00011253148697567643, 0.00011414700370182136, 0.00011746817328046271, 0.00012302887892152818, 0.00012529614917667581,
).toDoubleArray(),
arrayOf(
3.993011017354587e-5, 3.993011017354587e-5, 3.557586304922102e-5, 3.384941793145527e-5, 3.242804745297344e-5, 3.1498956506063355e-5, 3.04935968993323e-5, 2.826793873546562e-5, 2.8635415005512143e-5, 2.8254071706407262e-5, 2.7616188369722728e-5, 2.8496744714928552e-5, 2.7734058116718783e-5, 2.7935130038064995e-5, 2.9509037836188787e-5, 2.8801819354212456e-5, 2.8351140909815778e-5, 2.9883447620764492e-5, 3.0264790919869373e-5, 3.009145305663988e-5, 2.9730910301122538e-5, 3.165149382570531e-5, 3.194963495046004e-5, 3.232404473503574e-5, 3.208137172651446e-5, 3.209523875557281e-5, 3.317686702212485e-5, 3.4008888765626406e-5, 3.352354274858383e-5, 3.4057423367330664e-5, 3.508358351764926e-5, 3.5347057069758084e-5, 3.5568929534691835e-5, 3.552039493298758e-5, 3.667135834483141e-5, 3.8023393678021455e-5, 3.642175182178094e-5, 3.8037260707079814e-5, 3.863354295658926e-5, 3.924369223515708e-5, 3.972210473767048e-5, 3.8813814334347936e-5, 4.0262918870946496e-5, 4.127521199220673e-5, 4.1067206556331337e-5, 4.1067206556331337e-5, 4.147628391355294e-5, 4.3570205301365214e-5, 4.337606689454818e-5, 4.351473718513177e-5, 4.317499497320197e-5, 4.4256623239754e-5, 4.431209135598744e-5, 4.441609407392513e-5, 4.4873706032850994e-5, 4.5906799697698765e-5, 4.6634818723262635e-5, 4.774418104793138e-5, 4.7827383222281546e-5, 4.9491426709284664e-5, 4.944289210758041e-5, 4.9449825622109586e-5, 5.0475985772428184e-5, 5.034424899637377e-5, 5.138427617575073e-5, 5.073945932453702e-5, 5.255604013118209e-5, 5.273631150894077e-5, 5.2680843392707334e-5, 5.358913379602988e-5, 5.537104703002905e-5, 5.618920174447226e-5, 5.5787057901779826e-5, 5.7527370048603935e-5, 5.8803136721973e-5, 5.8713001033093667e-5, 5.978769578511652e-5, 6.174294688234519e-5, 6.21173566669209e-5, 6.117439869095247e-5, 6.430834725814168e-5, 6.548704472810224e-5, 6.529983983581438e-5, 6.638840161689559e-5, 6.794150887143184e-5, 7.05485103344034e-5, 6.910633931233403e-5, 7.172027428983477e-5, 7.425794060751454e-5, 7.450061361603584e-5,
).toDoubleArray(),
arrayOf(
3.432494279176201e-5, 3.432494279176201e-5, 3.203522975990526e-5, 2.9627918173542262e-5, 2.7607990060846873e-5, 2.7006162164256126e-5, 2.5830176619193746e-5, 2.5020821861709636e-5, 2.4965481365471408e-5, 2.455734520571446e-5, 2.4204549542195746e-5, 2.432214809670198e-5, 2.3907094374915262e-5, 2.411462123580862e-5, 2.4363653468880655e-5, 2.372723776214101e-5, 2.4073115863629947e-5, 2.375490801026013e-5, 2.4550427643684682e-5, 2.434290078279132e-5, 2.5242183846662554e-5, 2.589243467746175e-5, 2.5726413188747063e-5, 2.6148384472563562e-5, 2.5975445421819096e-5, 2.6584190880439623e-5, 2.7289782207477056e-5, 2.7317452455596172e-5, 2.73727929518344e-5, 2.7732506177382894e-5, 2.8154477461199397e-5, 2.8417344818330985e-5, 2.894307953259417e-5, 2.957949523933381e-5, 2.910218345927908e-5, 3.015365288780545e-5, 3.064479979191973e-5, 3.1184369630242475e-5, 3.0755480784396195e-5, 3.154408285579097e-5, 3.1620176038118536e-5, 3.16962692204461e-5, 3.227042686891773e-5, 3.275465621100224e-5, 3.2685480590704456e-5, 3.3059028940312504e-5, 3.3079781626401847e-5, 3.3923724194034846e-5, 3.398598225230286e-5, 3.489910044023365e-5, 3.438720085003002e-5, 3.478841944775719e-5, 3.5514763460883955e-5, 3.49475233744421e-5, 3.55631863950924e-5, 3.6531645079261424e-5, 3.680834756045258e-5, 3.7008956859316155e-5, 3.768687793823447e-5, 3.802583847769363e-5, 3.7998168229574515e-5, 3.833021120700389e-5, 3.9194906460726234e-5, 3.864841906037371e-5, 4.0184117830984594e-5, 3.95961250584534e-5, 4.159530048505945e-5, 4.072368766930733e-5, 4.059917155277131e-5, 4.127017506965985e-5, 4.312408169364055e-5, 4.259834697937736e-5, 4.247383086284135e-5, 4.375357983835041e-5, 4.4210138932315805e-5, 4.4251644304494476e-5, 4.4632110216132305e-5, 4.547605278376531e-5, 4.517168005445505e-5, 4.656211002244057e-5, 4.691490568595928e-5, 4.771734288141362e-5, 4.813239660320034e-5, 4.851286251483817e-5, 5.036676913881887e-5, 5.045669744520599e-5, 5.0027808599359705e-5, 5.210307720829332e-5, 5.0525873065503785e-5, 5.190938547145953e-5,
).toDoubleArray(),
arrayOf(
4.097487409375173e-5, 4.097487409375173e-5, 3.645746859261719e-5, 3.4181471027727046e-5, 3.3026177430959104e-5, 3.1767114948253914e-5, 3.0805523271902155e-5, 2.9933864630029333e-5, 3.0335104322319995e-5, 2.8820078587636282e-5, 2.7657867065139186e-5, 2.8321987935137525e-5, 2.7754718025347278e-5, 2.720128396701533e-5, 2.7035253749515745e-5, 2.687614145774531e-5, 2.675853672034977e-5, 2.6606342354308486e-5, 2.6710111240245724e-5, 2.6606342354308486e-5, 2.6384968730975706e-5, 2.6364214953788256e-5, 2.7394985887431513e-5, 2.686230560628701e-5, 2.699374619514085e-5, 2.7145940561182136e-5, 2.7478000996181304e-5, 2.8066024683159002e-5, 2.6841551829099562e-5, 2.7533344402014498e-5, 2.6744700868891468e-5, 2.6689357463058277e-5, 2.8363495489512426e-5, 2.839808511815817e-5, 2.8059106757429855e-5, 2.8460346449720517e-5, 2.8764735181803088e-5, 2.821130112347114e-5, 3.0113730698987216e-5, 2.875089933034479e-5, 2.9062205988156508e-5, 2.9311251314405888e-5, 3.0120648624716366e-5, 3.005838729315402e-5, 3.0079141070341465e-5, 2.9837013669821242e-5, 3.0480380762632134e-5, 3.0203663733466157e-5, 3.0238253362111904e-5, 3.1220598815651114e-5, 3.207842160606564e-5, 3.1767114948253914e-5, 3.095771763794344e-5, 3.1109912003984725e-5, 3.2327466932315015e-5, 3.225828767502352e-5, 3.13312856273175e-5, 3.216835464054458e-5, 3.1670263988045826e-5, 3.2071503680336485e-5, 3.313686424262549e-5, 3.277713210470973e-5, 3.355193978637445e-5, 3.420222480491449e-5, 3.448585975980962e-5, 3.4050030438873204e-5, 3.4472023908351317e-5, 3.445818805689302e-5, 3.482483812053794e-5, 3.382865681554043e-5, 3.534368255022414e-5, 3.5613481653660965e-5, 3.540594388178648e-5, 3.557889202501522e-5, 3.640904311251315e-5, 3.606314682605568e-5, 3.649205822126294e-5, 3.7405224417510656e-5, 3.728070175438597e-5, 3.837373401959156e-5, 3.79448226243843e-5, 3.834606231667497e-5, 3.785488958990536e-5, 3.841524157396646e-5, 3.927306436438099e-5, 3.998561071448337e-5, 3.990951353146272e-5, 3.975040123969229e-5, 4.0310753223753394e-5, 4.161132326083347e-5,
).toDoubleArray(),
arrayOf(
2.922372662620021e-5, 2.922372662620021e-5, 2.6591518625116932e-5, 2.485743933831403e-5, 2.3613876503156577e-5, 2.228740947898862e-5, 2.2052514276792218e-5, 2.139618944712578e-5, 2.110602478558904e-5, 2.12994678932802e-5, 2.0048996375705204e-5, 2.0048996375705204e-5, 2.007663110537537e-5, 1.9779557761421086e-5, 1.9579205971312387e-5, 1.962756674823518e-5, 1.9959183504277166e-5, 1.964138411307026e-5, 1.963447543065272e-5, 1.989009668010175e-5, 1.9765740396586005e-5, 1.9482484417466807e-5, 2.0069722422957827e-5, 1.989009668010175e-5, 2.0691503840536555e-5, 2.0988577184490835e-5, 2.1803801709760723e-5, 2.1175111609764453e-5, 2.1271833163610033e-5, 2.1720897520750227e-5, 2.147909363613628e-5, 2.1900523263606304e-5, 2.2114692418550087e-5, 2.2812469342721776e-5, 2.2674295694370943e-5, 2.2584482822942904e-5, 2.3261533699861966e-5, 2.3869497752605607e-5, 2.339279866579525e-5, 2.3890223799858233e-5, 2.384186302293544e-5, 2.3959310624033648e-5, 2.4829804608643864e-5, 2.4159662414142348e-5, 2.5078517175675355e-5, 2.4284018697658093e-5, 2.4974886939412236e-5, 2.5458494708640138e-5, 2.6183906362481985e-5, 2.5403225249299807e-5, 2.614936295039428e-5, 2.7206391360278118e-5, 2.6888591969071212e-5, 2.609409349105395e-5, 2.769690781192356e-5, 2.6591518625116932e-5, 2.7731451224011263e-5, 2.735838237346403e-5, 2.814597216906375e-5, 2.860885389103902e-5, 2.819433294598654e-5, 2.7987072473460296e-5, 2.8981922741586264e-5, 2.8961196694333638e-5, 2.8788479633895104e-5, 2.9741877807515815e-5, 2.956916074707728e-5, 3.017712479982093e-5, 3.056401101520325e-5, 3.0384385272347167e-5, 3.1607222060252e-5, 3.0633097839378665e-5, 3.136541817563805e-5, 3.138614422289068e-5, 3.1475957094318715e-5, 3.0474198143775208e-5, 3.1876660674536114e-5, 3.228427293717106e-5, 3.307186273277078e-5, 3.41427085074897e-5, 3.3465657630570645e-5, 3.4308516885510695e-5, 3.359001391408639e-5, 3.370746151518459e-5, 3.376273097452492e-5, 3.4280882155840527e-5, 3.522046296462616e-5, 3.535863661297699e-5, 3.5683344686601436e-5, 3.555207972066815e-5,
).toDoubleArray(),
)
// private val coarseInterpolator = PiecewiseBicubicSplineInterpolator().interpolate(x, yCoarse, gridCoarse)
private val coarseInterpolator = BilinearInterpolator(x, yCoarse, gridCoarse)
private val yFine = arrayOf(
0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, 96.0, 97.0, 98.0, 99.0, 100.0,
).toDoubleArray()
private val gridFine = arrayOf(
arrayOf(
0.0017053321996841977, 0.0017053321996841977, 0.00030955562110669606, 0.00010549877670003991, 5.9690097343443635e-5, 3.262133226909129e-5, 2.3598410577640507e-5, 1.4575488886189724e-5, 8.328850792108415e-6, 8.328850792108415e-6, 6.24663809408131e-6, 4.164425396054207e-6, 0.0003317658898856518, 0.0016935329943953774, 0.0013180406378511566, 0.0008821641130641495, 0.0007148930263226388, 0.0005955128316357516, 0.0005413753014870469, 0.00045392236816990856, 0.0004247713903975291, 0.00035467022956394995, 0.0002873453523277403, 0.0002505595946625948, 0.00023876038937377454, 0.00017351772483559195, 0.00020336277350731376, 0.00020613905710468325, 0.00017976436292967328, 0.00018670507192309694, 0.00017907029203033088, 0.00016241259044611408, 0.00014297860526452777, 0.00014159046346584305, 0.0001297912581770228, 9.994620950530096e-5, 9.786399680727386e-5, 0.00010064028040464334, 7.77359407263452e-5, 9.022921691450782e-5, 9.300550051187729e-5, 0.00011521576929083306, 0.00011174541479412122, 8.675886241779598e-5, 0.00011590984019017543, 0.00010619284759938227, 9.022921691450782e-5, 8.467664971976887e-5, 6.801894813555204e-5, 8.259443702174177e-5, 7.148930263226389e-5, 7.77359407263452e-5, 7.148930263226389e-5, 7.704186982700283e-5, 7.912408252502994e-5, 7.77359407263452e-5, 7.77359407263452e-5, 6.454859363884021e-5, 7.704186982700283e-5, 7.218337353160625e-5, 8.537072061911125e-5, 7.495965712897573e-5, 7.357151533029099e-5, 6.316045184015547e-5, 7.079523173292152e-5, 6.871301903489442e-5, 7.634779892766046e-5, 7.287744443094863e-5, 8.259443702174177e-5, 7.426558622963335e-5, 6.0384168242786e-5, 5.8996026444101265e-5, 7.079523173292152e-5, 6.801894813555204e-5, 6.871301903489442e-5, 5.760788464541653e-5, 5.691381374607416e-5, 6.732487723620968e-5, 7.010116083357915e-5, 6.593673543752494e-5, 6.732487723620968e-5, 6.246638094081311e-5, 6.107823914212837e-5, 5.9690097343443635e-5, 5.691381374607416e-5, 6.801894813555204e-5, 6.663080633686732e-5, 5.8301955544758895e-5, 5.9690097343443635e-5, 5.8996026444101265e-5, 5.621974284673179e-5, 5.3443459249362324e-5, 6.524266453818258e-5, 7.218337353160625e-5, 6.732487723620968e-5, 5.621974284673179e-5, 6.385452273949784e-5, 5.3443459249362324e-5, 5.8301955544758895e-5, 6.801894813555204e-5, 5.691381374607416e-5,
).toDoubleArray(),
arrayOf(
0.001241105124377454, 0.001241105124377454, 0.0003217166355928149, 0.00010677664198554633, 5.6161740265125016e-5, 3.4667740904398155e-5, 2.218735417881482e-5, 1.3867096361759263e-5, 9.706967453231484e-6, 7.626902998967594e-6, 6.240193362791669e-6, 6.240193362791669e-6, 0.00031408973259384733, 0.0013998833777195976, 0.001056672742766056, 0.0008354925557959956, 0.0005616174026512502, 0.0005103091461127409, 0.0004763347600264307, 0.00037025147285897234, 0.0003293435385917825, 0.000301609345868264, 0.00026486154050960194, 0.00020592638097212507, 0.00017472541415816672, 0.00017749883343051856, 0.00017056528524963892, 0.00017056528524963892, 0.00015115135034317597, 0.00015531147925170374, 0.00013312412507288893, 0.0001185636738930417, 0.00012272380280156948, 0.00011440354498451392, 0.00010053644862275466, 9.013612635143521e-5, 9.22161908056991e-5, 7.626902998967594e-5, 7.418896553541206e-5, 8.042915889820373e-5, 7.696238480776391e-5, 8.320257817055557e-5, 9.082948116952318e-5, 8.250922335246762e-5, 8.320257817055557e-5, 7.34956107173241e-5, 7.626902998967594e-5, 8.042915889820373e-5, 7.696238480776391e-5, 5.962851435556483e-5, 6.864212699070835e-5, 8.45892878067315e-5, 6.03218691736528e-5, 6.656206253644446e-5, 7.280225589923613e-5, 6.1015223991740755e-5, 6.79487721726204e-5, 5.754844990130094e-5, 6.656206253644446e-5, 5.962851435556483e-5, 5.962851435556483e-5, 5.962851435556483e-5, 6.37886432640926e-5, 5.8241804719388903e-5, 6.656206253644446e-5, 5.685509508321298e-5, 5.754844990130094e-5, 5.8241804719388903e-5, 5.754844990130094e-5, 5.6161740265125016e-5, 5.685509508321298e-5, 5.685509508321298e-5, 6.170857880982872e-5, 5.061490172042131e-5, 6.37886432640926e-5, 5.26949661746852e-5, 5.6161740265125016e-5, 6.309528844600465e-5, 5.546838544703705e-5, 6.240193362791668e-5, 5.477503062894909e-5, 5.061490172042131e-5, 5.962851435556483e-5, 5.2001611356597236e-5, 6.170857880982872e-5, 5.061490172042131e-5, 5.26949661746852e-5, 5.130825653850927e-5, 4.992154690233335e-5, 5.6161740265125016e-5, 5.3388320992773165e-5, 4.368135353954168e-5, 5.685509508321298e-5, 5.8241804719388903e-5, 5.546838544703705e-5, 4.853483726615742e-5, 5.546838544703705e-5, 4.576141799380557e-5, 4.992154690233335e-5, 5.754844990130094e-5, 4.9228192084245384e-5,
).toDoubleArray(),
arrayOf(
0.0010303202590361028, 0.0010303202590361028, 0.0002939810160372191, 0.00010400271793769544, 3.813432991048833e-5, 3.1200815381308634e-5, 2.4267300852128935e-5, 1.733378632294924e-5, 1.1786974699605483e-5, 6.240163076261727e-6, 5.546811623343757e-6, 4.160108717507818e-6, 0.0002419796570683714, 0.0011946445533776615, 0.0008770895879412316, 0.0007120719421467548, 0.0004742523937958912, 0.0004222510348270435, 0.00038203665055780125, 0.0003272618857772816, 0.00028150068988469566, 0.00023157938527460184, 0.0002142455989516526, 0.00018859159519368774, 0.00019067164955244162, 0.00013659023622484, 0.00014699050801860955, 0.00015531072545362518, 0.00013104342460149625, 0.00012064315280772671, 0.00012896337024274234, 0.00011925644990189076, 0.0001046960693906134, 0.00011024288101395716, 8.736228306766417e-5, 8.805563452058214e-5, 8.18154714443204e-5, 7.765536272681259e-5, 7.418860546222275e-5, 7.904206563264853e-5, 7.349525400930477e-5, 7.834871417973056e-5, 7.765536272681259e-5, 7.07218481976329e-5, 6.933514529179696e-5, 6.17082793096993e-5, 6.17082793096993e-5, 7.141519965055087e-5, 6.933514529179696e-5, 5.893487349802742e-5, 5.061465606301178e-5, 5.7548170592191474e-5, 4.5067844439668026e-5, 5.962822495094538e-5, 5.7548170592191474e-5, 4.78412502513399e-5, 5.061465606301178e-5, 4.368114153383208e-5, 4.7147898798421934e-5, 5.061465606301178e-5, 4.645454734550396e-5, 5.616146768635554e-5, 4.645454734550396e-5, 5.408141332760163e-5, 4.576119589258599e-5, 4.368114153383208e-5, 4.922795315717584e-5, 4.5067844439668026e-5, 4.4374492986750054e-5, 5.616146768635554e-5, 4.368114153383208e-5, 4.4374492986750054e-5, 3.6054275551734415e-5, 4.922795315717584e-5, 4.368114153383208e-5, 4.7147898798421934e-5, 4.576119589258599e-5, 2.981411247547269e-5, 4.1601087175078175e-5, 4.09077357221602e-5, 4.7147898798421934e-5, 4.368114153383208e-5, 3.8827681363406295e-5, 5.130800751592975e-5, 3.9521032816324267e-5, 4.09077357221602e-5, 4.2294438627996146e-5, 4.1601087175078175e-5, 4.368114153383208e-5, 4.368114153383208e-5, 5.200135896884772e-5, 4.368114153383208e-5, 4.021438426924224e-5, 3.9521032816324267e-5, 3.9521032816324267e-5, 3.744097845757036e-5, 4.78412502513399e-5, 3.536092409881645e-5, 4.922795315717584e-5, 5.200135896884772e-5, 4.7147898798421934e-5,
).toDoubleArray(),
arrayOf(
0.0008508601296627827, 0.0008508601296627827, 0.0002753189687851931, 0.0001113727486794374, 3.943010356973871e-5, 2.4903223307203395e-5, 1.936917368338042e-5, 9.68458684169021e-6, 1.1759855450623826e-5, 4.150537217867232e-6, 6.917562029778721e-6, 4.842293420845105e-6, 0.0002227454973588748, 0.0010618457715710337, 0.0007768422159441504, 0.0006177382892592398, 0.0004240465524254356, 0.0004212795276135241, 0.00032166663438471053, 0.00030852326652813095, 0.00027393545637923735, 0.00022966305938865354, 0.00018677417480402546, 0.00015564514567002123, 0.00015287812085810974, 0.0001487275836402425, 0.0001342007033777072, 0.00011483152969432677, 0.00011206450488241528, 0.00010998923627348166, 0.00010791396766454805, 0.00011068099247645954, 9.546235601094635e-5, 8.508601296627827e-5, 9.477059980796847e-5, 7.886020713947742e-5, 5.9491033456097e-5, 5.1189959020362534e-5, 5.7415764847163385e-5, 5.9491033456097e-5, 6.018278965907487e-5, 7.19426451096987e-5, 6.848386409480934e-5, 4.7731178005473176e-5, 5.6724008644185514e-5, 5.603225244120764e-5, 5.603225244120764e-5, 5.603225244120764e-5, 4.1505372178672324e-5, 4.980644661440679e-5, 4.842293420845105e-5, 4.980644661440679e-5, 5.6724008644185514e-5, 4.7039421802495304e-5, 4.842293420845105e-5, 4.358064078760594e-5, 5.1189959020362534e-5, 3.527956635187148e-5, 4.496415319356169e-5, 4.427239699058382e-5, 4.911469041142892e-5, 3.666307875782722e-5, 4.911469041142892e-5, 4.288888458462807e-5, 3.2512541539959986e-5, 4.565590939653956e-5, 4.2197128381650196e-5, 4.081361597569445e-5, 3.8046591163782966e-5, 3.043727293102637e-5, 4.358064078760594e-5, 3.666307875782722e-5, 4.7039421802495304e-5, 3.527956635187148e-5, 4.358064078760594e-5, 4.7731178005473176e-5, 4.565590939653956e-5, 3.943010356973871e-5, 3.8046591163782966e-5, 3.597132255484935e-5, 3.943010356973871e-5, 4.288888458462807e-5, 4.7731178005473176e-5, 4.1505372178672324e-5, 3.597132255484935e-5, 4.358064078760594e-5, 3.043727293102637e-5, 4.081361597569445e-5, 3.666307875782722e-5, 4.496415319356169e-5, 2.905376052507063e-5, 3.943010356973871e-5, 3.389605394591573e-5, 3.597132255484935e-5, 3.7354834960805095e-5, 4.288888458462807e-5, 3.666307875782722e-5, 3.666307875782722e-5, 3.7354834960805095e-5, 3.320429774293786e-5, 3.7354834960805095e-5,
).toDoubleArray(),
arrayOf(
0.0006738059660191488, 0.0006738059660191488, 0.00026772372571808067, 0.00010169350821849576, 4.150755437489623e-5, 3.389783607283192e-5, 1.7986606895788368e-5, 1.5911229177043554e-5, 1.5911229177043554e-5, 8.301510874979247e-6, 5.5343405833194975e-6, 4.84254801040456e-6, 0.00022621617134318446, 0.001023853007914107, 0.000748519563893962, 0.0006212297304776136, 0.00041161658088438764, 0.0003818695002490453, 0.00032790967956168024, 0.00026910731086391055, 0.0002269079639160994, 0.0002068459793015662, 0.00018470861696828823, 0.00014250927002047706, 0.000121063700260114, 0.00013144058885383806, 0.00011760473739553932, 0.0001224472854059439, 0.00014043389230173226, 0.00010861143394764513, 0.00011622115224970945, 0.0001155293596767945, 9.062482705185677e-5, 9.270020477060159e-5, 7.748076816647296e-5, 7.886435331230284e-5, 6.917925729149372e-5, 7.194642758315347e-5, 6.848746471857879e-5, 7.81725607393879e-5, 7.748076816647296e-5, 6.433670928108916e-5, 6.917925729149372e-5, 6.779567214566384e-5, 5.9494161270684595e-5, 6.917925729149372e-5, 4.6350102385300794e-5, 5.39598206873651e-5, 5.603519840610991e-5, 4.911727267696054e-5, 5.119265039570535e-5, 4.6350102385300794e-5, 5.741878355193979e-5, 4.565830981238585e-5, 6.848746471857879e-5, 6.50285018540041e-5, 5.0500857822790416e-5, 4.911727267696054e-5, 4.3582932093641044e-5, 4.4966517239470916e-5, 5.39598206873651e-5, 6.156953898942942e-5, 5.603519840610991e-5, 4.911727267696054e-5, 5.257623554153522e-5, 4.911727267696054e-5, 5.188444296862029e-5, 3.943217665615142e-5, 4.911727267696054e-5, 4.565830981238585e-5, 3.8048591510321544e-5, 4.427472466655598e-5, 5.465161326028004e-5, 4.980906524987548e-5, 3.458962864574686e-5, 4.980906524987548e-5, 3.389783607283192e-5, 4.0815761801981294e-5, 5.465161326028004e-5, 4.911727267696054e-5, 4.2199346947811166e-5, 4.427472466655598e-5, 4.7733687531130666e-5, 5.465161326028004e-5, 4.289113952072611e-5, 3.8048591510321544e-5, 3.874038408323648e-5, 5.741878355193979e-5, 4.427472466655598e-5, 4.84254801040456e-5, 4.704189495821573e-5, 3.874038408323648e-5, 4.289113952072611e-5, 4.3582932093641044e-5, 3.735679893740661e-5, 4.150755437489623e-5, 4.565830981238585e-5, 4.427472466655598e-5, 3.943217665615142e-5, 5.257623554153522e-5, 4.289113952072611e-5,
).toDoubleArray(),
arrayOf(
0.000670833062743272, 0.000670833062743272, 0.000257693854174295, 0.00010708457747189202, 4.42155674722651e-5, 2.7634729670165686e-5, 1.727170604385355e-5, 2.210778373613255e-5, 1.727170604385355e-5, 1.31264965933287e-5, 3.4543412087707107e-6, 8.981287142803847e-6, 0.00019482484417466807, 0.0009464894912031747, 0.0006307627047215318, 0.0005630576170296258, 0.0003654692998879412, 0.0003426706479100545, 0.00029500073922901867, 0.000267366009558853, 0.00021900523263606304, 0.00019137050296589737, 0.0001526818814276654, 0.00013748278010907429, 0.0001181384693399583, 0.00012090194230697487, 9.395808087856332e-5, 9.533981736207161e-5, 0.00010984805043890859, 8.497679373575947e-5, 9.603068560382575e-5, 7.944984780172634e-5, 9.879415857084232e-5, 6.632335120839765e-5, 7.806811131821806e-5, 7.185029714243078e-5, 6.425074648313521e-5, 4.490643571401923e-5, 4.905164516454409e-5, 5.319685461506894e-5, 6.56324829666435e-5, 4.076122626349438e-5, 4.007035802174024e-5, 5.1124249889806513e-5, 4.076122626349438e-5, 5.3887722856823085e-5, 5.526945934033137e-5, 4.9742513406298234e-5, 4.5597303955773376e-5, 3.7306885054723674e-5, 4.697904043928166e-5, 4.490643571401923e-5, 3.3852543845952966e-5, 4.42155674722651e-5, 4.628817219752752e-5, 4.1452094505248525e-5, 4.3524699230510954e-5, 3.799775329647782e-5, 3.5234280329461245e-5, 3.3852543845952966e-5, 3.93794897799861e-5, 3.45434120877071e-5, 3.7306885054723674e-5, 4.490643571401923e-5, 3.316167560419882e-5, 2.62529931866574e-5, 2.7634729670165686e-5, 3.3852543845952966e-5, 3.1089070878936394e-5, 4.490643571401923e-5, 3.7306885054723674e-5, 3.868862153823196e-5, 2.8325597911919825e-5, 2.901646615367397e-5, 3.316167560419882e-5, 4.214296274700267e-5, 3.177993912069054e-5, 2.8325597911919825e-5, 3.1089070878936394e-5, 2.62529931866574e-5, 3.177993912069054e-5, 3.039820263718225e-5, 2.901646615367397e-5, 3.7306885054723674e-5, 4.1452094505248525e-5, 2.5562124944903257e-5, 3.93794897799861e-5, 2.7634729670165686e-5, 3.177993912069054e-5, 3.316167560419882e-5, 3.3852543845952966e-5, 3.3852543845952966e-5, 3.1089070878936394e-5, 4.3524699230510954e-5, 2.901646615367397e-5, 3.316167560419882e-5, 3.3852543845952966e-5, 3.177993912069054e-5, 3.799775329647782e-5, 3.5234280329461245e-5, 3.177993912069054e-5,
).toDoubleArray(),
)
// private val fineInterpolator = PiecewiseBicubicSplineInterpolator().interpolate(x, yFine, gridFine)
private val fineInterpolator = BilinearInterpolator(x, yFine, gridFine)
fun value(ei: Double, delta: Double): Double {
var eiL = ei;
if (ei < x.first() || ei > x.last())
if (ei > x.last() && (ei - x.last()) < 200.0) {
eiL = x.last()
} else {
error("trap: ei ($ei) not in [${x.first()}..${x.last()}]")
}
if (delta < yFine.first())
error("trap: delta < ${yFine.first()}")
if (delta > yCoarse.last())
error("trap: delta > ${yCoarse.last()}")
return if (delta < yFine.last()) {
fineInterpolator.value(eiL, delta)
} else {
coarseInterpolator.value(eiL, delta)
}
}
}

@ -0,0 +1,77 @@
package ru.inr.mass.scripts
import ru.inr.mass.models.*
import ru.inr.mass.models.NBkgSpectrum.Companion.bkg
import ru.inr.mass.models.NBkgSpectrum.Companion.norm
import ru.inr.mass.models.NumassBeta.e0
import ru.inr.mass.models.NumassBeta.mnu2
import ru.inr.mass.models.NumassBeta.msterile2
import ru.inr.mass.models.NumassBeta.u2
import ru.inr.mass.models.NumassTransmission.Companion.thickness
import ru.inr.mass.models.NumassTransmission.Companion.trap
import ru.inr.mass.workspace.buffer
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.real.step
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
fun main() {
val trapInterpolator = TrapInterpolator()
val range = 10000.0..18600.0 step 50.0
val args: Map<Symbol, Double> = mapOf(
norm to 231296.31435970013,
bkg to 1.156996613764463,
mnu2 to 0.0,
e0 to 18553.267180007213,
msterile2 to 16e6,
u2 to -0.006326658267906115,
thickness to 0.1,
trap to 3.0,
rearWall to 0.0
)
val argsRWall = args.toMutableMap();
argsRWall[rearWall] = 0.04
val spectrumC: NBkgSpectrum = CustomSterileNeutrinoSpectrum(
fss = null,
transmission = NumassTransmission(
trapFunc = { ei, ef, _ ->
val delta = ei - ef
trapInterpolator.value(ei, delta)
},
adjustX = false,
),
resolution = NumassResolution(1.7e-4, tailFunction = {
e,u -> adiabacity(e,u)
})
).withNBkg()
Plotly.page {
plot {
scatter {
name = "CustomSterileNeutrinoSpectrum (rearWall=${args[rearWall]})"
mode = ScatterMode.lines
x.buffer = range
y.numbers = x.doubles.map { spectrumC(it, args) }
}
scatter {
name = "CustomSterileNeutrinoSpectrum (rearWall=${argsRWall[rearWall]})"
mode = ScatterMode.lines
x.buffer = range
y.numbers = x.doubles.map { spectrumC(it, argsRWall) }
}
layout {
title = "Compare Trap"
// yaxis.type = AxisType.log
}
}
}.makeFile()
println("HV\trearWall=${args[rearWall]}\trearWall=${argsRWall[rearWall]}")
range.iterator().forEach {
println("${it}\t${spectrumC(it, args)}\t${spectrumC(it, argsRWall)}")
}
}

@ -0,0 +1,21 @@
package ru.inr.mass.scripts
import ru.inr.mass.workspace.buffer
import space.kscience.kmath.real.step
import space.kscience.plotly.*
import space.kscience.plotly.models.ScatterMode
fun main() {
Plotly.page {
plot {
scatter {
name = "Rear Wall Function"
mode = ScatterMode.lines
x.buffer = WALL_L..18600.0 step 10.0
y.numbers = x.doubles.map {
wallStep(it)
}
}
}
}.makeFile()
}

@ -0,0 +1,29 @@
package ru.inr.mass.scripts
import org.apache.commons.math3.analysis.interpolation.LinearInterpolator
import space.kscience.kmath.real.step
import space.kscience.kmath.structures.toDoubleArray
//fun wallStep(u: Double): Double {
// return (3.932729e-13 * u.pow(4.0)
// - 2.827187e-8 * u.pow(3.0)
// + 7.618574e-4 * u.pow(2.0)
// - 9.124489 * u
// + 4.099330e+4) * 1e-4
//}
// Angle = 170.4, 2025-03-10 (weekend simulation)
private val WALL_FROM_GEANT = arrayOf<Double>(
1.0, 0.974889596797131, 0.950165449373342, 0.925878240027274, 0.902311758151626, 0.879132319047274, 0.856348579628581, 0.834079847915328, 0.812201149543789, 0.790758287460869, 0.769751104268126, 0.749232643240847, 0.729118853610476, 0.709528256404582, 0.690139758799478, 0.671295072814881, 0.652845299523728, 0.634648150733563, 0.616858191715396, 0.599567815355257, 0.582656454445821, 0.566172272910642, 0.549971565971275, 0.534191899866888, 0.518664543466603, 0.503475593718732, 0.488613875333822, 0.474227972442051, 0.460122868372562, 0.446209318208182, 0.432675413088279, 0.419513597887587, 0.406557974647203, 0.39401237435079, 0.381752137431506, 0.369754755912004, 0.358029988495748, 0.346635285614428, 0.335533816032385, 0.324734236663984, 0.314120544856746, 0.303777263574553, 0.293732881935585, 0.284010852307847, 0.274466525522236, 0.265141454767701, 0.25609466446036, 0.247273111324928, 0.238704969682699, 0.23032838194558, 0.222270998250831, 0.214340005505798, 0.206652508152059, 0.199180961462093, 0.191947716014804, 0.184905394878853, 0.178079181805118, 0.171412570752568, 0.164988038505326, 0.158764504069773, 0.152701043850734, 0.146805212973472, 0.141124703166211, 0.135583805777877, 0.130177484058292, 0.124914394921823, 0.119823499681976, 0.1149093628936, 0.110161438861015, 0.105554071638013, 0.101109611803498, 0.0968214486228659, 0.0926755736346905, 0.0886904024568008, 0.084864990698539, 0.081125675888589, 0.0775395097636615, 0.0740462087200941, 0.070699130830058, 0.0674773421006365, 0.0643366135693513, 0.061336127050764, 0.0583973407218261, 0.0556094994997091, 0.0529393923129434, 0.0503435771912657, 0.0478253595019787, 0.0454036270582404, 0.0430920735245903, 0.0408570156342299, 0.0387310348648569, 0.0366708466446508, 0.0347000607400591, 0.0328421295190864, 0.0310358249874121, 0.0293187653729092, 0.0276646651355995, 0.0261045317687508, 0.0245946085052137, 0.0231578755176638, 0.02176631588325, 0.0204498353061392, 0.0191941105280198, 0.0180100020414578, 0.0168789368301811, 0.0157873786280931, 0.0147616129751721, 0.0137995936916593, 0.0128448147365237, 0.0119873080191516, 0.011181270592635, 0.010398370737237, 0.00964521918756275, 0.00893724099102467, 0.00828797241371929, 0.00766215620441839, 0.00708025416070979, 0.00652825782116798, 0.00602001824877548, 0.00555034129491384, 0.00508947865385926, 0.00466733602977853, 0.00426014625778119, 0.00388002901797695, 0.00352808609946669, 0.0032043175022504, 0.00290069590573596, 0.00261753610680932, 0.00236428201204948, 0.00212330499584232, 0.00191302067601687, 0.00170981928612566, 0.0015275518891512, 0.00136794986796632, 0.00121228280785601, 0.00107487396713174, 0.00094974220496016, 0.000832952560266683, 0.000731587962985553, 0.000632899139235135, 0.000551366745769878, 0.000469519555418654, 0.000398375459190283, 0.000341239824387409, 0.000290714924189827, 0.000243652789737873, 0.000211071312040367, 0.000175971459255131, 0.000143704778443591, 0.000117576636908392, 9.41242689039072E-05, 7.47642604169831E-05, 5.54042519300591E-05, 4.28123764914093E-05, 3.44702590133038E-05, 2.75447275220464E-05, 2.1878383574654E-05, 1.69990318421772E-05, 1.24344769956667E-05, 7.86992214915612E-06, 5.35154706142616E-06, 3.30536730264557E-06, 2.04617975878059E-06, 9.44390657898734E-07, 6.29593771932489E-07, 1.57398442983122E-07, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
)
const val WALL_STEP = 50.0
const val WALL_L = 10_000.0
const val WALL_R = 19_000.0
private val WALL_INTERPOLATOR = LinearInterpolator().interpolate(
(WALL_L..WALL_R step WALL_STEP).toDoubleArray(),
WALL_FROM_GEANT.toDoubleArray()
)
fun wallStep(u: Double): Double {
return WALL_INTERPOLATOR.value(u)
}

@ -1,45 +0,0 @@
package ru.inr.mass.workspace
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassPoint
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
object Numass {
val workspace = Workspace {
context {
plugin(NumassWorkspacePlugin)
}
}
val context get() = workspace.context
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) }
}
fun NumassBlock.listFrames() = runBlocking { frames.toList() }
fun NumassBlock.listEvents() = runBlocking { events.toList() }

@ -1,134 +0,0 @@
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()
}
}

@ -0,0 +1,118 @@
@file:OptIn(UnstableKMathAPI::class)
package ru.inr.mass.workspace
import ru.inr.mass.models.Spectrum
import space.kscience.attributes.Attributes
import space.kscience.attributes.AttributesBuilder
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.data.XYColumnarData
import space.kscience.kmath.data.XYErrorColumnarData
import space.kscience.kmath.expressions.AutoDiffProcessor
import space.kscience.kmath.expressions.DifferentiableExpression
import space.kscience.kmath.expressions.ExpressionAlgebra
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.optimization.*
import space.kscience.kmath.random.RandomGenerator
import space.kscience.kmath.samplers.PoissonSampler
import space.kscience.kmath.stat.next
import space.kscience.kmath.structures.Float64
import space.kscience.kmath.structures.asBuffer
import kotlin.math.sqrt
//public suspend fun XYColumnarData<Double, Double, Double>.fitWith(
// optimizer: Optimizer<Double, XYFit>,
// modelExpression: DifferentiableExpression<Double>,
// startingPoint: Map<Symbol, Double>,
// vararg features: OptimizationFeature = emptyArray(),
// xSymbol: Symbol = Symbol.x,
// pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY,
// pointWeight: PointWeight = PointWeight.byYSigma,
//): XYFit {
// var actualFeatures = FeatureSet.of(*features, OptimizationStartPoint(startingPoint))
//
// if (actualFeatures.getFeature<OptimizationLog>() == null) {
// actualFeatures = actualFeatures.with(OptimizationLog(Loggable.console))
// }
// val problem = XYFit(
// this,
// modelExpression,
// actualFeatures,
// pointToCurveDistance,
// pointWeight,
// xSymbol
// )
// return optimizer.optimize(problem)
//}
public fun AttributesBuilder<OptimizationProblem<*>>.freeParameters(vararg symbols: Symbol) {
OptimizationParameters(symbols.asList())
}
public fun AttributesBuilder<OptimizationProblem<*>>.iterations(iterations: Int) {
OptimizationIterations(iterations)
}
public suspend fun XYColumnarData<Double, Double, Double>.fitWith(
optimizer: Optimizer<Double, XYFit>,
modelExpression: DifferentiableExpression<Float64>,
startingPoint: Map<Symbol, Double>,
attributesBuilder: AttributesBuilder<XYFit>.() -> Unit,
xSymbol: Symbol = Symbol.x,
pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY,
pointWeight: PointWeight = PointWeight.byYSigma,
): XYFit = fitWith(
optimizer = optimizer,
modelExpression = modelExpression,
startingPoint = startingPoint,
attributes = Attributes<XYFit>(attributesBuilder),
xSymbol = xSymbol,
pointToCurveDistance = pointToCurveDistance,
pointWeight = pointWeight
)
public suspend fun <I : Any, A> XYColumnarData<Double, Double, Double>.fitWith(
optimizer: Optimizer<Double, XYFit>,
processor: AutoDiffProcessor<Double, I, A>,
startingPoint: Map<Symbol, Double>,
attributesBuilder: AttributesBuilder<XYFit>.() -> Unit,
xSymbol: Symbol = Symbol.x,
pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY,
pointWeight: PointWeight = PointWeight.byYSigma,
model: A.(I) -> I,
): XYFit where A : ExtendedField<I>, A : ExpressionAlgebra<Double, I> = fitWith(
optimizer = optimizer,
processor = processor,
startingPoint = startingPoint,
attributes = Attributes<XYFit>(attributesBuilder),
xSymbol = xSymbol,
pointToCurveDistance = pointToCurveDistance,
pointWeight = pointWeight,
model = model
)
public suspend fun Spectrum.generate(
strategy: Map<Double, Double>,
arguments: Map<Symbol, Double>,
generator: RandomGenerator = RandomGenerator.default,
): XYErrorColumnarData<Double, Double, Double> {
val xs = mutableListOf<Double>()
val ys = mutableListOf<Double>()
val errors = mutableListOf<Double>()
strategy.forEach { (x, time) ->
xs.add(x)
val mu = invoke(x, arguments) * time
val y = PoissonSampler(mu).next(generator) / time
val error = sqrt(mu) / time
ys.add(y)
errors.add(error)
}
return XYErrorColumnarData.of(
xs.toTypedArray().asBuffer(),
ys.toTypedArray().asBuffer(),
errors.toTypedArray().asBuffer()
)
}

@ -1,147 +1,18 @@
package ru.inr.mass.workspace
import kotlinx.coroutines.runBlocking
import kotlinx.html.h1
import kotlinx.html.h2
import ru.inr.mass.data.analysis.NumassAmplitudeSpectrum
import ru.inr.mass.data.analysis.NumassEventExtractor
import ru.inr.mass.data.analysis.amplitudeSpectrum
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.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
import space.kscience.kmath.operations.asIterable
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.plotly.*
import space.kscience.kmath.structures.Float64Buffer
import space.kscience.plotly.models.*
import kotlin.time.DurationUnit
/**
* Plot a kmath histogram
*/
@OptIn(UnstableKMathAPI::class)
fun Plot.histogram(histogram: Histogram1D<Double, Double>, block: Scatter.() -> Unit = {}): Trace = scatter {
x.numbers = histogram.bins.map { it.domain.center }
y.numbers = histogram.bins.map { it.binValue }
line.shape = LineShape.hv
block()
}
fun Plot.histogram(
spectrum: NumassAmplitudeSpectrum,
binSize: UInt = 20U,
block: Scatter.() -> Unit = {},
): Trace = scatter {
val binned = spectrum.binned(binSize)
x.numbers = binned.keys.map { (it.first + it.last).toDouble() / 2.0 }
y.numbers = binned.values
line.shape = LineShape.hv
block()
}
/**
* Generate a plot from hv data
*/
fun Plot.hvData(data: HVData): Trace = scatter {
x.strings = data.map { it.timestamp.toString() }
y.numbers = data.map { it.value }
}
fun Plotly.plotNumassBlock(
block: NumassBlock,
amplitudeBinSize: UInt = 20U,
eventExtractor: NumassEventExtractor = NumassEventExtractor.EVENTS_ONLY,
splitChannels: Boolean = true,
): PlotlyFragment = Plotly.fragment {
plot {
runBlocking {
if (splitChannels && block is NumassPoint) {
block.channels.forEach { (channel, channelBlock) ->
val spectrum = channelBlock.amplitudeSpectrum(eventExtractor)
histogram(spectrum, amplitudeBinSize) {
name = block.title + "[$channel]"
}
}
} else {
scatter {
val spectrum = block.amplitudeSpectrum(eventExtractor)
histogram(spectrum, amplitudeBinSize)
}
}
}
}
}
fun Plotly.plotNumassSet(
set: NumassSet,
amplitudeBinSize: UInt = 20U,
eventExtractor: NumassEventExtractor = NumassEventExtractor.EVENTS_ONLY,
): PlotlyFragment = Plotly.fragment {
h1 { +"Numass point set ${(set as? NumassDirectorySet)?.path ?: ""}" }
//TODO do in parallel
val spectra = runBlocking {
set.points.sortedBy { it.index }.map { it to it.amplitudeSpectrum(eventExtractor) }
}
h2 { +"Amplitude spectrum" }
plot {
spectra.forEach { (point, spectrum) ->
histogram(spectrum, amplitudeBinSize) {
name = point.title
}
}
}
h2 { +"Time spectra" }
plot {
spectra.forEach { (point, spectrum) ->
val countRate = runBlocking {
spectrum.sum().toDouble() / point.getLength().toDouble(DurationUnit.SECONDS)
}
val binSize = 1.0 / countRate / 10.0
histogram(point.timeHistogram(binSize)) {
name = point.title
}
}
layout.yaxis.type = AxisType.log
}
h2 { +"Integral spectrum" }
plot {
scatter {
mode = ScatterMode.markers
x.numbers = spectra.map { it.first.voltage }
y.numbers = spectra.map { it.second.sum().toLong() }
}
}
if (set is NumassDirectorySet) {
set.hvData?.let { entries ->
h2 { +"HV" }
plot {
hvData(entries)
}
}
}
}
/**
* Add a number buffer accessor for Plotly trace values
*/
public var TraceValues.buffer: Buffer<Number>
get() = value?.list?.let { list -> DoubleBuffer(list.size) { list[it].double } } ?: DoubleBuffer()
get() = value?.list?.let { list -> Float64Buffer(list.size) { list[it].double } } ?: Float64Buffer()
set(value) {
this.value = value.asIterable().map { it.asValue() }.asValue()
}

@ -0,0 +1,108 @@
U events error
12000 6.452460E+07 8032.720335
12050 6.308058E+07 7942.32812
12100 6.166233E+07 7852.536369
12150 6.026178E+07 7762.846435
12200 5.888044E+07 7673.359382
12250 5.752020E+07 7584.207129
12300 5.618589E+07 7495.725049
12350 5.486976E+07 7407.412404
12400 5.357057E+07 7319.192132
12450 5.229649E+07 7231.631507
12500 5.104097E+07 7144.295993
12550 4.980586E+07 7057.326711
12600 4.858747E+07 6970.471306
12650 4.739252E+07 6884.222328
12700 4.621748E+07 6798.344134
12750 4.505844E+07 6712.55872
12800 4.392086E+07 6627.281125
12850 4.280192E+07 6542.317643
12900 4.170236E+07 6457.736238
12950 4.062241E+07 6373.571204
13000 3.955862E+07 6289.564579
13050 3.851518E+07 6206.059556
13100 3.748997E+07 6122.905734
13150 3.648207E+07 6040.03875
13200 3.549434E+07 5957.712236
13250 3.452146E+07 5875.496153
13300 3.356598E+07 5793.615159
13350 3.263059E+07 5712.318869
13400 3.171169E+07 5631.313607
13450 3.080984E+07 5550.661274
13500 2.992572E+07 5470.440919
13550 2.905686E+07 5390.441869
13600 2.820575E+07 5310.908839
13650 2.737116E+07 5231.745008
13700 2.655560E+07 5153.212589
13750 2.575232E+07 5074.674515
13800 2.496715E+07 4996.713422
13850 2.419569E+07 4918.911404
13900 2.344232E+07 4841.727268
13950 2.270363E+07 4764.832291
14000 2.198215E+07 4688.512852
14050 2.127411E+07 4612.386446
14100 2.058196E+07 4536.734227
14150 1.990347E+07 4461.330615
14200 1.924117E+07 4386.475463
14250 1.859371E+07 4312.041926
14300 1.796066E+07 4238.001528
14350 1.734144E+07 4164.305627
14400 1.673491E+07 4090.832005
14450 1.614486E+07 4018.066921
14500 1.556582E+07 3945.354348
14550 1.500395E+07 3873.492826
14600 1.445357E+07 3801.785423
14650 1.391677E+07 3730.51812
14700 1.339411E+07 3659.796472
14750 1.288430E+07 3589.470303
14800 1.238646E+07 3519.440284
14850 1.190164E+07 3449.875909
14900 1.143011E+07 3380.844281
14950 1.097078E+07 3312.217027
15000 1.052425E+07 3244.109423
15050 1.008924E+07 3176.356172
15100 9.665787E+06 3108.984892
15150 9.254249E+06 3042.079724
15200 8.854339E+06 2975.624154
15250 8.467155E+06 2909.837666
15300 8.090963E+06 2844.46187
15350 7.725603E+06 2779.496931
15400 7.370687E+06 2714.900844
15450 7.028022E+06 2651.041609
15500 6.694518E+06 2587.376647
15550 6.372090E+06 2524.299879
15600 6.058846E+06 2461.472259
15650 5.758606E+06 2399.709617
15700 5.466336E+06 2338.019685
15750 5.183979E+06 2276.835393
15800 4.912587E+06 2216.435542
15850 4.648231E+06 2155.975548
15900 4.396058E+06 2096.677784
15950 4.151727E+06 2037.578662
16000 3.916397E+06 1978.98901
16100 3.473288E+06 1863.676016
16200 3.065010E+06 1750.717128
16300 2.688767E+06 1639.746111
16400 2.344119E+06 1531.051707
16500 2.029421E+06 1424.577365
16600 1.743956E+06 1320.589413
16700 1.487062E+06 1219.45145
16800 1.255541E+06 1120.509421
16900 1.049216E+06 1024.312329
17000 8.724297E+05 934.0394267
17100 7.157295E+05 846.0079518
17200 5.750288E+05 758.3065238
17300 4.560588E+05 675.3212528
17400 3.553991E+05 596.1536111
17500 2.697442E+05 519.3690855
17600 2.005270E+05 447.8024159
17700 1.434300E+05 378.7215839
17800 9.860455E+04 314.0136092
17900 6.354514E+04 252.0816166
18000 3.898907E+04 197.456499
18100 2.149273E+04 146.6039915
18200 1.010559E+04 100.5265405
18300 4.910901E+03 70.07781835
18400 2.252190E+03 47.4572434
18500 1.860929E+03 43.13848425
18600 1.760000E+03 41.95235393
1 U events error
2 12000 6.452460E+07 8032.720335
3 12050 6.308058E+07 7942.32812
4 12100 6.166233E+07 7852.536369
5 12150 6.026178E+07 7762.846435
6 12200 5.888044E+07 7673.359382
7 12250 5.752020E+07 7584.207129
8 12300 5.618589E+07 7495.725049
9 12350 5.486976E+07 7407.412404
10 12400 5.357057E+07 7319.192132
11 12450 5.229649E+07 7231.631507
12 12500 5.104097E+07 7144.295993
13 12550 4.980586E+07 7057.326711
14 12600 4.858747E+07 6970.471306
15 12650 4.739252E+07 6884.222328
16 12700 4.621748E+07 6798.344134
17 12750 4.505844E+07 6712.55872
18 12800 4.392086E+07 6627.281125
19 12850 4.280192E+07 6542.317643
20 12900 4.170236E+07 6457.736238
21 12950 4.062241E+07 6373.571204
22 13000 3.955862E+07 6289.564579
23 13050 3.851518E+07 6206.059556
24 13100 3.748997E+07 6122.905734
25 13150 3.648207E+07 6040.03875
26 13200 3.549434E+07 5957.712236
27 13250 3.452146E+07 5875.496153
28 13300 3.356598E+07 5793.615159
29 13350 3.263059E+07 5712.318869
30 13400 3.171169E+07 5631.313607
31 13450 3.080984E+07 5550.661274
32 13500 2.992572E+07 5470.440919
33 13550 2.905686E+07 5390.441869
34 13600 2.820575E+07 5310.908839
35 13650 2.737116E+07 5231.745008
36 13700 2.655560E+07 5153.212589
37 13750 2.575232E+07 5074.674515
38 13800 2.496715E+07 4996.713422
39 13850 2.419569E+07 4918.911404
40 13900 2.344232E+07 4841.727268
41 13950 2.270363E+07 4764.832291
42 14000 2.198215E+07 4688.512852
43 14050 2.127411E+07 4612.386446
44 14100 2.058196E+07 4536.734227
45 14150 1.990347E+07 4461.330615
46 14200 1.924117E+07 4386.475463
47 14250 1.859371E+07 4312.041926
48 14300 1.796066E+07 4238.001528
49 14350 1.734144E+07 4164.305627
50 14400 1.673491E+07 4090.832005
51 14450 1.614486E+07 4018.066921
52 14500 1.556582E+07 3945.354348
53 14550 1.500395E+07 3873.492826
54 14600 1.445357E+07 3801.785423
55 14650 1.391677E+07 3730.51812
56 14700 1.339411E+07 3659.796472
57 14750 1.288430E+07 3589.470303
58 14800 1.238646E+07 3519.440284
59 14850 1.190164E+07 3449.875909
60 14900 1.143011E+07 3380.844281
61 14950 1.097078E+07 3312.217027
62 15000 1.052425E+07 3244.109423
63 15050 1.008924E+07 3176.356172
64 15100 9.665787E+06 3108.984892
65 15150 9.254249E+06 3042.079724
66 15200 8.854339E+06 2975.624154
67 15250 8.467155E+06 2909.837666
68 15300 8.090963E+06 2844.46187
69 15350 7.725603E+06 2779.496931
70 15400 7.370687E+06 2714.900844
71 15450 7.028022E+06 2651.041609
72 15500 6.694518E+06 2587.376647
73 15550 6.372090E+06 2524.299879
74 15600 6.058846E+06 2461.472259
75 15650 5.758606E+06 2399.709617
76 15700 5.466336E+06 2338.019685
77 15750 5.183979E+06 2276.835393
78 15800 4.912587E+06 2216.435542
79 15850 4.648231E+06 2155.975548
80 15900 4.396058E+06 2096.677784
81 15950 4.151727E+06 2037.578662
82 16000 3.916397E+06 1978.98901
83 16100 3.473288E+06 1863.676016
84 16200 3.065010E+06 1750.717128
85 16300 2.688767E+06 1639.746111
86 16400 2.344119E+06 1531.051707
87 16500 2.029421E+06 1424.577365
88 16600 1.743956E+06 1320.589413
89 16700 1.487062E+06 1219.45145
90 16800 1.255541E+06 1120.509421
91 16900 1.049216E+06 1024.312329
92 17000 8.724297E+05 934.0394267
93 17100 7.157295E+05 846.0079518
94 17200 5.750288E+05 758.3065238
95 17300 4.560588E+05 675.3212528
96 17400 3.553991E+05 596.1536111
97 17500 2.697442E+05 519.3690855
98 17600 2.005270E+05 447.8024159
99 17700 1.434300E+05 378.7215839
100 17800 9.860455E+04 314.0136092
101 17900 6.354514E+04 252.0816166
102 18000 3.898907E+04 197.456499
103 18100 2.149273E+04 146.6039915
104 18200 1.010559E+04 100.5265405
105 18300 4.910901E+03 70.07781835
106 18400 2.252190E+03 47.4572434
107 18500 1.860929E+03 43.13848425
108 18600 1.760000E+03 41.95235393

@ -1,7 +1,6 @@
rootProject.name = "numass"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
enableFeaturePreview("VERSION_CATALOGS")
pluginManagement {
@ -15,6 +14,7 @@ pluginManagement {
}
plugins {
id("org.jetbrains.compose").version(extra["compose.version"] as String)
id("space.kscience.gradle.project") version toolsVersion
id("space.kscience.gradle.mpp") version toolsVersion
id("space.kscience.gradle.jvm") version toolsVersion
@ -33,7 +33,7 @@ dependencyResolutionManagement {
}
versionCatalogs {
create("npmlibs") {
create("spclibs") {
from("space.kscience:version-catalog:$toolsVersion")
}
}
@ -41,9 +41,9 @@ dependencyResolutionManagement {
include(
":numass-data-model",
":numass-analysis",
":numass-data-proto",
":numass-data-server",
// ":numass-analysis",
// ":numass-data-proto",
// ":numass-data-server",
":numass-workspace",
":numass-model",
//":numass-detector-client"