Stabilize integrals

This commit is contained in:
Alexander Nozik 2021-05-24 14:22:40 +03:00
parent 5e1a4c9477
commit 29d9bd6a72
3 changed files with 80 additions and 79 deletions

View File

@ -10,9 +10,7 @@ import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.UnivariateFunction import space.kscience.kmath.functions.UnivariateFunction
import space.kscience.kmath.functions.asFunction import space.kscience.kmath.functions.asFunction
import space.kscience.kmath.integration.GaussIntegrator import space.kscience.kmath.integration.*
import space.kscience.kmath.integration.integrate
import space.kscience.kmath.integration.value
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import kotlin.jvm.Synchronized import kotlin.jvm.Synchronized
import kotlin.math.* import kotlin.math.*
@ -251,7 +249,7 @@ public class NumassTransmission(
* @return * @return
*/ */
private fun getMargin(order: Int): Double { private fun getMargin(order: Int): Double {
return 80 + order * 50.0 return 50 + order * 50.0
} }
/** /**
@ -264,13 +262,12 @@ public class NumassTransmission(
@Synchronized @Synchronized
private fun getNextLoss(margin: Double, loss: UnivariateFunction<Double>): PiecewisePolynomial<Double> { private fun getNextLoss(margin: Double, loss: UnivariateFunction<Double>): PiecewisePolynomial<Double> {
val res = { x: Double -> val res = { x: Double ->
integrator.integrate(5.0..margin) { y -> DoubleField.simpsonIntegrator.integrate(5.0..margin, IntegrandMaxCalls(200)) { y ->
loss(x - y) * singleScatterFunction(y) loss(x - y) * singleScatterFunction(y)
}.value }.value
} }
return res.cache(0.0..margin, 200) return res.cache(0.0..margin, 100)
} }
/** /**
@ -316,7 +313,6 @@ public class NumassTransmission(
* порог по вероятности, до которого вычисляются компоненты функции потерь * порог по вероятности, до которого вычисляются компоненты функции потерь
*/ */
private const val SCATTERING_PROBABILITY_THRESHOLD = 1e-3 private const val SCATTERING_PROBABILITY_THRESHOLD = 1e-3
private val integrator = GaussIntegrator(DoubleField)
private val lossProbCache = HashMap<Double, List<Double>>(100) private val lossProbCache = HashMap<Double, List<Double>>(100)
@ -343,48 +339,48 @@ public class NumassTransmission(
} }
/** // /**
* A generic loss function for numass experiment in "Lobashev" // * A generic loss function for numass experiment in "Lobashev"
* parameterization // * parameterization
* // *
* @param exPos // * @param exPos
* @param ionPos // * @param ionPos
* @param exW // * @param exW
* @param ionW // * @param ionW
* @param exIonRatio // * @param exIonRatio
* @return // * @return
*/ // */
public fun getSingleScatterFunction( // public fun getSingleScatterFunction(
exPos: Double, // exPos: Double,
ionPos: Double, // ionPos: Double,
exW: Double, // exW: Double,
ionW: Double, // ionW: Double,
exIonRatio: Double, // exIonRatio: Double,
): UnivariateFunction<Double> { // ): UnivariateFunction<Double> {
val func: UnivariateFunction<Double> = { eps: Double -> // val func: UnivariateFunction<Double> = { eps: Double ->
if (eps <= 0) { // if (eps <= 0) {
0.0 // 0.0
} else { // } else {
val z1 = eps - exPos // val z1 = eps - exPos
val ex = exIonRatio * exp(-2.0 * z1 * z1 / exW / exW) // val ex = exIonRatio * exp(-2.0 * z1 * z1 / exW / exW)
//
val z = 4.0 * (eps - ionPos) * (eps - ionPos) // val z = 4.0 * (eps - ionPos) * (eps - ionPos)
val ion = 1 / (1 + z / ionW / ionW) // val ion = 1 / (1 + z / ionW / ionW)
//
if (eps < exPos) { // if (eps < exPos) {
ex // ex
} else { // } else {
max(ex, ion) // max(ex, ion)
} // }
} // }
} // }
//
val cutoff = 25.0 // val cutoff = 25.0
//caclulating lorentz integral analythically // //calculating lorentz integral analytically
val tailNorm = (atan((ionPos - cutoff) * 2.0 / ionW) + 0.5 * PI) * ionW / 2.0 // val tailNorm = (atan((ionPos - cutoff) * 2.0 / ionW) + 0.5 * PI) * ionW / 2.0
val norm: Double = integrator.integrate(range = 0.0..cutoff, function = func).value + tailNorm // val norm: Double = integrator.integrate(range = 0.0..cutoff, function = func).value + tailNorm
return { e -> func(e) / norm } // return { e -> func(e) / norm }
} // }
public val exPos: Symbol by symbol public val exPos: Symbol by symbol
@ -393,15 +389,15 @@ public class NumassTransmission(
public val ionW: Symbol by symbol public val ionW: Symbol by symbol
public val exIonRatio: Symbol by symbol public val exIonRatio: Symbol by symbol
public fun getSingleScatterFunction(set: Map<Symbol, Double>): UnivariateFunction<Double> { // public fun getSingleScatterFunction(set: Map<Symbol, Double>): UnivariateFunction<Double> {
val exPos = set.getValue(exPos) // val exPos = set.getValue(exPos)
val ionPos = set.getValue(ionPos) // val ionPos = set.getValue(ionPos)
val exW = set.getValue(exW) // val exW = set.getValue(exW)
val ionW = set.getValue(ionW) // val ionW = set.getValue(ionW)
val exIonRatio = set.getValue(exIonRatio) // val exIonRatio = set.getValue(exIonRatio)
//
return getSingleScatterFunction(exPos, ionPos, exW, ionW, exIonRatio) // return getSingleScatterFunction(exPos, ionPos, exW, ionW, exIonRatio)
} // }
public val trapFunction: (Double, Double) -> Double = { Ei: Double, Ef: Double -> public val trapFunction: (Double, Double) -> Double = { Ei: Double, Ef: Double ->
val eps = Ei - Ef val eps = Ei - Ef

View File

@ -137,7 +137,11 @@ public class SterileNeutrinoSpectrum(
arguments: Map<Symbol, Double>, arguments: Map<Symbol, Double>,
): Double = DoubleField.gaussIntegrator.integrate(u..eIn, generateRanges( ): Double = DoubleField.gaussIntegrator.integrate(u..eIn, generateRanges(
u..eIn, u..eIn,
*((u + 25)..(u + 6000) step 25.0).toDoubleArray() u + 2.0,
u + 7.0,
u + 15.0,
u + 30.0,
*((u + 50)..(u + 6000) step 30.0).toDoubleArray()
)) { eOut: Double -> )) { eOut: Double ->
transFunc(eIn, eOut, arguments) * resolution(eOut, u, arguments) transFunc(eIn, eOut, arguments) * resolution(eOut, u, arguments)
}.value }.value

View File

@ -35,34 +35,35 @@ fun main() {
) )
Plotly.page { 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 { val spectrumTime = measureTimeMillis {
plot { plot {
scatter { scatter {
name = "Computed spectrum" mode = ScatterMode.markers
mode = ScatterMode.lines javaClass.getResource("/old-spectrum.dat").readText().lines().map {
x.buffer = 14000.0..18600.0 step 10.0 val (u, w) = it.split("\t").map { it.toDouble() }
y.numbers = x.doubles.map { spectrum(it, args) } appendXY(u, w / spectrum(u, args) - 1.0)
}
} }
layout { layout {
title = "Sterile neutrino spectrum" title = "Sterile neutrino old/new ratio"
yaxis.type = AxisType.log
} }
} }
} }
println("Spectrum with 460 points computed in $spectrumTime millis") println("Spectrum with 460 points computed in $spectrumTime millis")
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"
}
}
plot { plot {
val resolution = NumassResolution() val resolution = NumassResolution()
scatter { scatter {