Compare commits

...

4 Commits

Author SHA1 Message Date
c0bd75ff6c feat(grid-fit): move parallelization to Spectrum model
- save intermediate results more often
2026-01-29 11:28:31 +03:00
c9e66de47d fix: graalvm build multiple binaries and bundled resources 2026-01-29 11:27:25 +03:00
59737178c8 refactor: deduplicate resource loading code 2026-01-29 11:26:35 +03:00
704ff16cc4 fix: some trap models instantiation 2026-01-23 10:24:01 +03:00
6 changed files with 130 additions and 98 deletions

View File

@@ -11,10 +11,6 @@ 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
@@ -38,6 +34,32 @@ kotlinJupyter {
}
}
graalvmNative {
toolchainDetection.set(true)
// ← добавляем блок с настройками для нескольких бинарников
binaries {
named("main") {
imageName = "mass-app"
mainClass = "ru.inr.mass.scripts.ApplicationKt"
}
// создаём дополнительные бинарники
register("grid-fit") {
imageName = "grid-fit"
classpath = files(tasks.named<Jar>("jar"), configurations.runtimeClasspath)
buildArgs.add("--initialize-at-build-time=com.github.ajalt.mordant.internal.nativeimage.NativeImageWin32MppImpls")
mainClass = "ru.inr.mass.scripts.Grid_fitKt"
}
register("fit-custom") {
imageName = "fit-custom"
buildArgs.add("--initialize-at-build-time=com.github.ajalt.mordant.internal.nativeimage.NativeImageWin32MppImpls")
mainClass = "ru.inr.mass.scripts.Fit_customKt"
}
}
}
application {
}

View File

@@ -110,7 +110,6 @@ private class GridArgs : CliktCommand() {
@UnstableKMathAPI
override fun run() {
val postfix = if (postfix != null) "-$postfix" else ""
val fitParamsBase: Map<Symbol, Double> = mapOf(
@@ -123,7 +122,7 @@ private class GridArgs : CliktCommand() {
rearWall to rwall
)
val spectrumModel: NBkgSpectrum = SterileNeutrinoSpectrumRWall(
val spectrumModel: NBkgSpectrum = SterileNeutrinoSpectrumRWallMP(
wallFunc = wallFunc, transmission = NumassTransmission(
trapFunc = { ei, ef, _ ->
val delta = ei - ef
@@ -160,55 +159,61 @@ private class GridArgs : CliktCommand() {
val chi2Matrix = mutableMapOf<Pair<Double, Double>, Double?>()
withContext(Dispatchers.Default) {
coroutineScope {
mGrid.forEach { m ->
u2Grid.forEach { u2Val ->
launch {
val taskId = "${m.toInt()}_${String.format("%.0e", u2Val)}"
val fitParams = fitParamsBase.toMutableMap()
fitParams[NumassBeta.msterile2] = (m * 1000.0).pow(2)
fitParams[NumassBeta.u2] = u2Val
val logMessages = mutableListOf<String>()
val dumpLogger = Loggable { tag, block ->
val msg = "[$tag] ${block()}"
logMessages += msg
println("[$taskId] $msg")
}
val fit = fitNumassSpectrumRWall(
spectrumModel, data, fitVars, fitParams, dumpLogger
)
chi2Matrix[Pair(m, u2Val)] = fit.chiSquaredOrNull
if (!noReports) {
val mStr = String.format("%04.1f", m)
val u2Str = String.format("%9.2e", u2Val).replace(".", "_")
val reportFileName = "${mStr}-${u2Str}.html"
val reportPath = reportsDir.resolve(reportFileName)
reportPage(
spectrum,
postfix,
data,
spectrumModel,
fitParams,
fit,
dataForView,
dataPath,
this@GridArgs,
logMessages
).makeFile(path = reportPath, show = false)
}
}
}
}
mGrid.forEach { m ->
u2Grid.forEach { u2 ->
chi2Matrix[Pair(m, u2)] = null
}
}
saveChi2GridToTsv(spectrum, postfix, mGrid, u2Grid, chi2Matrix)
var current = 0
val total = mGrid.size * u2Grid.size
for (m in mGrid) {
for (u2Val in u2Grid) {
current++
val taskId = "${m.toInt()}_${String.format("%.0e", u2Val)}"
val fitParams = fitParamsBase.toMutableMap()
fitParams[NumassBeta.msterile2] = (m * 1000.0).pow(2)
fitParams[NumassBeta.u2] = u2Val
val logMessages = mutableListOf<String>()
val dumpLogger = Loggable { tag, block ->
val msg = "[$tag] ${block()}"
logMessages += msg
println("$current/$total [$taskId] $msg")
}
val fit = fitNumassSpectrumRWall(
spectrumModel, data, fitVars, fitParams, dumpLogger
)
chi2Matrix[Pair(m, u2Val)] = fit.chiSquaredOrNull
if (!noReports) {
val mStr = String.format("%04.1f", m)
val u2Str = String.format("%9.2e", u2Val).replace(".", "_")
val reportFileName = "${mStr}-${u2Str}.html"
val reportPath = reportsDir.resolve(reportFileName)
reportPage(
spectrum,
postfix,
data,
spectrumModel,
fitParams,
fit,
dataForView,
dataPath,
this@GridArgs,
logMessages
).makeFile(path = reportPath, show = false)
}
saveChi2GridToTsv(spectrum, postfix, mGrid, u2Grid, chi2Matrix)
}
}
}
}
}

View File

@@ -75,19 +75,21 @@ private class RearTrap10kev: ITrap {
}
}
fun loadResourceAsString(resourcePath: String): String {
return {}::class.java.classLoader
.getResourceAsStream(resourcePath)
?.bufferedReader()
?.use { it.readText() }
?: throw IllegalArgumentException("Resource not found: $resourcePath")
}
fun getRearTrapByName(name: String): ITrap {
return when(name) {
"RearTrap10kev" -> RearTrap10kev()
"25-11-26-2+" -> {
val resourcePath = "reartrap-6-days.json"
// Load JSON from resources at compile-time
val jsonInput = {}::class.java.classLoader
.getResourceAsStream(resourcePath)
?.bufferedReader()
?.use { it.readText() }
?: throw IllegalArgumentException("Resource not found: $resourcePath")
FineGridInterpolation(jsonInput, 2000.0, 2.0)
FineGridInterpolation(loadResourceAsString("reartrap-6-days.json"), 2000.0, 2.0)
}
else -> throw IllegalArgumentException()
}
}

View File

@@ -23,13 +23,26 @@ enum class TrapModel(val description: String) : ITrap {
NOZIK -> nozikValue(delta)
FINE_2DAY -> fine2DayInterpolator.value(ei, delta)
FINE_5DAY -> fine5DayInterpolator.value(ei, delta)
LEGACY_2024_07_12 -> TrapInterpolator_24_07_12().value(ei, delta)
LEGACY_FULL -> TrapInterpolatorFull().value(ei, delta)
LEGACY_DEFAULT -> TrapInterpolator().value(ei, delta)
LEGACY_2024_07_12 -> trapInterpolator_24_07_12.value(ei, delta)
LEGACY_FULL -> trapInterpolatorFull.value(ei, delta)
LEGACY_DEFAULT -> trapInterpolator.value(ei, delta)
}
}
private companion object {
private val trapInterpolator_24_07_12: TrapInterpolator_24_07_12 by lazy {
TrapInterpolator_24_07_12()
}
private val trapInterpolatorFull: TrapInterpolatorFull by lazy {
TrapInterpolatorFull()
}
private val trapInterpolator: TrapInterpolator by lazy {
TrapInterpolator()
}
// =====================================================================
// 1. Аналитическая модель Нозика
// =====================================================================
@@ -56,17 +69,6 @@ enum class TrapModel(val description: String) : ITrap {
val jsonInput = loadResourceAsString("trap-fine-5-day-2V.json")
FineGridInterpolation(jsonInput, wallL = 2000.0, deltaStep = 2.0)
}
// =====================================================================
// Утилита для загрузки ресурсов
// =====================================================================
private fun loadResourceAsString(resourcePath: String): String {
return {}::class.java.classLoader
.getResourceAsStream(resourcePath)
?.bufferedReader()
?.use { it.readText() }
?: throw IllegalArgumentException("Ресурс не найден: $resourcePath")
}
}
}

View File

@@ -3,14 +3,15 @@ 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
import kotlin.collections.toDoubleArray
/**
* Единая модель задней стенки (rear wall transmission)
*/
enum class WallModel(val description: String) {
GEANT_2025_03_10("Geant4 симуляция, угол 170.4°, март 2025"),
GEANT_2025_10_09("Geant4 симуляция, угол ~174.3°, октябрь 2025"),
GEANT_2024_07_12("Geant4 симуляция, старая версия, июль 2024"),
GEANT_2025_03_10("Geant4 симуляция, угол 170.4°, март 2025"), GEANT_2025_10_09("Geant4 симуляция, угол ~174.3°, октябрь 2025"), GEANT_2024_07_12(
"Geant4 симуляция, старая версия, июль 2024"
),
TSV_2025_12_01("Данные из файла rearwall-25-12-01.tsv, декабрь 2025");
/**
@@ -563,14 +564,10 @@ enum class WallModel(val description: String) {
// =====================================================================
// 4. Данные из внешнего TSV-файла (декабрь 2025)
// =====================================================================
private val Y_2025_12_01 = {}::class.java.classLoader
.getResourceAsStream("rearwall-25-12-01.tsv")
?.bufferedReader()
?.readLines()
?.filter { it.isNotBlank() }
?.map { it.trim().toDouble() }
?.toDoubleArray()
?: throw IllegalStateException("Не найден файл rearwall-25-12-01.tsv в ресурсах")
private val Y_2025_12_01 = loadResourceAsString("rearwall-25-12-01.tsv")
.lines()
.filter { it.isNotBlank() }
.map { it.trim().toDouble() }.toDoubleArray()
private val X_TSV = (2000.0..19000.0 step 50.0).toDoubleArray()
@@ -611,8 +608,7 @@ const val WALL_L = 2_000.0
const val WALL_R = 19_000.0
private val WALL_INTERPOLATOR = LinearInterpolator().interpolate(
(10_000.0..WALL_R step WALL_STEP).toDoubleArray(),
WALL_FROM_GEANT.toDoubleArray()
(10_000.0..WALL_R step WALL_STEP).toDoubleArray(), WALL_FROM_GEANT.toDoubleArray()
)
fun wallStep(u: Double): Double {
@@ -624,25 +620,18 @@ private val WALL_25_10_09 = arrayOf<Double>(
)
private val WALL_25_10_09_INTERPOLATOR = LinearInterpolator().interpolate(
(10_000.0..WALL_R step WALL_STEP).toDoubleArray(),
WALL_25_10_09.toDoubleArray()
(10_000.0..WALL_R step WALL_STEP).toDoubleArray(), WALL_25_10_09.toDoubleArray()
)
fun wall251009(u: Double): Double {
return WALL_25_10_09_INTERPOLATOR.value(u)
}
private val WALL_25_12_01 = {}::class.java.classLoader
.getResourceAsStream("rearwall-25-12-01.tsv")
?.bufferedReader()!!
.readLines()
.filter { it.isNotBlank() }
.map { it.trim().toDouble() }
.toDoubleArray()
private val WALL_25_12_01 = loadResourceAsString("rearwall-25-12-01.tsv")
.lines().filter { it.isNotBlank() }.map { it.trim().toDouble() }.toDoubleArray()
private val WALL_25_12_01_INTERPOLATOR = LinearInterpolator().interpolate(
(2000.0..19000.0 step 50.0).toDoubleArray(),
WALL_25_12_01
(2000.0..19000.0 step 50.0).toDoubleArray(), WALL_25_12_01
)
fun getWallByName(name: String): (u: Double) -> Double {

View File

@@ -0,0 +1,12 @@
{
"resources": {
"includes": [
{
"pattern": ".*\\.tsv$"
},
{
"pattern": ".*\\.json"
}
]
}
}