From 4b323fd14543ca7283ef75b0fa454c553e438039 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 13 Dec 2017 14:57:54 +0300 Subject: [PATCH] A lot of minor fixes. Moving some code to kotlin --- build.gradle | 8 +- .../java/inr/numass/data/NumassDataUtils.java | 105 ------- .../data/analyzers/AbstractAnalyzer.java | 100 ------- .../data/analyzers/DebunchAnalyzer.java | 25 -- .../numass/data/analyzers/SimpleAnalyzer.java | 43 --- .../numass/data/analyzers/SmartAnalyzer.java | 77 ----- .../numass/data/analyzers/TimeAnalyzer.java | 209 -------------- .../numass/data/analyzers/AbstractAnalyzer.kt | 104 +++++++ .../numass/data/analyzers/DebunchAnalyzer.kt | 33 +++ .../numass/data/analyzers/NumassAnalyzer.kt | 262 ++++++++++++++++++ .../numass/data/analyzers/SimpleAnalyzer.kt | 50 ++++ .../numass/data/analyzers/SmartAnalyzer.kt | 72 +++++ .../inr/numass/data/analyzers/TimeAnalyzer.kt | 231 +++++++++++++++ .../inr/numass/data/PointAnalyzer.groovy | 2 +- .../numass/scripts/temp/JoinSpectra.groovy | 2 +- .../numass/scripts/times/AnalyzePoint.groovy | 2 +- .../inr/numass/scripts/times/TestProto.groovy | 2 +- .../numass/scripts/underflow/Underflow.groovy | 4 +- .../scripts/underflow/UnderflowFitter.groovy | 14 +- .../scripts/underflow/UnderflowUtils.groovy | 2 +- .../numass/actions/MonitorCorrectAction.java | 5 +- .../inr/numass/utils/NMEventGenerator.java | 2 +- .../inr/numass/utils/UnderflowCorrection.java | 10 +- .../main/kotlin/inr/numass/NumassPlugin.kt | 2 +- .../src/main/kotlin/inr/numass/NumassUtils.kt | 2 +- .../inr/numass/actions/AnalyzeDataAction.kt | 2 +- .../inr/numass/actions/MergeDataAction.kt | 2 +- .../inr/numass/actions/TimeAnalyzerAction.kt | 4 +- .../inr/numass/actions/TimeSpectrumAction.kt | 4 +- .../inr/numass/actions/TransformDataAction.kt | 4 +- .../inr/numass/scripts/InversedChain.kt | 102 +++++++ .../kotlin/inr/numass/viewer/AmplitudeView.kt | 6 +- .../kotlin/inr/numass/viewer/SpectrumView.kt | 2 +- .../inr/numass/viewer/test/ComponentTest.kt | 4 +- 34 files changed, 898 insertions(+), 600 deletions(-) delete mode 100644 numass-core/src/main/java/inr/numass/data/analyzers/AbstractAnalyzer.java delete mode 100644 numass-core/src/main/java/inr/numass/data/analyzers/DebunchAnalyzer.java delete mode 100644 numass-core/src/main/java/inr/numass/data/analyzers/SimpleAnalyzer.java delete mode 100644 numass-core/src/main/java/inr/numass/data/analyzers/SmartAnalyzer.java delete mode 100644 numass-core/src/main/java/inr/numass/data/analyzers/TimeAnalyzer.java create mode 100644 numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/analyzers/DebunchAnalyzer.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/analyzers/SimpleAnalyzer.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/analyzers/SmartAnalyzer.kt create mode 100644 numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt create mode 100644 numass-main/src/main/kotlin/inr/numass/scripts/InversedChain.kt diff --git a/build.gradle b/build.gradle index 58a92d85..115d5547 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ plugins { allprojects{ apply plugin: 'idea' apply plugin: 'java' + apply plugin: "kotlin" group = 'inr.numass' version = '1.0.0' @@ -19,7 +20,12 @@ allprojects{ maven { url "https://dl.bintray.com/kotlin/kotlinx" } } - apply plugin: "kotlin" + dependencies{ + compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0" + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.0" + } + + compileKotlin { kotlinOptions { diff --git a/numass-core/src/main/java/inr/numass/data/NumassDataUtils.java b/numass-core/src/main/java/inr/numass/data/NumassDataUtils.java index aa895bba..167b8273 100644 --- a/numass-core/src/main/java/inr/numass/data/NumassDataUtils.java +++ b/numass-core/src/main/java/inr/numass/data/NumassDataUtils.java @@ -2,12 +2,6 @@ package inr.numass.data; import hep.dataforge.meta.Meta; import hep.dataforge.meta.MetaBuilder; -import hep.dataforge.tables.ListTable; -import hep.dataforge.tables.Table; -import hep.dataforge.tables.TableFormat; -import hep.dataforge.tables.TableFormatBuilder; -import hep.dataforge.values.Value; -import hep.dataforge.values.Values; import inr.numass.data.api.NumassPoint; import inr.numass.data.api.NumassSet; import inr.numass.data.api.SimpleNumassPoint; @@ -16,14 +10,9 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; -import static hep.dataforge.tables.Adapters.*; -import static inr.numass.data.api.NumassAnalyzer.*; - /** * Created by darksnake on 30-Jan-17. */ @@ -52,100 +41,6 @@ public class NumassDataUtils { }; } - /** - * Subtract reference spectrum. - * - * @param sp1 - * @param sp2 - * @return - */ - public static Table subtractSpectrum(Table sp1, Table sp2) { - TableFormat format = new TableFormatBuilder() - .addNumber(CHANNEL_KEY, X_VALUE_KEY) - .addNumber(COUNT_RATE_KEY, Y_VALUE_KEY) - .addNumber(COUNT_RATE_ERROR_KEY, Y_ERROR_KEY) - .build(); - - //indexing table elements - Map t1 = sp1.getRows().collect(Collectors.toMap(row -> row.getDouble(CHANNEL_KEY), row -> row)); - Map t2 = sp2.getRows().collect(Collectors.toMap(row -> row.getDouble(CHANNEL_KEY), row -> row)); - - ListTable.Builder builder = new ListTable.Builder(format); - - t1.forEach((channel, row1) -> { - Values row2 = t2.get(channel); - if (row2 == null) { - builder.row(row1); - } else { - double value = Math.max(row1.getDouble(COUNT_RATE_KEY) - row2.getDouble(COUNT_RATE_KEY), 0); - double error1 = row1.getDouble(COUNT_RATE_ERROR_KEY); - double error2 = row2.getDouble(COUNT_RATE_ERROR_KEY); - double error = Math.sqrt(error1 * error1 + error2 * error2); - builder.row(channel, value, error); - } - }); - return builder.build(); - } - - /** - * Apply window and binning to a spectrum. Empty bins are filled with zeroes - * - * @param binSize - * @param loChannel autodefined if negative - * @param upChannel autodefined if negative - * @return - */ - public static Table spectrumWithBinning(Table spectrum, int binSize, int loChannel, int upChannel) { - TableFormat format = new TableFormatBuilder() - .addNumber(CHANNEL_KEY, X_VALUE_KEY) - .addNumber(COUNT_KEY, Y_VALUE_KEY) - .addNumber(COUNT_RATE_KEY) - .addNumber(COUNT_RATE_ERROR_KEY) - .addNumber("binSize"); - ListTable.Builder builder = new ListTable.Builder(format); - - if (loChannel < 0) { - loChannel = spectrum.getColumn(CHANNEL_KEY).stream().mapToInt(Value::intValue).min().orElse(0); - } - - if (upChannel < 0) { - upChannel = spectrum.getColumn(CHANNEL_KEY).stream().mapToInt(Value::intValue).max().orElse(1); - } - - - for (int chan = loChannel; chan < upChannel - binSize; chan += binSize) { - AtomicLong count = new AtomicLong(0); - AtomicReference countRate = new AtomicReference<>(0d); - AtomicReference countRateDispersion = new AtomicReference<>(0d); - - int binLo = chan; - int binUp = chan + binSize; - - spectrum.getRows().filter(row -> { - int c = row.getInt(CHANNEL_KEY); - return c >= binLo && c < binUp; - }).forEach(row -> { - count.addAndGet(row.getValue(COUNT_KEY, 0).longValue()); - countRate.accumulateAndGet(row.getDouble(COUNT_RATE_KEY, 0), (d1, d2) -> d1 + d2); - countRateDispersion.accumulateAndGet(Math.pow(row.getDouble(COUNT_RATE_ERROR_KEY, 0),2), (d1, d2) -> d1 + d2); - }); - int bin = Math.min(binSize, upChannel - chan); - builder.row((double) chan + (double) bin / 2d, count.get(), countRate.get(), Math.sqrt(countRateDispersion.get()), bin); - } - return builder.build(); - } - - /** - * The same as above, but with auto definition for borders - * - * @param spectrum - * @param binSize - * @return - */ - public static Table spectrumWithBinning(Table spectrum, int binSize) { - return spectrumWithBinning(spectrum, binSize, -1, -1); - } - @NotNull public static SpectrumAdapter adapter() { return new SpectrumAdapter("Uset", "CR", "CRerr", "Time"); diff --git a/numass-core/src/main/java/inr/numass/data/analyzers/AbstractAnalyzer.java b/numass-core/src/main/java/inr/numass/data/analyzers/AbstractAnalyzer.java deleted file mode 100644 index 7f8ee9d4..00000000 --- a/numass-core/src/main/java/inr/numass/data/analyzers/AbstractAnalyzer.java +++ /dev/null @@ -1,100 +0,0 @@ -package inr.numass.data.analyzers; - -import hep.dataforge.meta.Meta; -import hep.dataforge.tables.ListTable; -import hep.dataforge.tables.Table; -import hep.dataforge.tables.TableFormat; -import hep.dataforge.tables.TableFormatBuilder; -import inr.numass.data.api.*; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.stream.Stream; - -import static hep.dataforge.tables.Adapters.*; -import static inr.numass.data.api.NumassPoint.HV_KEY; - -/** - * Created by darksnake on 11.07.2017. - */ -public abstract class AbstractAnalyzer implements NumassAnalyzer { - public static final String WINDOW_KEY = "window"; - public static final String TIME_KEY = "timestamp"; - - public static final String[] NAME_LIST = {LENGTH_KEY, COUNT_KEY, COUNT_RATE_KEY, COUNT_RATE_ERROR_KEY, WINDOW_KEY, TIME_KEY}; -// public static String[] NAME_LIST_WITH_HV = {HV_KEY, LENGTH_KEY, COUNT_KEY, COUNT_RATE_KEY, COUNT_RATE_ERROR_KEY, WINDOW_KEY, TIME_KEY}; - @Nullable - private final SignalProcessor processor; - - public AbstractAnalyzer(@Nullable SignalProcessor processor) { - this.processor = processor; - } - - public AbstractAnalyzer() { - this.processor = null; - } - - /** - * Return unsorted stream of events including events from frames. - * In theory, events after processing could be unsorted due to mixture of frames and events. - * In practice usually block have either frame or events, but not both. - * - * @param block - * @return - */ - public Stream getEvents(NumassBlock block, Meta config) { - int loChannel = config.getInt("window.lo", 0); - int upChannel = config.getInt("window.up", Integer.MAX_VALUE); - Stream res = getAllEvents(block).filter(event -> { - short channel = event.getChanel(); - return channel >= loChannel && channel < upChannel; - }); - if (config.getBoolean("sort", false)) { - res = res.sorted(Comparator.comparing(NumassEvent::getTimeOffset)); - } - return res; - } - - protected Stream getAllEvents(NumassBlock block) { - if (block.getFrames().count() == 0) { - return block.getEvents(); - } else if (getProcessor() == null) { - throw new IllegalArgumentException("Signal processor needed to analyze frames"); - } else { - return Stream.concat(block.getEvents(), block.getFrames().flatMap(getProcessor()::analyze)); - } - } - - /** - * Get table format for summary table - * - * @param config - * @return - */ - protected TableFormat getTableFormat(Meta config) { - return new TableFormatBuilder() - .addNumber(HV_KEY, X_VALUE_KEY) - .addNumber(LENGTH_KEY) - .addNumber(COUNT_KEY) - .addNumber(COUNT_RATE_KEY, Y_VALUE_KEY) - .addNumber(COUNT_RATE_ERROR_KEY, Y_ERROR_KEY) - .addColumn(WINDOW_KEY) - .addTime() - .build(); - } - - - @Override - public Table analyzeSet(NumassSet set, Meta config) { - TableFormat format = getTableFormat(config); - - return new ListTable.Builder(format) - .rows(set.getPoints().map(point -> analyzePoint(point, config))) - .build(); - } - - @Nullable - public SignalProcessor getProcessor() { - return processor; - } -} diff --git a/numass-core/src/main/java/inr/numass/data/analyzers/DebunchAnalyzer.java b/numass-core/src/main/java/inr/numass/data/analyzers/DebunchAnalyzer.java deleted file mode 100644 index 4b06a456..00000000 --- a/numass-core/src/main/java/inr/numass/data/analyzers/DebunchAnalyzer.java +++ /dev/null @@ -1,25 +0,0 @@ -package inr.numass.data.analyzers; - -import hep.dataforge.meta.Meta; -import hep.dataforge.values.Values; -import inr.numass.data.api.NumassBlock; -import inr.numass.data.api.SignalProcessor; -import org.jetbrains.annotations.Nullable; - -/** - * Block analyzer that can perform debunching - * Created by darksnake on 11.07.2017. - */ -public class DebunchAnalyzer extends AbstractAnalyzer { - public DebunchAnalyzer(@Nullable SignalProcessor processor) { - super(processor); - } - - public DebunchAnalyzer() { - } - - @Override - public Values analyze(NumassBlock block, Meta config) { - throw new UnsupportedOperationException("TODO"); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/analyzers/SimpleAnalyzer.java b/numass-core/src/main/java/inr/numass/data/analyzers/SimpleAnalyzer.java deleted file mode 100644 index 9713d0b2..00000000 --- a/numass-core/src/main/java/inr/numass/data/analyzers/SimpleAnalyzer.java +++ /dev/null @@ -1,43 +0,0 @@ -package inr.numass.data.analyzers; - -import hep.dataforge.meta.Meta; -import hep.dataforge.tables.ValueMap; -import hep.dataforge.values.Values; -import inr.numass.data.api.NumassBlock; -import inr.numass.data.api.SignalProcessor; -import org.jetbrains.annotations.Nullable; - -/** - * A simple event counter - * Created by darksnake on 07.07.2017. - */ -public class SimpleAnalyzer extends AbstractAnalyzer { - - public SimpleAnalyzer(@Nullable SignalProcessor processor) { - super(processor); - } - - public SimpleAnalyzer() { - } - - - @Override - public Values analyze(NumassBlock block, Meta config) { - int loChannel = config.getInt("window.lo", 0); - int upChannel = config.getInt("window.up", Integer.MAX_VALUE); - long count = getEvents(block, config).count(); - double length = (double) block.getLength().toNanos() / 1e9; - double countRate = (double) count / length; - double countRateError = Math.sqrt((double) count) / length; - - return ValueMap.of(NAME_LIST, - length, - count, - countRate, - countRateError, - new Integer[]{loChannel, upChannel}, - block.getStartTime()); - } - - -} diff --git a/numass-core/src/main/java/inr/numass/data/analyzers/SmartAnalyzer.java b/numass-core/src/main/java/inr/numass/data/analyzers/SmartAnalyzer.java deleted file mode 100644 index 9bb45939..00000000 --- a/numass-core/src/main/java/inr/numass/data/analyzers/SmartAnalyzer.java +++ /dev/null @@ -1,77 +0,0 @@ -package inr.numass.data.analyzers; - -import hep.dataforge.meta.Meta; -import hep.dataforge.tables.TableFormat; -import hep.dataforge.tables.ValueMap; -import hep.dataforge.values.Value; -import hep.dataforge.values.Values; -import inr.numass.data.api.NumassAnalyzer; -import inr.numass.data.api.NumassBlock; -import inr.numass.data.api.NumassEvent; -import inr.numass.data.api.SignalProcessor; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; -import java.util.stream.Stream; - -/** - * An analyzer dispatcher which uses different analyzer for different meta - * Created by darksnake on 11.07.2017. - */ -public class SmartAnalyzer extends AbstractAnalyzer { - private SimpleAnalyzer simpleAnalyzer = new SimpleAnalyzer(); - private DebunchAnalyzer debunchAnalyzer = new DebunchAnalyzer(); - private TimeAnalyzer timeAnalyzer = new TimeAnalyzer(); - - public SmartAnalyzer(@Nullable SignalProcessor processor) { - super(processor); - this.simpleAnalyzer = new SimpleAnalyzer(processor); - this.debunchAnalyzer = new DebunchAnalyzer(processor); - this.timeAnalyzer = new TimeAnalyzer(processor); - } - - public SmartAnalyzer() { - } - - private NumassAnalyzer getAnalyzer(Meta config){ - if (config.hasValue("type")) { - switch (config.getString("type")) { - case "simple": - return simpleAnalyzer; - case "time": - return timeAnalyzer; - case "debunch": - return debunchAnalyzer; - default: - throw new IllegalArgumentException("Analyzer not found"); - } - } else { - if(config.hasValue("t0")||config.hasMeta("t0")){ - return timeAnalyzer; - } else { - return simpleAnalyzer; - } - } - } - - @Override - public Values analyze(NumassBlock block, Meta config) { - NumassAnalyzer analyzer = getAnalyzer(config); - Map map = analyzer.analyze(block, config).asMap(); - map.putIfAbsent(TimeAnalyzer.T0_KEY, Value.of(0d)); - return new ValueMap(map); - } - - @Override - public Stream getEvents(NumassBlock block, Meta config) { - return getAnalyzer(config).getEvents(block, config); - } - - @Override - protected TableFormat getTableFormat(Meta config) { - if (config.hasValue(TimeAnalyzer.T0_KEY) || config.hasMeta(TimeAnalyzer.T0_KEY)) { - return timeAnalyzer.getTableFormat(config); - } - return super.getTableFormat(config); - } -} diff --git a/numass-core/src/main/java/inr/numass/data/analyzers/TimeAnalyzer.java b/numass-core/src/main/java/inr/numass/data/analyzers/TimeAnalyzer.java deleted file mode 100644 index 9f062e59..00000000 --- a/numass-core/src/main/java/inr/numass/data/analyzers/TimeAnalyzer.java +++ /dev/null @@ -1,209 +0,0 @@ -package inr.numass.data.analyzers; - -import hep.dataforge.description.ValueDef; -import hep.dataforge.meta.Meta; -import hep.dataforge.tables.TableFormat; -import hep.dataforge.tables.TableFormatBuilder; -import hep.dataforge.tables.ValueMap; -import hep.dataforge.values.Value; -import hep.dataforge.values.ValueType; -import hep.dataforge.values.Values; -import inr.numass.data.api.NumassBlock; -import inr.numass.data.api.NumassEvent; -import inr.numass.data.api.NumassPoint; -import inr.numass.data.api.SignalProcessor; -import javafx.util.Pair; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Stream; - -import static hep.dataforge.tables.Adapters.*; -import static inr.numass.data.api.NumassPoint.HV_KEY; - -/** - * An analyzer which uses time information from events - * Created by darksnake on 11.07.2017. - */ -public class TimeAnalyzer extends AbstractAnalyzer { - public static String T0_KEY = "t0"; - - public static final String[] NAME_LIST = {LENGTH_KEY, COUNT_KEY, COUNT_RATE_KEY, COUNT_RATE_ERROR_KEY, WINDOW_KEY, TIME_KEY, T0_KEY}; -// public static String[] NAME_LIST_WITH_HV = {HV_KEY, LENGTH_KEY, COUNT_KEY, COUNT_RATE_KEY, COUNT_RATE_ERROR_KEY, WINDOW_KEY, TIME_KEY, T0_KEY}; - - public TimeAnalyzer(@Nullable SignalProcessor processor) { - super(processor); - } - - public TimeAnalyzer() { - } - - @Override - public Values analyze(NumassBlock block, Meta config) { - //In case points inside points - if (block instanceof NumassPoint) { - return analyzePoint((NumassPoint) block, config); - } - - - int loChannel = config.getInt("window.lo", 0); - int upChannel = config.getInt("window.up", Integer.MAX_VALUE); - long t0 = getT0(block, config); - - AtomicLong totalN = new AtomicLong(0); - AtomicLong totalT = new AtomicLong(0); - - getEventsWithDelay(block, config) - .filter(pair -> pair.getValue() >= t0) - .forEach(pair -> { - totalN.incrementAndGet(); - //TODO add progress listener here - totalT.addAndGet(pair.getValue()); - }); - - double countRate = 1e6 * totalN.get() / (totalT.get() / 1000 - t0 * totalN.get() / 1000);//1e9 / (totalT.get() / totalN.get() - t0); - double countRateError = countRate / Math.sqrt(totalN.get()); - double length = totalT.get() / 1e9; - long count = (long) (length * countRate); - - return ValueMap.of(NAME_LIST, - length, - count, - countRate, - countRateError, - new Integer[]{loChannel, upChannel}, - block.getStartTime(), - (double) t0 / 1000d - ); - } - - @Override - public Values analyzePoint(NumassPoint point, Meta config) { - //Average count rates, do not sum events - Values res = point.getBlocks() - .map(it -> analyze(it, config)) - .reduce(null, this::combineBlockResults); - - Map map = new HashMap<>(res.asMap()); - map.put(HV_KEY, Value.of(point.getVoltage())); - return new ValueMap(map); - } - - /** - * Combine two blocks from the same point into one - * - * @param v1 - * @param v2 - * @return - */ - private Values combineBlockResults(Values v1, Values v2) { - if (v1 == null) { - return v2; - } - if (v2 == null) { - return v1; - } - - - double t1 = v1.getDouble(LENGTH_KEY); - double t2 = v2.getDouble(LENGTH_KEY); - double cr1 = v1.getDouble(COUNT_RATE_KEY); - double cr2 = v2.getDouble(COUNT_RATE_KEY); - double err1 = v1.getDouble(COUNT_RATE_ERROR_KEY); - double err2 = v2.getDouble(COUNT_RATE_ERROR_KEY); - - double countRate = (t1 * cr1 + t2 * cr2) / (t1 + t2); - - double countRateErr = Math.sqrt(Math.pow(t1 * err1 / (t1 + t2), 2) + Math.pow(t2 * err2 / (t1 + t2), 2)); - - - return ValueMap.of(NAME_LIST, - v1.getDouble(LENGTH_KEY) + v2.getDouble(LENGTH_KEY), - v1.getInt(COUNT_KEY) + v2.getInt(COUNT_KEY), - countRate, - countRateErr, - v1.getValue(WINDOW_KEY), - v1.getValue(TIME_KEY), - v1.getDouble(T0_KEY) - ); - } - - @ValueDef(name = "t0", type = ValueType.NUMBER, info = "Constant t0 cut") - @ValueDef(name = "t0.crFraction", type = ValueType.NUMBER, info = "The relative fraction of events that should be removed by time cut") - @ValueDef(name = "t0.min", type = ValueType.NUMBER, def = "0", info = "Minimal t0") - private int getT0(NumassBlock block, Meta meta) { - if (meta.hasValue("t0")) { - return meta.getInt("t0"); - } else if (meta.hasMeta("t0")) { - double fraction = meta.getDouble("t0.crFraction"); - double cr = estimateCountRate(block); - if (cr < meta.getDouble("t0.minCR", 0)) { - return 0; - } else { - return (int) Math.max(-1e9 / cr * Math.log(1d - fraction), meta.getDouble("t0.min", 0)); - } - } else { - return 0; - } - - } - - private double estimateCountRate(NumassBlock block) { - return (double) block.getEvents().count() / block.getLength().toMillis() * 1000; - } - - /** - * The chain of event times in nanos - * - * @param block - * @param config - * @return - */ - public Stream> getEventsWithDelay(NumassBlock block, Meta config) { - AtomicReference lastEvent = new AtomicReference<>(null); - - Stream eventStream = super.getEvents(block, config);//using super implementation - - return eventStream.map(event -> { - long res = lastEvent.get() == null ? 0L : event.getTimeOffset() - lastEvent.get().getTimeOffset(); - - if (res < 0) { - res = 0L; - } - - lastEvent.set(event); - //TODO remove autoboxing somehow - return new Pair<>(event, res); - }); - } - - /** - * The filtered stream of events - * - * @param block - * @param config - * @return - */ - @Override - public Stream getEvents(NumassBlock block, Meta config) { - long t0 = getT0(block, config); - return getEventsWithDelay(block, config).filter(pair -> pair.getValue() >= t0).map(Pair::getKey); - } - - @Override - protected TableFormat getTableFormat(Meta config) { - return new TableFormatBuilder() - .addNumber(HV_KEY, X_VALUE_KEY) - .addNumber(LENGTH_KEY) - .addNumber(COUNT_KEY) - .addNumber(COUNT_RATE_KEY, Y_VALUE_KEY) - .addNumber(COUNT_RATE_ERROR_KEY, Y_ERROR_KEY) - .addColumn(WINDOW_KEY) - .addTime() - .addNumber(T0_KEY) - .build(); - } -} diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt new file mode 100644 index 00000000..b5e71c84 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/AbstractAnalyzer.kt @@ -0,0 +1,104 @@ +/* + * 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 inr.numass.data.analyzers + +import hep.dataforge.meta.Meta +import hep.dataforge.tables.Adapters.* +import hep.dataforge.tables.ListTable +import hep.dataforge.tables.Table +import hep.dataforge.tables.TableFormat +import hep.dataforge.tables.TableFormatBuilder +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.NumassEvent +import inr.numass.data.api.NumassPoint.HV_KEY +import inr.numass.data.api.NumassSet +import inr.numass.data.api.SignalProcessor +import java.lang.IllegalArgumentException +import java.util.* +import java.util.stream.Stream + +/** + * Created by darksnake on 11.07.2017. + */ +abstract class AbstractAnalyzer @JvmOverloads constructor(private val processor: SignalProcessor? = null) : NumassAnalyzer { + + /** + * Return unsorted stream of events including events from frames. + * In theory, events after processing could be unsorted due to mixture of frames and events. + * In practice usually block have either frame or events, but not both. + * + * @param block + * @return + */ + override fun getEvents(block: NumassBlock, meta: Meta): Stream { + val loChannel = meta.getInt("window.lo", 0) + val upChannel = meta.getInt("window.up", Integer.MAX_VALUE) + var res = getAllEvents(block).filter { event -> + event.chanel.toInt() in loChannel..(upChannel - 1) + } + if (meta.getBoolean("sort", false)) { + res = res.sorted(Comparator.comparing { it.timeOffset }) + } + return res + } + + protected fun getAllEvents(block: NumassBlock): Stream { + return when { + block.frames.count() == 0L -> block.events + processor == null -> throw IllegalArgumentException("Signal processor needed to analyze frames") + else -> Stream.concat(block.events, block.frames.flatMap { processor.analyze(it) }) + } + } + + /** + * Get table format for summary table + * + * @param config + * @return + */ + protected open fun getTableFormat(config: Meta): TableFormat { + return TableFormatBuilder() + .addNumber(HV_KEY, X_VALUE_KEY) + .addNumber(NumassAnalyzer.LENGTH_KEY) + .addNumber(NumassAnalyzer.COUNT_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_KEY, Y_VALUE_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_ERROR_KEY, Y_ERROR_KEY) + .addColumn(NumassAnalyzer.WINDOW_KEY) + .addTime() + .build() + } + + + override fun analyzeSet(set: NumassSet, config: Meta): Table { + val format = getTableFormat(config) + + return ListTable.Builder(format) + .rows(set.points.map { point -> analyzePoint(point, config) }) + .build() + } + + companion object { + val NAME_LIST = arrayOf( + NumassAnalyzer.LENGTH_KEY, + NumassAnalyzer.COUNT_KEY, + NumassAnalyzer.COUNT_RATE_KEY, + NumassAnalyzer.COUNT_RATE_ERROR_KEY, + NumassAnalyzer.WINDOW_KEY, + NumassAnalyzer.TIME_KEY + ) + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/DebunchAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/DebunchAnalyzer.kt new file mode 100644 index 00000000..6d852025 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/DebunchAnalyzer.kt @@ -0,0 +1,33 @@ +/* + * 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 inr.numass.data.analyzers + +import hep.dataforge.meta.Meta +import hep.dataforge.values.Values +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.SignalProcessor + +/** + * Block analyzer that can perform debunching + * Created by darksnake on 11.07.2017. + */ +class DebunchAnalyzer @JvmOverloads constructor(private val processor: SignalProcessor? = null) : AbstractAnalyzer(processor) { + + override fun analyze(block: NumassBlock, config: Meta): Values { + TODO() + } +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt new file mode 100644 index 00000000..c9555401 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/NumassAnalyzer.kt @@ -0,0 +1,262 @@ +/* + * 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 inr.numass.data.analyzers + +import hep.dataforge.meta.Meta +import hep.dataforge.tables.* +import hep.dataforge.tables.Adapters.* +import hep.dataforge.values.Value +import hep.dataforge.values.Values +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.NumassEvent +import inr.numass.data.api.NumassPoint +import inr.numass.data.api.NumassPoint.HV_KEY +import inr.numass.data.api.NumassSet +import java.util.* +import java.util.concurrent.atomic.AtomicLong +import java.util.concurrent.atomic.AtomicReference +import java.util.stream.IntStream +import java.util.stream.Stream +import kotlin.streams.asSequence + +/** + * A general raw data analysis utility. Could have different implementations + * Created by darksnake on 06-Jul-17. + */ +interface NumassAnalyzer { + + /** + * 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 + */ + fun analyze(block: NumassBlock, config: Meta = Meta.empty()): Values + + /** + * Analysis result for point including hv information + * @param point + * @param config + * @return + */ + fun analyzePoint(point: NumassPoint, config: Meta = Meta.empty()): Values { + val map = HashMap(analyze(point, config).asMap()) + map.put(HV_KEY, Value.of(point.voltage)) + return ValueMap(map) + } + + /** + * Return unsorted stream of events including events from frames + * + * @param block + * @return + */ + fun getEvents(block: NumassBlock, meta: Meta = Meta.empty()): Stream + + /** + * Analyze the whole set. And return results as a table + * + * @param set + * @param config + * @return + */ + fun analyzeSet(set: NumassSet, config: Meta): Table + + /** + * Get the approximate number of events in block. Not all analyzers support precise event counting + * + * @param block + * @param config + * @return + */ + fun getCount(block: NumassBlock, config: Meta): Long { + return analyze(block, config).getValue(COUNT_KEY).numberValue().toLong() + } + + /** + * Get approximate effective point length in nanos. It is not necessary corresponds to real point length. + * + * @param block + * @param config + * @return + */ + fun getLength(block: NumassBlock, config: Meta): Long { + return analyze(block, config).getValue(LENGTH_KEY).numberValue().toLong() + } + + fun getSpectrum(block: NumassBlock, config: Meta): Table { + val seconds = block.length.toMillis().toDouble() / 1000.0 + return getSpectrum(seconds, getEvents(block, config).asSequence(), config) + } + + companion object { + const val CHANNEL_KEY = "channel" + const val COUNT_KEY = "count" + const val LENGTH_KEY = "length" + const val COUNT_RATE_KEY = "cr" + const val COUNT_RATE_ERROR_KEY = "crErr" + + const val WINDOW_KEY = "window" + const val TIME_KEY = "timestamp" + + val DEFAULT_ANALYZER: NumassAnalyzer = SmartAnalyzer() + + val ADAPTER: ValuesAdapter = Adapters.buildXYAdapter(CHANNEL_KEY, COUNT_RATE_KEY) + +// val MAX_CHANNEL = 10000 + + fun Table.withBinning(binSize: Int, loChannel: Int? = null, upChannel: Int? = null): Table { + return spectrumWithBinning(this,binSize, loChannel, upChannel) + } + + /** + * Subtract reference spectrum. + * + * @param sp1 + * @param sp2 + * @return + */ + fun subtractSpectrum(sp1: Table, sp2: Table): Table { + val format = TableFormatBuilder() + .addNumber(CHANNEL_KEY, X_VALUE_KEY) + .addNumber(COUNT_RATE_KEY, Y_VALUE_KEY) + .addNumber(COUNT_RATE_ERROR_KEY, Y_ERROR_KEY) + .build() + + val builder = ListTable.Builder(format) + + sp1.forEach { row1 -> + val channel = row1.getDouble(CHANNEL_KEY) + val row2 = sp2.rows.asSequence().find { it.getDouble(CHANNEL_KEY) == channel } //t2[channel] + if (row2 == null) { + builder.row(row1) + } else { + val value = Math.max(row1.getDouble(COUNT_RATE_KEY) - row2.getDouble(COUNT_RATE_KEY), 0.0) + val error1 = row1.getDouble(COUNT_RATE_ERROR_KEY) + val error2 = row2.getDouble(COUNT_RATE_ERROR_KEY) + val error = Math.sqrt(error1 * error1 + error2 * error2) + builder.row(channel, value, error) + } + } + return builder.build() + } + + } +} + +/** + * Calculate number of counts in the given channel + * + * @param spectrum + * @param loChannel + * @param upChannel + * @return + */ +fun countInWindow(spectrum: Table, loChannel: Short, upChannel: Short): Long { + return spectrum.rows.filter { row -> + row.getInt(NumassAnalyzer.CHANNEL_KEY) in loChannel..(upChannel - 1) + }.mapToLong { it -> it.getValue(NumassAnalyzer.COUNT_KEY).numberValue().toLong() }.sum() +} + +/** + * Calculate the amplitude spectrum for a given block. The s + * + * @param block + * @param config + * @return + */ +fun getSpectrum(length: Double, events: Sequence, config: Meta = Meta.empty()): Table { + val format = TableFormatBuilder() + .addNumber(NumassAnalyzer.CHANNEL_KEY, X_VALUE_KEY) + .addNumber(NumassAnalyzer.COUNT_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_KEY, Y_VALUE_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_ERROR_KEY, Y_ERROR_KEY) + .updateMeta { metaBuilder -> metaBuilder.setNode("config", config) } + .build() + + //optimized for fastest computation + val spectrum: MutableMap = HashMap() + events.forEach { event -> + val channel = event.chanel.toInt() + spectrum.getOrPut(channel) { + AtomicLong(0) + }.incrementAndGet() + } + + + val minChannel = config.getInt("window.lo") { spectrum.keys.min() } + val maxChannel = config.getInt("window.up") { spectrum.keys.max() } + + return ListTable.Builder(format) + .rows(IntStream.range(minChannel, maxChannel) + .mapToObj { i -> + val value = spectrum[i]?.get() ?: 0 + ValueMap.of( + format.namesAsArray(), + i, + value, + value.toDouble() / length, + Math.sqrt(value.toDouble()) / length + ) + } + ).build() +} + +/** + * Apply window and binning to a spectrum. Empty bins are filled with zeroes + * + * @param binSize + * @param loChannel autodefined if negative + * @param upChannel autodefined if negative + * @return + */ +@JvmOverloads +fun spectrumWithBinning(spectrum: Table, binSize: Int, loChannel: Int? = null, upChannel: Int? = null): Table { + val format = TableFormatBuilder() + .addNumber(NumassAnalyzer.CHANNEL_KEY, X_VALUE_KEY) + .addNumber(NumassAnalyzer.COUNT_KEY, Y_VALUE_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_ERROR_KEY) + .addNumber("binSize") + val builder = ListTable.Builder(format) + + var chan = loChannel ?: spectrum.getColumn(NumassAnalyzer.CHANNEL_KEY).stream().mapToInt { it.intValue() }.min().orElse(0) + + val top = upChannel ?: spectrum.getColumn(NumassAnalyzer.CHANNEL_KEY).stream().mapToInt { it.intValue() }.max().orElse(1) + + while (chan < top - binSize) { + val count = AtomicLong(0) + val countRate = AtomicReference(0.0) + val countRateDispersion = AtomicReference(0.0) + + val binLo = chan + val binUp = chan + binSize + + spectrum.rows.filter { row -> + row.getInt(NumassAnalyzer.CHANNEL_KEY) in binLo..(binUp - 1) + }.forEach { row -> + count.addAndGet(row.getValue(NumassAnalyzer.COUNT_KEY, 0).longValue()) + countRate.accumulateAndGet(row.getDouble(NumassAnalyzer.COUNT_RATE_KEY, 0.0)) { d1, d2 -> d1 + d2 } + countRateDispersion.accumulateAndGet(Math.pow(row.getDouble(NumassAnalyzer.COUNT_RATE_ERROR_KEY, 0.0), 2.0)) { d1, d2 -> d1 + d2 } + } + val bin = Math.min(binSize, top - chan) + builder.row(chan.toDouble() + bin.toDouble() / 2.0, count.get(), countRate.get(), Math.sqrt(countRateDispersion.get()), bin) + chan += binSize + } + return builder.build() +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/SimpleAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/SimpleAnalyzer.kt new file mode 100644 index 00000000..a8cfad59 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/SimpleAnalyzer.kt @@ -0,0 +1,50 @@ +/* + * 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 inr.numass.data.analyzers + +import hep.dataforge.meta.Meta +import hep.dataforge.tables.ValueMap +import hep.dataforge.values.Values +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.SignalProcessor + +/** + * A simple event counter + * Created by darksnake on 07.07.2017. + */ +class SimpleAnalyzer @JvmOverloads constructor(private val processor: SignalProcessor? = null) : AbstractAnalyzer(processor) { + + + override fun analyze(block: NumassBlock, config: Meta): Values { + val loChannel = config.getInt("window.lo", 0) + val upChannel = config.getInt("window.up", Integer.MAX_VALUE) + val count = getEvents(block, config).count() + val length = block.length.toNanos().toDouble() / 1e9 + val countRate = count.toDouble() / length + val countRateError = Math.sqrt(count.toDouble()) / length + + return ValueMap.of(AbstractAnalyzer.NAME_LIST, + length, + count, + countRate, + countRateError, + arrayOf(loChannel, upChannel), + block.startTime) + } + + +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/SmartAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/SmartAnalyzer.kt new file mode 100644 index 00000000..1a4969c1 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/SmartAnalyzer.kt @@ -0,0 +1,72 @@ +/* + * 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 inr.numass.data.analyzers + +import hep.dataforge.meta.Meta +import hep.dataforge.tables.TableFormat +import hep.dataforge.tables.ValueMap +import hep.dataforge.values.Value +import hep.dataforge.values.Values +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.NumassEvent +import inr.numass.data.api.SignalProcessor +import java.util.stream.Stream + +/** + * An analyzer dispatcher which uses different analyzer for different meta + * Created by darksnake on 11.07.2017. + */ +class SmartAnalyzer(processor: SignalProcessor? = null) : AbstractAnalyzer(processor) { + private val simpleAnalyzer = SimpleAnalyzer(processor) + private val debunchAnalyzer = DebunchAnalyzer(processor) + private val timeAnalyzer = TimeAnalyzer(processor) + + private fun getAnalyzer(config: Meta): NumassAnalyzer { + return if (config.hasValue("type")) { + when (config.getString("type")) { + "simple" -> simpleAnalyzer + "time" -> timeAnalyzer + "debunch" -> debunchAnalyzer + else -> throw IllegalArgumentException("Analyzer not found") + } + } else { + if (config.hasValue("t0") || config.hasMeta("t0")) { + timeAnalyzer + } else { + simpleAnalyzer + } + } + } + + override fun analyze(block: NumassBlock, config: Meta): Values { + val analyzer = getAnalyzer(config) + val map = analyzer.analyze(block, config).asMap() + map.putIfAbsent(TimeAnalyzer.T0_KEY, Value.of(0.0)) + return ValueMap(map) + } + + override fun getEvents(block: NumassBlock, config: Meta): Stream { + return getAnalyzer(config).getEvents(block, config) + } + + override fun getTableFormat(config: Meta): TableFormat { + return if (config.hasValue(TimeAnalyzer.T0_KEY) || config.hasMeta(TimeAnalyzer.T0_KEY)) { + timeAnalyzer.getTableFormat(config) + } else super.getTableFormat(config) + } + +} diff --git a/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt b/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt new file mode 100644 index 00000000..4890e788 --- /dev/null +++ b/numass-core/src/main/kotlin/inr/numass/data/analyzers/TimeAnalyzer.kt @@ -0,0 +1,231 @@ +/* + * 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 inr.numass.data.analyzers + +import hep.dataforge.description.ValueDef +import hep.dataforge.description.ValueDefs +import hep.dataforge.meta.Meta +import hep.dataforge.tables.Adapters.* +import hep.dataforge.tables.TableFormat +import hep.dataforge.tables.TableFormatBuilder +import hep.dataforge.tables.ValueMap +import hep.dataforge.values.Value +import hep.dataforge.values.ValueType +import hep.dataforge.values.Values +import inr.numass.data.api.NumassBlock +import inr.numass.data.api.NumassEvent +import inr.numass.data.api.NumassPoint +import inr.numass.data.api.NumassPoint.HV_KEY +import inr.numass.data.api.SignalProcessor +import java.util.* +import java.util.concurrent.atomic.AtomicLong +import java.util.stream.Stream +import kotlin.streams.asSequence +import kotlin.streams.asStream + +/** + * An analyzer which uses time information from events + * Created by darksnake on 11.07.2017. + */ +class TimeAnalyzer @JvmOverloads constructor(private val processor: SignalProcessor? = null) : AbstractAnalyzer(processor) { + + override fun analyze(block: NumassBlock, config: Meta): Values { + //In case points inside points + if (block is NumassPoint) { + return analyzePoint(block, config) + } + + + val loChannel = config.getInt("window.lo", 0) + val upChannel = config.getInt("window.up", Integer.MAX_VALUE) + val t0 = getT0(block, config).toLong() + + val totalN = AtomicLong(0) + val totalT = AtomicLong(0) + + getEventsWithDelay(block, config) + .filter { pair -> pair.second >= t0 } + .forEach { pair -> + totalN.incrementAndGet() + //TODO add progress listener here + totalT.addAndGet(pair.second) + } + + val countRate = 1e6 * totalN.get() / (totalT.get() / 1000 - t0 * totalN.get() / 1000)//1e9 / (totalT.get() / totalN.get() - t0); + val countRateError = countRate / Math.sqrt(totalN.get().toDouble()) + val length = totalT.get() / 1e9 + val count = (length * countRate).toLong() + + return ValueMap.of(NAME_LIST, + length, + count, + countRate, + countRateError, + arrayOf(loChannel, upChannel), + block.startTime, + t0.toDouble() / 1000.0 + ) + } + + override fun analyzePoint(point: NumassPoint, config: Meta): Values { + //Average count rates, do not sum events + val res = point.blocks + .map { it -> analyze(it, config) } + .reduce(null) { v1, v2 -> this.combineBlockResults(v1, v2) } + + val map = HashMap(res.asMap()) + map.put(HV_KEY, Value.of(point.voltage)) + return ValueMap(map) + } + + /** + * Combine two blocks from the same point into one + * + * @param v1 + * @param v2 + * @return + */ + private fun combineBlockResults(v1: Values?, v2: Values?): Values? { + if (v1 == null) { + return v2 + } + if (v2 == null) { + return v1 + } + + + val t1 = v1.getDouble(NumassAnalyzer.LENGTH_KEY) + val t2 = v2.getDouble(NumassAnalyzer.LENGTH_KEY) + val cr1 = v1.getDouble(NumassAnalyzer.COUNT_RATE_KEY) + val cr2 = v2.getDouble(NumassAnalyzer.COUNT_RATE_KEY) + val err1 = v1.getDouble(NumassAnalyzer.COUNT_RATE_ERROR_KEY) + val err2 = v2.getDouble(NumassAnalyzer.COUNT_RATE_ERROR_KEY) + + val countRate = (t1 * cr1 + t2 * cr2) / (t1 + t2) + + val countRateErr = Math.sqrt(Math.pow(t1 * err1 / (t1 + t2), 2.0) + Math.pow(t2 * err2 / (t1 + t2), 2.0)) + + + return ValueMap.of(NAME_LIST, + v1.getDouble(NumassAnalyzer.LENGTH_KEY) + v2.getDouble(NumassAnalyzer.LENGTH_KEY), + v1.getInt(NumassAnalyzer.COUNT_KEY) + v2.getInt(NumassAnalyzer.COUNT_KEY), + countRate, + countRateErr, + v1.getValue(NumassAnalyzer.WINDOW_KEY), + v1.getValue(NumassAnalyzer.TIME_KEY), + v1.getDouble(T0_KEY) + ) + } + + @ValueDefs( + ValueDef(name = "t0", type = arrayOf(ValueType.NUMBER), info = "Constant t0 cut"), + ValueDef(name = "t0.crFraction", type = arrayOf(ValueType.NUMBER), info = "The relative fraction of events that should be removed by time cut"), + ValueDef(name = "t0.min", type = arrayOf(ValueType.NUMBER), def = "0", info = "Minimal t0") + ) + private fun getT0(block: NumassBlock, meta: Meta): Int { + return if (meta.hasValue("t0")) { + meta.getInt("t0")!! + } else if (meta.hasMeta("t0")) { + val fraction = meta.getDouble("t0.crFraction")!! + val cr = estimateCountRate(block) + if (cr < meta.getDouble("t0.minCR", 0.0)) { + 0 + } else { + Math.max(-1e9 / cr * Math.log(1.0 - fraction), meta.getDouble("t0.min", 0.0)!!).toInt() + } + } else { + 0 + } + + } + + private fun estimateCountRate(block: NumassBlock): Double { + return block.events.count().toDouble() / block.length.toMillis() * 1000 + } + + fun getEventsPairs(block: NumassBlock, config: Meta): Sequence> { + return Sequence { getEvents(block, config).iterator() }.zipWithNext() + } + + /** + * The chain of event times in nanos + * + * @param block + * @param config + * @return + */ + fun getEventsWithDelay(block: NumassBlock, config: Meta): Stream> { + return super.getEvents(block, config).asSequence().zipWithNext { prev, next -> + val delay = Math.max(next.timeOffset - prev.timeOffset, 0) + Pair(prev, delay) + }.asStream() +// val lastEvent = AtomicReference(null) +// +// val eventStream = super.getEvents(block, config)//using super implementation +// +// return eventStream.map { event -> +// var res = if (lastEvent.get() == null) 0L else event.timeOffset - lastEvent.get().timeOffset +// +// if (res < 0) { +// res = 0L +// } +// +// lastEvent.set(event) +// //TODO remove autoboxing somehow +// Pair(event, res) +// } + } + + /** + * The filtered stream of events + * + * @param block + * @param config + * @return + */ + override fun getEvents(block: NumassBlock, config: Meta): Stream { + val t0 = getT0(block, config).toLong() + return getEventsWithDelay(block, config).filter { pair -> pair.second >= t0 }.map { it.first } + } + + public override fun getTableFormat(config: Meta): TableFormat { + return TableFormatBuilder() + .addNumber(HV_KEY, X_VALUE_KEY) + .addNumber(NumassAnalyzer.LENGTH_KEY) + .addNumber(NumassAnalyzer.COUNT_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_KEY, Y_VALUE_KEY) + .addNumber(NumassAnalyzer.COUNT_RATE_ERROR_KEY, Y_ERROR_KEY) + .addColumn(NumassAnalyzer.WINDOW_KEY) + .addTime() + .addNumber(T0_KEY) + .build() + } + + companion object { + const val T0_KEY = "t0" + + val NAME_LIST = arrayOf( + NumassAnalyzer.LENGTH_KEY, + NumassAnalyzer.COUNT_KEY, + NumassAnalyzer.COUNT_RATE_KEY, + NumassAnalyzer.COUNT_RATE_ERROR_KEY, + NumassAnalyzer.WINDOW_KEY, + NumassAnalyzer.TIME_KEY, + T0_KEY + ) + } +} diff --git a/numass-main/src/main/groovy/inr/numass/data/PointAnalyzer.groovy b/numass-main/src/main/groovy/inr/numass/data/PointAnalyzer.groovy index 5ee2b35b..07433b42 100644 --- a/numass-main/src/main/groovy/inr/numass/data/PointAnalyzer.groovy +++ b/numass-main/src/main/groovy/inr/numass/data/PointAnalyzer.groovy @@ -23,7 +23,7 @@ class PointAnalyzer { .fill( analyzer .getEventsWithDelay(point, Grind.buildMeta("window.lo": loChannel, "window.up": upChannel)) - .mapToDouble { it.value / 1000 as double } + .mapToDouble { it.second / 1000 as double } ) } diff --git a/numass-main/src/main/groovy/inr/numass/scripts/temp/JoinSpectra.groovy b/numass-main/src/main/groovy/inr/numass/scripts/temp/JoinSpectra.groovy index a1a4b6fe..c04a9946 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/temp/JoinSpectra.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/temp/JoinSpectra.groovy @@ -14,8 +14,8 @@ import hep.dataforge.tables.ColumnTable import hep.dataforge.tables.Table import inr.numass.NumassPlugin import inr.numass.data.NumassDataUtils +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.SmartAnalyzer -import inr.numass.data.api.NumassAnalyzer import inr.numass.data.api.NumassSet import inr.numass.data.storage.NumassStorage import inr.numass.data.storage.NumassStorageFactory diff --git a/numass-main/src/main/groovy/inr/numass/scripts/times/AnalyzePoint.groovy b/numass-main/src/main/groovy/inr/numass/scripts/times/AnalyzePoint.groovy index 8dfac6c1..15c3f6cf 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/times/AnalyzePoint.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/times/AnalyzePoint.groovy @@ -23,7 +23,7 @@ import inr.numass.data.storage.NumassStorageFactory Context ctx = Global.instance() ctx.getPluginManager().load(PlotManager) -ctx.getPluginManager().load(NumassPlugin.class) +ctx.getPluginManager().load(NumassPlugin) new GrindShell(ctx).eval { File rootDir = new File("D:\\Work\\Numass\\data\\2017_05\\Fill_2") diff --git a/numass-main/src/main/groovy/inr/numass/scripts/times/TestProto.groovy b/numass-main/src/main/groovy/inr/numass/scripts/times/TestProto.groovy index 81fb50a0..3a298ab8 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/times/TestProto.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/times/TestProto.groovy @@ -7,7 +7,7 @@ import hep.dataforge.grind.helpers.PlotHelper import hep.dataforge.tables.ValueMap import inr.numass.NumassPlugin import inr.numass.data.PointAnalyzer -import inr.numass.data.api.NumassAnalyzer +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.api.NumassPoint import inr.numass.data.storage.ProtoNumassPoint diff --git a/numass-main/src/main/groovy/inr/numass/scripts/underflow/Underflow.groovy b/numass-main/src/main/groovy/inr/numass/scripts/underflow/Underflow.groovy index 5caedf47..837d1935 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/underflow/Underflow.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/underflow/Underflow.groovy @@ -25,8 +25,8 @@ import inr.numass.data.NumassDataUtils import javafx.application.Platform import static hep.dataforge.grind.Grind.buildMeta -import static inr.numass.data.api.NumassAnalyzer.CHANNEL_KEY -import static inr.numass.data.api.NumassAnalyzer.COUNT_RATE_KEY +import static inr.numass.data.analyzers.NumassAnalyzer.CHANNEL_KEY +import static inr.numass.data.analyzers.NumassAnalyzer.COUNT_RATE_KEY Context ctx = Global.instance() ctx.getPluginManager().load(PlotManager) diff --git a/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowFitter.groovy b/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowFitter.groovy index 5843d699..c5ba9a31 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowFitter.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowFitter.groovy @@ -6,7 +6,7 @@ import hep.dataforge.tables.Table import hep.dataforge.tables.TableTransform import hep.dataforge.tables.ValueMap import hep.dataforge.values.Values -import inr.numass.data.NumassDataUtils +import inr.numass.data.analyzers.NumassAnalyzerKt import org.apache.commons.math3.analysis.ParametricUnivariateFunction import org.apache.commons.math3.exception.DimensionMismatchException import org.apache.commons.math3.fitting.SimpleCurveFitter @@ -14,8 +14,8 @@ import org.apache.commons.math3.fitting.WeightedObservedPoint import java.util.stream.Collectors -import static inr.numass.data.api.NumassAnalyzer.CHANNEL_KEY -import static inr.numass.data.api.NumassAnalyzer.COUNT_RATE_KEY +import static inr.numass.data.analyzers.NumassAnalyzer.CHANNEL_KEY +import static inr.numass.data.analyzers.NumassAnalyzer.COUNT_RATE_KEY @CompileStatic class UnderflowFitter { @@ -33,7 +33,7 @@ class UnderflowFitter { double a = fitRes[0]; double sigma = fitRes[1]; - return ValueMap.of(pointNames, voltage, a, sigma, a * sigma * Math.exp(xLow / sigma) / norm + 1d); + return ValueMap.of(pointNames, voltage, a, sigma, a * sigma * Math.exp(xLow / sigma as double) / norm + 1d); } static Table fitAllPoints(Map data, int xLow, int xHigh, int upper, int binning) { @@ -56,7 +56,7 @@ class UnderflowFitter { throw new IllegalArgumentException("Wrong borders for underflow calculation"); } Table binned = TableTransform.filter( - NumassDataUtils.spectrumWithBinning(spectrum, binning), + NumassAnalyzerKt.spectrumWithBinning(spectrum, binning), CHANNEL_KEY, xLow, xHigh @@ -89,7 +89,7 @@ class UnderflowFitter { double a = parameters[0]; double sigma = parameters[1]; //return a * (Math.exp(x / sigma) - 1); - return a * Math.exp(x / sigma); + return a * Math.exp(x / sigma as double); } @Override @@ -99,7 +99,7 @@ class UnderflowFitter { } double a = parameters[0]; double sigma = parameters[1]; - return [Math.exp(x / sigma), -a * x / sigma / sigma * Math.exp(x / sigma)] as double[] + return [Math.exp(x / sigma as double), -a * x / sigma / sigma * Math.exp(x / sigma as double)] as double[] } } diff --git a/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowUtils.groovy b/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowUtils.groovy index d11413a0..1fa17eac 100644 --- a/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowUtils.groovy +++ b/numass-main/src/main/groovy/inr/numass/scripts/underflow/UnderflowUtils.groovy @@ -8,8 +8,8 @@ import hep.dataforge.grind.actions.GrindPipe import hep.dataforge.meta.Meta import hep.dataforge.storage.commons.StorageUtils import hep.dataforge.tables.Table +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.TimeAnalyzer -import inr.numass.data.api.NumassAnalyzer import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassSet import inr.numass.data.api.SimpleNumassPoint diff --git a/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java b/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java index 5bedcf54..7e08e5a1 100644 --- a/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java +++ b/numass-main/src/main/java/inr/numass/actions/MonitorCorrectAction.java @@ -28,7 +28,7 @@ import hep.dataforge.tables.ValueMap; import hep.dataforge.values.Value; import hep.dataforge.values.Values; import inr.numass.NumassUtils; -import inr.numass.data.api.NumassAnalyzer; +import inr.numass.data.analyzers.NumassAnalyzer; import inr.numass.data.api.NumassPoint; import javafx.util.Pair; import org.apache.commons.math3.analysis.interpolation.SplineInterpolator; @@ -42,7 +42,6 @@ import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; import static hep.dataforge.values.ValueType.NUMBER; -import static inr.numass.data.analyzers.AbstractAnalyzer.TIME_KEY; /** * @author Darksnake @@ -211,7 +210,7 @@ public class MonitorCorrectAction extends OneToOneAction { } private Instant getTime(Values point) { - return point.getValue(TIME_KEY).timeValue(); + return point.getValue(NumassAnalyzer.TIME_KEY).timeValue(); } private int getTotal(Values point) { diff --git a/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java b/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java index 2d225757..7bca6b31 100644 --- a/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java +++ b/numass-main/src/main/java/inr/numass/utils/NMEventGenerator.java @@ -29,7 +29,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; -import static inr.numass.data.api.NumassAnalyzer.COUNT_RATE_KEY; +import static inr.numass.data.analyzers.NumassAnalyzer.COUNT_RATE_KEY; /** * A generator for Numass events with given energy spectrum diff --git a/numass-main/src/main/java/inr/numass/utils/UnderflowCorrection.java b/numass-main/src/main/java/inr/numass/utils/UnderflowCorrection.java index 322ed4bd..b145b0fb 100644 --- a/numass-main/src/main/java/inr/numass/utils/UnderflowCorrection.java +++ b/numass-main/src/main/java/inr/numass/utils/UnderflowCorrection.java @@ -11,8 +11,7 @@ import hep.dataforge.tables.Table; import hep.dataforge.tables.TableTransform; import hep.dataforge.tables.ValueMap; import hep.dataforge.values.Values; -import inr.numass.data.NumassDataUtils; -import inr.numass.data.api.NumassAnalyzer; +import inr.numass.data.analyzers.NumassAnalyzer; import inr.numass.data.api.NumassPoint; import org.apache.commons.math3.analysis.ParametricUnivariateFunction; import org.apache.commons.math3.exception.DimensionMismatchException; @@ -22,8 +21,9 @@ import org.apache.commons.math3.fitting.WeightedObservedPoint; import java.util.List; import java.util.stream.Collectors; -import static inr.numass.data.api.NumassAnalyzer.CHANNEL_KEY; -import static inr.numass.data.api.NumassAnalyzer.COUNT_RATE_KEY; +import static inr.numass.data.analyzers.NumassAnalyzer.CHANNEL_KEY; +import static inr.numass.data.analyzers.NumassAnalyzer.COUNT_RATE_KEY; +import static inr.numass.data.analyzers.NumassAnalyzerKt.spectrumWithBinning; /** * A class to calculate underflow correction @@ -110,7 +110,7 @@ public class UnderflowCorrection { throw new IllegalArgumentException("Wrong borders for underflow calculation"); } Table binned = TableTransform.filter( - NumassDataUtils.spectrumWithBinning(spectrum, binning), + spectrumWithBinning(spectrum, binning), CHANNEL_KEY, xLow, xHigh diff --git a/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt b/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt index 6700a496..1c5f64fd 100644 --- a/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt +++ b/numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt @@ -28,7 +28,7 @@ import hep.dataforge.stat.models.WeightedXYModel import hep.dataforge.stat.models.XYModel import hep.dataforge.tables.Adapters import hep.dataforge.tables.ValuesAdapter -import inr.numass.data.api.NumassAnalyzer +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.api.NumassPoint import inr.numass.models.* import inr.numass.models.sterile.SterileNeutrinoSpectrum diff --git a/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt b/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt index 5643d787..15f6586a 100644 --- a/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt +++ b/numass-main/src/main/kotlin/inr/numass/NumassUtils.kt @@ -32,7 +32,7 @@ import hep.dataforge.tables.Table import hep.dataforge.tables.ValueMap import hep.dataforge.values.ValueType import hep.dataforge.values.Values -import inr.numass.data.api.NumassAnalyzer +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassSet import inr.numass.models.FSS diff --git a/numass-main/src/main/kotlin/inr/numass/actions/AnalyzeDataAction.kt b/numass-main/src/main/kotlin/inr/numass/actions/AnalyzeDataAction.kt index bac2394c..b8369652 100644 --- a/numass-main/src/main/kotlin/inr/numass/actions/AnalyzeDataAction.kt +++ b/numass-main/src/main/kotlin/inr/numass/actions/AnalyzeDataAction.kt @@ -10,7 +10,7 @@ import hep.dataforge.tables.Table import hep.dataforge.values.ValueType.NUMBER import hep.dataforge.values.ValueType.STRING import inr.numass.NumassUtils -import inr.numass.data.api.NumassAnalyzer +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.api.NumassSet /** diff --git a/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt b/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt index 20c3102e..27d5dfd8 100644 --- a/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt +++ b/numass-main/src/main/kotlin/inr/numass/actions/MergeDataAction.kt @@ -26,7 +26,7 @@ import hep.dataforge.meta.Meta import hep.dataforge.tables.* import hep.dataforge.values.Values import inr.numass.NumassUtils -import inr.numass.data.api.NumassAnalyzer +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.api.NumassPoint import java.util.* diff --git a/numass-main/src/main/kotlin/inr/numass/actions/TimeAnalyzerAction.kt b/numass-main/src/main/kotlin/inr/numass/actions/TimeAnalyzerAction.kt index 6261b109..c0b7d660 100644 --- a/numass-main/src/main/kotlin/inr/numass/actions/TimeAnalyzerAction.kt +++ b/numass-main/src/main/kotlin/inr/numass/actions/TimeAnalyzerAction.kt @@ -12,8 +12,8 @@ import hep.dataforge.plots.data.DataPlot import hep.dataforge.tables.Adapters import hep.dataforge.tables.Table import hep.dataforge.values.ValueType +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.TimeAnalyzer -import inr.numass.data.api.NumassAnalyzer import inr.numass.data.api.NumassPoint /** @@ -60,7 +60,7 @@ class TimeAnalyzerAction : OneToOneAction() { val histogram = UnivariateHistogram.buildUniform(0.0, binSize * binNum, binSize) .fill(analyzer .getEventsWithDelay(input, inputMeta) - .mapToDouble { it.value / 1000.0 } + .mapToDouble { it.second / 1000.0 } ).asTable() //.histogram(input, loChannel, upChannel, binSize, binNum).asTable(); diff --git a/numass-main/src/main/kotlin/inr/numass/actions/TimeSpectrumAction.kt b/numass-main/src/main/kotlin/inr/numass/actions/TimeSpectrumAction.kt index 61111062..f6bf1464 100644 --- a/numass-main/src/main/kotlin/inr/numass/actions/TimeSpectrumAction.kt +++ b/numass-main/src/main/kotlin/inr/numass/actions/TimeSpectrumAction.kt @@ -12,8 +12,8 @@ import hep.dataforge.plots.data.DataPlot import hep.dataforge.tables.Adapters import hep.dataforge.tables.Table import hep.dataforge.values.ValueType +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.TimeAnalyzer -import inr.numass.data.api.NumassAnalyzer import inr.numass.data.api.NumassPoint /** @@ -60,7 +60,7 @@ class TimeSpectrumAction : OneToOneAction() { val histogram = UnivariateHistogram.buildUniform(0.0, binSize * binNum, binSize) .fill(analyzer .getEventsWithDelay(input, inputMeta) - .mapToDouble { it.value / 1000.0 } + .mapToDouble { it.second / 1000.0 } ).asTable() //.histogram(input, loChannel, upChannel, binSize, binNum).asTable(); diff --git a/numass-main/src/main/kotlin/inr/numass/actions/TransformDataAction.kt b/numass-main/src/main/kotlin/inr/numass/actions/TransformDataAction.kt index c90382e7..8ea8210c 100644 --- a/numass-main/src/main/kotlin/inr/numass/actions/TransformDataAction.kt +++ b/numass-main/src/main/kotlin/inr/numass/actions/TransformDataAction.kt @@ -18,8 +18,8 @@ import hep.dataforge.values.ValueType.NUMBER import hep.dataforge.values.ValueType.STRING import hep.dataforge.values.Values import inr.numass.NumassUtils -import inr.numass.data.api.NumassAnalyzer.COUNT_RATE_ERROR_KEY -import inr.numass.data.api.NumassAnalyzer.COUNT_RATE_KEY +import inr.numass.data.analyzers.NumassAnalyzer.Companion.COUNT_RATE_ERROR_KEY +import inr.numass.data.analyzers.NumassAnalyzer.Companion.COUNT_RATE_KEY import inr.numass.pointExpression import java.util.* diff --git a/numass-main/src/main/kotlin/inr/numass/scripts/InversedChain.kt b/numass-main/src/main/kotlin/inr/numass/scripts/InversedChain.kt new file mode 100644 index 00000000..ef22966e --- /dev/null +++ b/numass-main/src/main/kotlin/inr/numass/scripts/InversedChain.kt @@ -0,0 +1,102 @@ +/* + * 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 inr.numass.scripts + +import hep.dataforge.fx.plots.PlotManager +import hep.dataforge.kodex.buildContext +import hep.dataforge.kodex.buildMeta +import hep.dataforge.meta.Meta +import hep.dataforge.plots.PlotPlugin +import hep.dataforge.plots.data.DataPlot +import hep.dataforge.tables.Adapters +import inr.numass.NumassPlugin +import inr.numass.data.NumassDataUtils +import inr.numass.data.analyzers.NumassAnalyzer +import inr.numass.data.analyzers.TimeAnalyzer +import inr.numass.data.analyzers.getSpectrum +import inr.numass.data.api.NumassSet +import inr.numass.data.storage.NumassStorageFactory +import java.io.File +import kotlin.streams.asSequence + + +fun main(args: Array) { + + val context = buildContext("NUMASS", NumassPlugin::class.java, PlotManager::class.java) + val rootDir = File("D:\\Work\\Numass\\data\\2017_05\\Fill_2") + + val storage = NumassStorageFactory.buildLocal(context, rootDir, true, false); + + val sets = (2..14).map { "set_$it" } + + val loaders = sets.mapNotNull { set -> + storage.provide("loader::$set", NumassSet::class.java).orElse(null) + } + + val all = NumassDataUtils.join("sum", loaders) + + val point = all.optPoint(14000.0).get() + + val t0 = 20e3.toLong() + + val analyzer = TimeAnalyzer() + + val seconds = point.length.toMillis().toDouble() / 1000.0 + + val binning = 20 + + + val plots = context.getFeature(PlotPlugin::class.java); + + val meta = buildMeta { + node("window"){ + "lo" to 300 + "up" to 1800 + } + } + + with(NumassAnalyzer) { + val events = getSpectrum(seconds, analyzer.getEvents(point).asSequence(),meta) + .withBinning(binning) + val filtered = getSpectrum( + seconds, + analyzer.getEventsPairs(point, Meta.empty()).filter { it.second.timeOffset - it.first.timeOffset > t0 }.map { it.second }, + meta + ).withBinning(binning) + + + plots.getPlotFrame("amps").apply { + add(DataPlot.plot("events", ADAPTER, events)) + add(DataPlot.plot("filtered", ADAPTER, filtered)) + } + + plots.getPlotFrame("ratio").apply { + + add( + DataPlot.plot( + "ratio", + Adapters.DEFAULT_XY_ADAPTER, + events.zip(filtered) { f, s -> + Adapters.buildXYDataPoint(f.getDouble(CHANNEL_KEY), f.getDouble(COUNT_RATE_KEY) / s.getDouble(COUNT_RATE_KEY)) + } + ) + ) + } + } + + +} diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt index c7b93b60..dc77a3bb 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt @@ -3,7 +3,6 @@ package inr.numass.viewer import hep.dataforge.fx.dfIcon import hep.dataforge.fx.plots.PlotContainer import hep.dataforge.fx.runGoal -import hep.dataforge.fx.ui import hep.dataforge.goals.Goal import hep.dataforge.kodex.configure import hep.dataforge.meta.Meta @@ -12,9 +11,8 @@ import hep.dataforge.plots.data.DataPlot import hep.dataforge.plots.jfreechart.JFreeChartFrame import hep.dataforge.tables.Adapters import hep.dataforge.tables.Table -import inr.numass.data.NumassDataUtils +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.SimpleAnalyzer -import inr.numass.data.api.NumassAnalyzer import inr.numass.data.api.NumassPoint import javafx.beans.Observable import javafx.beans.binding.DoubleBinding @@ -133,7 +131,7 @@ class AmplitudeView( DataPlot.plot( key, Adapters.buildXYAdapter(NumassAnalyzer.CHANNEL_KEY, valueAxis), - NumassDataUtils.spectrumWithBinning(getSpectrum(point), binning) + NumassAnalyzer.spectrumWithBinning(getSpectrum(point), binning) ).configure { "connectionType" to "step" "thickness" to 2 diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt index 82c914df..0f22ce55 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt @@ -11,8 +11,8 @@ import hep.dataforge.plots.data.DataPlot import hep.dataforge.plots.jfreechart.JFreeChartFrame import hep.dataforge.tables.Adapters import hep.dataforge.tables.Table +import inr.numass.data.analyzers.NumassAnalyzer import inr.numass.data.analyzers.SimpleAnalyzer -import inr.numass.data.api.NumassAnalyzer import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassSet import javafx.beans.property.SimpleIntegerProperty diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt index defa0852..680232ec 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt @@ -1,7 +1,7 @@ package inr.numass.viewer.test import hep.dataforge.fx.dfIcon -import hep.dataforge.kodex.GLOBAL +import hep.dataforge.kodex.global import hep.dataforge.tables.Table import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassSet @@ -37,7 +37,7 @@ class ViewerComponentsTest : View(title = "Numass viewer test", icon = ImageView action { runAsync { val rootDir = File("D:\\Work\\Numass\\data\\2017_05\\Fill_2") - val set: NumassSet = NumassStorageFactory.buildLocal(GLOBAL, rootDir, true, true) + val set: NumassSet = NumassStorageFactory.buildLocal(global, rootDir, true, true) .provide("loader::set_2", NumassSet::class.java) .orElseThrow { RuntimeException("err") } update(set);