diff --git a/.gitignore b/.gitignore
index 24ba39c470..f729a13c89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ docs.idx
#intellij stuff
.idea/
+.project
out/
diff --git a/.travis.yml b/.travis.yml
index 960b325c79..99b213682e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@ language: java
sudo: false
script: mvn clean verify
jdk:
-- openjdk7
- oraclejdk8
after_script:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09423c9219..82cbf623dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
#Changelog for the fact-tools
+## Version 0.17.0 -- 21.11.2016
+
+* Improvements on Single Pulse Extractor
+ * No more static API, now several instances of the SinglePulseExtractor can run in parallel with different settings.
+ * No more static (global) variable to steer the behaviour of the SinglePulseExtractor.
+ * Reconstruction of amplitude time series from the photon stream (`fact.utils.ConvertSinglePulses2Timeseries`).
+ * Added example XML `singlePeMinimalExample.xml`
+ * Use Java 8
+* Refactoring
+ * Renamed `fact.statistics.TimerowFeatures` to `fact.statistics.TimeseriesFeatures`
+
## Version 0.16.2 -- 26.10.2016
* ZFitsStream
diff --git a/examples/studies/pedestalNsbStudy.xml b/examples/studies/pedestalNsbStudy.xml
index d05e342b1a..9a837e7edd 100644
--- a/examples/studies/pedestalNsbStudy.xml
+++ b/examples/studies/pedestalNsbStudy.xml
@@ -23,7 +23,7 @@
-
+
diff --git a/examples/studies/singlePeExtractor/singlePeMinimalExample.xml b/examples/studies/singlePeExtractor/singlePeMinimalExample.xml
new file mode 100644
index 0000000000..1bd38c2791
--- /dev/null
+++ b/examples/studies/singlePeExtractor/singlePeMinimalExample.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/studies/singlePeExtractor/std_analysis_on_reconstructed_data.xml b/examples/studies/singlePeExtractor/std_analysis_on_reconstructed_data.xml
new file mode 100644
index 0000000000..7f037ece62
--- /dev/null
+++ b/examples/studies/singlePeExtractor/std_analysis_on_reconstructed_data.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/viewer.xml b/examples/viewer.xml
index 8d4c3f756e..f18aee28d0 100644
--- a/examples/viewer.xml
+++ b/examples/viewer.xml
@@ -23,7 +23,12 @@
+
+
diff --git a/pom.xml b/pom.xml
index 6eb9aecf13..932e7cf87a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
de.sfb876
fact-tools
fact-tools
- 0.16.2
+ 0.17.0
http://sfb876.de/fact-tools/
@@ -330,6 +330,14 @@
UTF-8
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.8
+
+
diff --git a/src/main/java/fact/Utils.java b/src/main/java/fact/Utils.java
index 409c312899..90dbea1898 100644
--- a/src/main/java/fact/Utils.java
+++ b/src/main/java/fact/Utils.java
@@ -522,4 +522,17 @@ public static DescriptiveStatistics[] calculateTimeseriesStatistics(double[][]
return pixelStatistics;
}
+
+ /**
+ * Flatten a 2d array
+ *
+ * @param array2d 2dim double array
+ * @return flattend double array
+ */
+ public static double[] flatten2dArray(double[][] array2d) {
+ return Arrays.stream(array2d)
+ .flatMapToDouble(Arrays::stream)
+ .toArray();
+ }
+
}
diff --git a/src/main/java/fact/extraction/SinglePulseExtraction.java b/src/main/java/fact/extraction/SinglePulseExtraction.java
index 2cb098ef29..07cbb7e45c 100644
--- a/src/main/java/fact/extraction/SinglePulseExtraction.java
+++ b/src/main/java/fact/extraction/SinglePulseExtraction.java
@@ -6,12 +6,15 @@
import stream.Processor;
import stream.annotations.Parameter;
import java.util.Arrays;
-import java.util.ArrayList;
-import fact.features.singlePulse.timeLineExtraction.SinglePulseExtractor;
-
-/*
-* Extracts a list of arrival slice positions of photons for each pixel
-* time line.
+import fact.features.singlePulse.timeSeriesExtraction.SinglePulseExtractor;
+import fact.features.singlePulse.timeSeriesExtraction.ElementWise;
+
+/**
+ * Extracts a list of arrival slice positions of photons for each pixel
+ * time line.
+ *
+ * Created by Sebastian Mueller
+ * and some modifications from Jens Buss
*/
public class SinglePulseExtraction implements Processor {
@Parameter(required=true, description="")
@@ -25,18 +28,19 @@ public class SinglePulseExtraction implements Processor {
private String outputKey = null;
@Parameter(
- required = true,
+ required = false,
description = "max number of extraction tries on a single pixel's "+
- "time line before abort"
+ "time line before abort",
+ defaultValue = "4000"
)
- protected int maxIterations;
+ protected int maxIterations = 4000;
@Parameter(
required = false,
description = "start slice of extraction window",
defaultValue = "20"
)
- protected int startSlice = 25;
+ protected int startSlice = 20;
@Parameter(
required = false,
@@ -56,88 +60,74 @@ public Data process(Data input) {
npix = (Integer) input.get("NPIX");
roi = (Integer) input.get("NROI");
- double[] timeLines = (double[]) input.get(dataKey);
+ double[] timeSerieses = (double[]) input.get(dataKey);
- double[] single_pe_count = new double[npix];
- ArrayList> pixelArrivalSlices =
- new ArrayList>();
+ double[] numberOfPulses = new double[npix];
+ int[][] pixelArrivalSlices = new int[npix][];
+ double[] baseLine = new double[npix];
+ double[][] timeSeriesAfterExtraction = new double[npix][];
+
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ config.maxIterations = maxIterations;
+ SinglePulseExtractor spe = new SinglePulseExtractor(config);
for (int pix = 0; pix < npix; pix++) {
int start = pix*roi+startSlice;
int end = start + windowLength;
- double[] pixelTimeLineInMv = Arrays.copyOfRange(
- timeLines,
+ double[] pixelTimeSeriesInMv = Arrays.copyOfRange(
+ timeSerieses,
start,
end
);
- double[] pixelTimeLine = SinglePulseExtractor.
- milliVoltToNormalizedSinglePulse(pixelTimeLineInMv);
-
- ArrayList arrivalSlices = SinglePulseExtractor.
- getArrivalSlicesOnTimeline(
- pixelTimeLine,
- maxIterations
- );
-
- single_pe_count[pix] = arrivalSlices.size();
- pixelArrivalSlices.add(arrivalSlices);
+ double[] pixelTimeSeries = ElementWise.multiply(
+ pixelTimeSeriesInMv, 1.0/config.factSinglePeAmplitudeInMv);
+
+ SinglePulseExtractor.Result result = spe.extractFromTimeSeries(
+ pixelTimeSeries);
+
+ numberOfPulses[pix] = result.numberOfPulses();
+ pixelArrivalSlices[pix] = result.pulseArrivalSlices;
+ timeSeriesAfterExtraction[pix] = ElementWise.multiply(
+ result.timeSeriesAfterExtraction,
+ config.factSinglePeAmplitudeInMv);
+ baseLine[pix] = result.timeSeriesBaseLine();
}
addStartSliceOffset(pixelArrivalSlices);
- // printArrivalSlices(pixelArrivalSlices);
+
input.put(outputKey, pixelArrivalSlices);
- input.put(outputKey+"Count", single_pe_count);
+ input.put(outputKey+"TimeSeriesAfterExtraction", Utils.flatten2dArray(timeSeriesAfterExtraction));
+ input.put(outputKey+"NumberOfPulses", numberOfPulses);
+ input.put(outputKey+"BaseLine", baseLine);
+ input.put(outputKey+"MaxIterations", maxIterations);
return input;
}
- private void addStartSliceOffset(ArrayList> arr) {
- for(int pix=0; pix> arr) {
- for(int pix=0; pix getArrivalSlicesOnTimeline(
- double[] timeLine,
- int maxIterations
- ) {
- ArrayList arrival_slices = new ArrayList();
- int iteration = 0;
-
- while(iteration < maxIterations) {
- final double[] conv = Convolve.firstWithSecond(
- timeLine,
- pulseToLookFor);
- final ArgMax am = new ArgMax(conv);
- final int offsetSlices =
- (int)((double)(pulseToLookFor.length)*0.35);
- // The offsetSlices are needed to comensate both the asymetric
- // convolution and the asymetric amplitude distribution in the
- // pulse template (mostly the rising edge of the pulse).
- // These asymetries cause the maximum amplitude in conv not to
- // be the optimum position for the pulse substraction.
- // The offsetSlices are chosen to correct for this and as a
- // first guide we provide here the magic factor:
- // offsetSlices = 0.35*templatePulse.length
- // This indicates the dependency of offsetSlices of the
- // templatePulse.length
- // (offsetSlices = 7 for templatePulse.length = 20).
- // It might be that offsetSlices can be optimized based on the
- // maxResponse.
- final int maxSlice = am.arg - offsetSlices;
- final double maxResponse = am.max/pulseToLookForIntegral;
-
- if(maxResponse > 0.5) {
- final double weight = 1.0;
- final double[] negativeSinglePulse = ElementWise.multiply(
- pulseToSubstract,
- -weight);
-
- AddFirstArrayToSecondArray.at(
- negativeSinglePulse,
- timeLine,
- maxSlice);
-
- applyAcCoupling(timeLine);
- arrival_slices.add(am.arg);
- }else{
- break;
- }
- iteration++;
- }
-
- return arrival_slices;
- }
-
- /**
- * Estimates the effect of FACT's AC coupling in between the
- * photo-electric converter (SIPM) and the signal sampler (DRS4).
- * Here simply the mean of the time line is substracted from it.
- *
- * @param timeLine
- * The time line is modified inplace.
- */
- public static void applyAcCoupling(double[] timeLine) {
- if(timeLine.length == 0)
- return;
-
- double sum = 0.0;
- for (double slice : timeLine){
- sum += slice;
- }
-
- final double mean = sum/(double)(timeLine.length);
-
- timeLine = ElementWise.add(timeLine, -mean);
- }
-
- /**
- * Convert time line amplitudes from mV to normalized amplitudes of
- * single photon pulses.
- *
- * @return timeLineNormalizedSinglePulses
- * The amplitude of single pulses is 1.0 here.
- *
- * @param timeLineInMv
- * In milli Volts (single pulse amplitude about 10mV)
- */
- public static double[] milliVoltToNormalizedSinglePulse(
- double[] timeLineInMv
- ) {
-
- return ElementWise.multiply(
- timeLineInMv,
- 1.0/factSinglePeAmplitudeInMv);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/fact/features/singlePulse/timeLineExtraction/AddFirstArrayToSecondArray.java b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/AddFirstArrayToSecondArray.java
similarity index 97%
rename from src/main/java/fact/features/singlePulse/timeLineExtraction/AddFirstArrayToSecondArray.java
rename to src/main/java/fact/features/singlePulse/timeSeriesExtraction/AddFirstArrayToSecondArray.java
index f7ae047f89..944d3742f8 100644
--- a/src/main/java/fact/features/singlePulse/timeLineExtraction/AddFirstArrayToSecondArray.java
+++ b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/AddFirstArrayToSecondArray.java
@@ -1,4 +1,4 @@
-package fact.features.singlePulse.timeLineExtraction;
+package fact.features.singlePulse.timeSeriesExtraction;
/**
* Utility class for adding elements of two arrays
diff --git a/src/main/java/fact/features/singlePulse/timeLineExtraction/ArgMax.java b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/ArgMax.java
similarity index 90%
rename from src/main/java/fact/features/singlePulse/timeLineExtraction/ArgMax.java
rename to src/main/java/fact/features/singlePulse/timeSeriesExtraction/ArgMax.java
index d79c911fca..d7d3b7a5bc 100644
--- a/src/main/java/fact/features/singlePulse/timeLineExtraction/ArgMax.java
+++ b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/ArgMax.java
@@ -1,4 +1,4 @@
-package fact.features.singlePulse.timeLineExtraction;
+package fact.features.singlePulse.timeSeriesExtraction;
/**
* Finds the maximum on an array and stores its position (arg)
diff --git a/src/main/java/fact/features/singlePulse/timeLineExtraction/Convolve.java b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/Convolve.java
similarity index 95%
rename from src/main/java/fact/features/singlePulse/timeLineExtraction/Convolve.java
rename to src/main/java/fact/features/singlePulse/timeSeriesExtraction/Convolve.java
index 20a1054e51..e6489543e8 100644
--- a/src/main/java/fact/features/singlePulse/timeLineExtraction/Convolve.java
+++ b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/Convolve.java
@@ -1,4 +1,4 @@
-package fact.features.singlePulse.timeLineExtraction;
+package fact.features.singlePulse.timeSeriesExtraction;
/**
* Utility class containing a method for convolving two arrays.
diff --git a/src/main/java/fact/features/singlePulse/timeSeriesExtraction/ElementWise.java b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/ElementWise.java
new file mode 100644
index 0000000000..64519120d7
--- /dev/null
+++ b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/ElementWise.java
@@ -0,0 +1,73 @@
+package fact.features.singlePulse.timeSeriesExtraction;
+
+/**
+ * A collection of element-wise operations on double[] arrays with a scalar.
+ */
+public class ElementWise {
+
+ /**
+ * Multiply values in an array with a scalar.
+ * @param arr
+ * The input array [N]
+ * @param scalar
+ * A scalar to multiply the array with
+ * @return out
+ * A copy of arr [N], but elementwise multiplied with scalar
+ */
+ public static double[] multiply(double[] arr, double scalar) {
+ double[] out = new double[arr.length];
+ for(int i=0; i arrival_slices = new ArrayList<>();
+ int iteration = 0;
+
+ while(iteration < config.maxIterations) {
+
+ final double[] pulseResponse = Convolve.firstWithSecond(
+ timeSeries,
+ pulseToLookFor);
+
+ final double[] baselineResponse = Convolve.firstWithSecond(
+ timeSeries,
+ plateauToLookFor);
+
+ final double[] response = ElementWise.subtractFirstFromSecond(
+ baselineResponse,
+ pulseResponse);
+
+ final ArgMax am = new ArgMax(response);
+ final int maxSlice = am.arg + config.plateauLength;
+ final double maxResponse = am.max;
+
+ if(maxResponse > 0.65) {
+ AddFirstArrayToSecondArray.at(
+ negativePulse,
+ timeSeries,
+ maxSlice);
+
+ if(maxSlice >= 1)
+ arrival_slices.add(maxSlice);
+ }else{
+ break;
+ }
+ iteration++;
+ }
+
+ Result result = new Result();
+ result.timeSeriesAfterExtraction = timeSeries;
+ result.pulseArrivalSlices = Utils.arrayListToInt(arrival_slices);
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/fact/features/singlePulse/timeLineExtraction/TemplatePulse.java b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/TemplatePulse.java
similarity index 97%
rename from src/main/java/fact/features/singlePulse/timeLineExtraction/TemplatePulse.java
rename to src/main/java/fact/features/singlePulse/timeSeriesExtraction/TemplatePulse.java
index 1b3c3ce629..7c194caafa 100644
--- a/src/main/java/fact/features/singlePulse/timeLineExtraction/TemplatePulse.java
+++ b/src/main/java/fact/features/singlePulse/timeSeriesExtraction/TemplatePulse.java
@@ -1,4 +1,4 @@
-package fact.features.singlePulse.timeLineExtraction;
+package fact.features.singlePulse.timeSeriesExtraction;
/**
* The pulse shape of FACTs SiPMs. This class contains a single function returning
diff --git a/src/main/java/fact/statistics/SinglePeStatisticsPixel.java b/src/main/java/fact/statistics/SinglePeStatisticsPixel.java
new file mode 100644
index 0000000000..a05fc0c364
--- /dev/null
+++ b/src/main/java/fact/statistics/SinglePeStatisticsPixel.java
@@ -0,0 +1,105 @@
+package fact.statistics;
+
+import fact.Utils;
+import org.apache.commons.math3.stat.StatUtils;
+import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
+
+import stream.Data;
+import stream.Processor;
+import stream.annotations.Parameter;
+
+
+
+/**
+ * Calculate the Statistics of Pixel Arrays
+ *
+ * @author Jens Buss
+ *
+ */
+public class SinglePeStatisticsPixel implements Processor {
+
+ @Parameter(required=true,description="key to the data array")
+ private String dataKey = null;
+ @Parameter(required=true,description="name of the key of the calculated features")
+ private String outputKey = null;
+
+ private int npix;
+
+ @Override
+ public Data process(Data input) {
+ Utils.isKeyValid(input, "NPIX", Integer.class);
+ npix = (Integer) input.get("NPIX");
+
+ Utils.mapContainsKeys(input, dataKey);
+
+ int[][] data = (int[][]) input.get(dataKey);
+
+ double[] mean = new double[npix];
+ double[] median = new double[npix];
+ double[] mode = new double[npix];
+ double[] std = new double[npix];
+ double[] kurtosis = new double[npix];
+ double[] skewness = new double[npix];
+ double[] min = new double[npix];
+ double[] max = new double[npix];
+ double[] quantil25 = new double[npix];
+ double[] quantil75 = new double[npix];
+
+ for (int pix = 0 ; pix < npix ; pix++){
+ double[] values = Utils.toDoubleArray(data[pix]);
+
+
+ ///FIXME: fill nans instead of continue
+ if (values.length == 0){
+ continue;
+ }
+
+ DescriptiveStatistics stats = new DescriptiveStatistics(values);
+ mean[pix] = stats.getMean();
+ min[pix] = stats.getMin();
+ max[pix] = stats.getMax();
+ std[pix] = stats.getStandardDeviation();
+ skewness[pix] = stats.getSkewness();
+ kurtosis[pix] = stats.getKurtosis();
+ quantil25[pix] = stats.getPercentile(0.25);
+ quantil75[pix] = stats.getPercentile(0.75);
+ median[pix] = stats.getPercentile(0.5);
+
+ double[] modeArray = StatUtils.mode(values);
+ mode[pix] = modeArray[0];
+ }
+
+ input.put(outputKey+ "_mean", mean);
+ input.put(outputKey+ "_median", median);
+ input.put(outputKey+ "_mode", mode);
+ input.put(outputKey+ "_std", std);
+ input.put(outputKey+ "_kurtosis", kurtosis);
+ input.put(outputKey+ "_skewness", skewness);
+ input.put(outputKey+ "_min", min);
+ input.put(outputKey+ "_max", max);
+ input.put(outputKey+ "_quantil25", quantil25);
+ input.put(outputKey+ "_quantil75", quantil75);
+
+
+ return input;
+ }
+
+
+ public String getDataKey() {
+ return dataKey;
+ }
+
+ public void setDataKey(String dataKey) {
+ this.dataKey = dataKey;
+ }
+
+ public String getOutputKey() {
+ return outputKey;
+ }
+
+ public void setOutputKey(String outputKey) {
+ this.outputKey = outputKey;
+ }
+
+
+}
diff --git a/src/main/java/fact/statistics/TimerowFeatures.java b/src/main/java/fact/statistics/TimeseriesFeatures.java
similarity index 90%
rename from src/main/java/fact/statistics/TimerowFeatures.java
rename to src/main/java/fact/statistics/TimeseriesFeatures.java
index 30c4ccb690..ce1e190782 100644
--- a/src/main/java/fact/statistics/TimerowFeatures.java
+++ b/src/main/java/fact/statistics/TimeseriesFeatures.java
@@ -8,6 +8,7 @@
import stream.Processor;
import stream.annotations.Parameter;
+import java.util.Arrays;
/**
@@ -19,7 +20,7 @@
* @author F. Temme
*
*/
-public class TimerowFeatures implements Processor {
+public class TimeseriesFeatures implements Processor {
@Parameter(required=true,description="key to the data array")
private String dataKey = null;
@@ -52,11 +53,18 @@ public Data process(Data input) {
Utils.checkWindow(searchWindowLeft, searchWindowRight-searchWindowLeft, 0, roi);
- Utils.mapContainsKeys(input, dataKey, movingAverageKey);
+ Utils.mapContainsKeys(input, dataKey);
double[] data = (double[]) input.get(dataKey);
- double[] movingAverage = (double[]) input.get(movingAverageKey);
-
+
+ double[] movingAverage;
+
+ if (movingAverageKey != null){
+ movingAverage = (double[]) input.get(movingAverageKey);
+ } else {
+ movingAverage = new double[data.length];
+ }
+
double[] mean = new double[npix];
double[] median = new double[npix];
@@ -125,50 +133,29 @@ private int findBinNumber(double value){
return binNumber;
}
- public String getDataKey() {
- return dataKey;
- }
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
- public String getMovingAverageKey() {
- return movingAverageKey;
- }
+
public void setMovingAverageKey(String movingAverageKey) {
this.movingAverageKey = movingAverageKey;
}
- public int getSearchWindowLeft() {
- return searchWindowLeft;
- }
-
public void setSearchWindowLeft(int searchWindowLeft) {
this.searchWindowLeft = searchWindowLeft;
}
- public int getSearchWindowRight() {
- return searchWindowRight;
- }
-
public void setSearchWindowRight(int searchWindowRight) {
this.searchWindowRight = searchWindowRight;
}
- public String getOutputKey() {
- return outputKey;
- }
-
public void setOutputKey(String outputKey) {
this.outputKey = outputKey;
}
- public int getNumberOfBins() {
- return numberOfBins;
- }
-
public void setNumberOfBins(int numberOfBins) {
this.numberOfBins = numberOfBins;
}
diff --git a/src/main/java/fact/utils/ConvertSinglePulses2Timeseries.java b/src/main/java/fact/utils/ConvertSinglePulses2Timeseries.java
new file mode 100644
index 0000000000..18b0fa2f9b
--- /dev/null
+++ b/src/main/java/fact/utils/ConvertSinglePulses2Timeseries.java
@@ -0,0 +1,87 @@
+package fact.utils;
+
+import fact.features.singlePulse.timeSeriesExtraction.AddFirstArrayToSecondArray;
+import fact.features.singlePulse.timeSeriesExtraction.SinglePulseExtractor;
+import fact.features.singlePulse.timeSeriesExtraction.TemplatePulse;
+import fact.features.singlePulse.timeSeriesExtraction.ElementWise;
+import org.apache.commons.lang3.ArrayUtils;
+import stream.Data;
+import stream.Processor;
+import stream.annotations.Parameter;
+
+
+/**
+ * Created by jebuss on 28.10.16.
+ */
+public class ConvertSinglePulses2Timeseries implements Processor {
+ @Parameter(required = true, description = "The arrival slices of the single pulses.")
+ private String singlePulsesKey = null;
+
+ @Parameter(required = true, description = "The reconstruted time series.")
+ private String timeSeriesKey = null;
+
+ @Parameter(required = false, description = "The region of interest to be reconstructed.")
+ private int roi = 300;
+
+ @Parameter(required = false, description = "The reconstructed baseline of the original time series.")
+ private String baseLineKey = null;
+
+ @Override
+ public Data process(Data input) {
+
+ int[][] singlePulses = (int[][]) input.get(singlePulsesKey);
+
+ double[] baseLine = new double[singlePulses.length];
+ if(baseLineKey != null) {
+ baseLine = (double[]) input.get(baseLineKey);
+ }
+
+ double[] pulseTemplate = TemplatePulse.factSinglePePulse(roi);
+
+ double[] timeSeries = new double[0];
+
+ for (int pix = 0; pix < singlePulses.length; pix++) {
+
+ // create empty time series of length roi
+ double[] currentTimeSeries = new double[roi];
+
+ // Add the single pulses to the time series
+ for (int pulse = 0; pulse < singlePulses[pix].length; pulse++) {
+ AddFirstArrayToSecondArray.at(
+ pulseTemplate,
+ currentTimeSeries,
+ singlePulses[pix][pulse]);
+ }
+
+ // Add the baseline to the time series
+ currentTimeSeries = ElementWise.add(currentTimeSeries, baseLine[pix]);
+
+ timeSeries = ArrayUtils.addAll(timeSeries, currentTimeSeries);
+ }
+
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ timeSeries = ElementWise.multiply(
+ timeSeries,
+ config.factSinglePeAmplitudeInMv);
+
+ input.put(timeSeriesKey, timeSeries);
+
+ return input;
+ }
+
+ public void setSinglePulsesKey(String singlePulsesKey) {
+ this.singlePulsesKey = singlePulsesKey;
+ }
+
+ public void settimeSeriesKey(String timeSeriesKey) {
+ this.timeSeriesKey = timeSeriesKey;
+ }
+
+ public void setBaseLineKey(String baseLineKey) {
+ this.baseLineKey = baseLineKey;
+ }
+
+ public void setRoi(int roi) {
+ this.roi = roi;
+ }
+}
diff --git a/src/test/java/fact/FunctionalTest.java b/src/test/java/fact/FunctionalTest.java
index 78ea10ae20..33aa783a9b 100644
--- a/src/test/java/fact/FunctionalTest.java
+++ b/src/test/java/fact/FunctionalTest.java
@@ -9,9 +9,15 @@
import stream.runtime.ProcessContainer;
import java.io.File;
+import java.io.IOException;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
@@ -70,23 +76,28 @@ public void analysis_mcXML() {
@Test
- public void studiesXMLs() {
- File folder = new File("examples/studies");
+ public void studiesXMLs() throws IOException {
int counter = 0;
- int size = folder.listFiles().length;
+ List pathList = Files.walk(Paths.get("examples/studies"))
+ .filter(Files::isRegularFile)
+ .collect(Collectors.toList());
+
+ int size = pathList.size();
+
ArrayList failedFilesList = new ArrayList<>();
- for (File f : folder.listFiles()){
- String[] args = {f.getAbsolutePath()};
+
+ for (Path f : pathList){
+ String[] args = {f.toAbsolutePath().toString()};
try{
stream.run.main(args);
} catch (Exception e){
log.error("Error executing xml: " + f, e);
- failedFilesList.add(f.getName());
+ failedFilesList.add(f.toString());
counter++;
}
}
- log.info("\n\n" + counter + " of " + size + " files in " + folder.getName() + " failed to execute");
+ log.info("\n\n" + counter + " of " + size + " files in examples/studies failed to execute");
log.info(Arrays.toString(failedFilesList.toArray()));
assertThat(failedFilesList.size(), is(0));
}
diff --git a/src/test/java/fact/UtilsTests.java b/src/test/java/fact/UtilsTests.java
new file mode 100644
index 0000000000..56fdc107a8
--- /dev/null
+++ b/src/test/java/fact/UtilsTests.java
@@ -0,0 +1,17 @@
+package fact;
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * Created by jebuss on 14.11.16.
+ */
+public class UtilsTests {
+ @Test
+ public void flattenEmpty2dArray(){
+
+ double[][] empty = new double[0][0];
+ double[] result = Utils.flatten2dArray(empty);
+ Assert.assertEquals(result.length, 0);
+ }
+
+}
diff --git a/src/test/java/fact/features/AddFirstArrayToSecondArrayTest.java b/src/test/java/fact/features/AddFirstArrayToSecondArrayTest.java
index 8aa38096ee..215de6df4c 100644
--- a/src/test/java/fact/features/AddFirstArrayToSecondArrayTest.java
+++ b/src/test/java/fact/features/AddFirstArrayToSecondArrayTest.java
@@ -3,7 +3,7 @@
import fact.Utils;
import junit.framework.Assert;
import org.junit.Test;
-import fact.features.singlePulse.timeLineExtraction.AddFirstArrayToSecondArray;
+import fact.features.singlePulse.timeSeriesExtraction.AddFirstArrayToSecondArray;
public class AddFirstArrayToSecondArrayTest {
diff --git a/src/test/java/fact/features/ArgMaxTest.java b/src/test/java/fact/features/ArgMaxTest.java
index ee9933b07a..2e915ebd99 100644
--- a/src/test/java/fact/features/ArgMaxTest.java
+++ b/src/test/java/fact/features/ArgMaxTest.java
@@ -3,17 +3,17 @@
import fact.Utils;
import junit.framework.Assert;
import org.junit.Test;
-import fact.features.singlePulse.timeLineExtraction.ArgMax;
+import fact.features.singlePulse.timeSeriesExtraction.ArgMax;
public class ArgMaxTest {
@Test
- public void testArgMaxEmptyTimeLine() {
+ public void testArgMaxEmptyTimeSeries() {
Throwable e = null;
try {
- double[] emptyTimeLine = {};
- ArgMax am = new ArgMax(emptyTimeLine);
+ double[] emptyTimeSeries = {};
+ ArgMax am = new ArgMax(emptyTimeSeries);
}catch(Throwable ex) {
e = ex;
}
@@ -21,19 +21,19 @@ public void testArgMaxEmptyTimeLine() {
}
@Test
- public void testArgMaxZeroTimeLine(){
+ public void testArgMaxZeroTimeSeries(){
- double[] zeroTimeLine = {
+ double[] zeroTimeSeries = {
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, 0.0, 0.0, 0.0, 0.0, 0.0};
- ArgMax am = new ArgMax(zeroTimeLine);
+ ArgMax am = new ArgMax(zeroTimeSeries);
Assert.assertEquals(0, am.arg);
Assert.assertEquals(0.0, am.max);
}
@Test
- public void testArgMaxSingleMaxTimeLine(){
+ public void testArgMaxSingleMaxTimeSeries(){
double[] trianglePulse = {
0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0};
diff --git a/src/test/java/fact/features/ConvolveTest.java b/src/test/java/fact/features/ConvolveTest.java
index 32dd3d012e..8e1621ce10 100644
--- a/src/test/java/fact/features/ConvolveTest.java
+++ b/src/test/java/fact/features/ConvolveTest.java
@@ -3,7 +3,7 @@
import fact.Utils;
import junit.framework.Assert;
import org.junit.Test;
-import fact.features.singlePulse.timeLineExtraction.Convolve;
+import fact.features.singlePulse.timeSeriesExtraction.Convolve;
public class ConvolveTest {
diff --git a/src/test/java/fact/features/ElementWiseTest.java b/src/test/java/fact/features/ElementWiseTest.java
index ede43b76f8..1065b457d1 100644
--- a/src/test/java/fact/features/ElementWiseTest.java
+++ b/src/test/java/fact/features/ElementWiseTest.java
@@ -3,7 +3,7 @@
import fact.Utils;
import junit.framework.Assert;
import org.junit.Test;
-import fact.features.singlePulse.timeLineExtraction.ElementWise;
+import fact.features.singlePulse.timeSeriesExtraction.ElementWise;
public class ElementWiseTest {
@@ -66,4 +66,32 @@ public void testAddZeros(){
for(int i=0; i arrivalSlices = SinglePulseExtractor.
- getArrivalSlicesOnTimeline(
- timeLine,
- maxIterations);
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ SinglePulseExtractor spe = new SinglePulseExtractor(config);
+
+ SinglePulseExtractor.Result result = spe.extractFromTimeSeries(timeSeries);
+ Assert.assertEquals(0, result.pulseArrivalSlices.length);
+ Assert.assertEquals(0, result.numberOfPulses());
+ }
+
+
+ @Test
+ public void testFlatTimeSeriesBaseLine() {
+
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ SinglePulseExtractor spe = new SinglePulseExtractor(config);
+
+ for(double baseLine=-50.0; baseLine<50; baseLine++) {
+
+ double[] timeSeries = new double[300];
+ for(int i=0; i= baseLine-1.0
+ );
+ }
+ }
+
+ @Test
+ public void testOnePulseBaseLine() {
- Assert.assertEquals(0, arrivalSlices.size());
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ SinglePulseExtractor spe = new SinglePulseExtractor(config);
+
+ for(double baseLine=-50.0; baseLine<50; baseLine++) {
+
+ double[] timeSeries = new double[300];
+ for(int i=0; i= baseLine-1.0
+ );
+ }
}
@Test
public void testOnePulseNoNoise() {
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ SinglePulseExtractor spe = new SinglePulseExtractor(config);
+
for(int injectionSlice = 50; injectionSlice< 250; injectionSlice++) {
- double[] timeLine = new double[300];
+ double[] timeSeries = new double[300];
AddFirstArrayToSecondArray.at(
TemplatePulse.factSinglePePulse(300),
- timeLine,
+ timeSeries,
injectionSlice);
- SinglePulseExtractor.applyAcCoupling(timeLine);
-
- final int maxIterations = 50;
- ArrayList arrivalSlices = SinglePulseExtractor.
- getArrivalSlicesOnTimeline(
- timeLine,
- maxIterations);
+ SinglePulseExtractor.Result result = spe.extractFromTimeSeries(timeSeries);
- Assert.assertEquals(1, arrivalSlices.size());
+ Assert.assertEquals(1, result.pulseArrivalSlices.length);
+ Assert.assertEquals(1, result.numberOfPulses());
Assert.assertTrue(
- arrivalSlices.get(0) <= injectionSlice+2 &&
- arrivalSlices.get(0) >= injectionSlice-2
+ result.pulseArrivalSlices[0] <= injectionSlice+2 &&
+ result.pulseArrivalSlices[0] >= injectionSlice-2
);
}
}
@@ -56,29 +101,27 @@ public void testOnePulseNoNoise() {
@Test
public void testSeveralPulsesOnTopOfEachOtherNoNoise() {
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ config.maxIterations = 100;
+ SinglePulseExtractor spe = new SinglePulseExtractor(config);
+
final int injectionSlice = 50;
- for(double amplitude = 0.0; amplitude<50.0; amplitude++) {
+ for(double amplitude = 0.0; amplitude<15.0; amplitude++) {
- double[] timeLine = new double[300];
+ double[] timeSeries = new double[300];
for(int i=0; i<(int)amplitude; i++)
AddFirstArrayToSecondArray.at(
TemplatePulse.factSinglePePulse(300),
- timeLine,
+ timeSeries,
injectionSlice);
- SinglePulseExtractor.applyAcCoupling(timeLine);
-
- final int maxIterations = 100;
- ArrayList arrivalSlices = SinglePulseExtractor.
- getArrivalSlicesOnTimeline(
- timeLine,
- maxIterations);
+ SinglePulseExtractor.Result result = spe.extractFromTimeSeries(timeSeries);
Assert.assertTrue(
- (double)arrivalSlices.size() <= amplitude+amplitude*0.15 &&
- (double)arrivalSlices.size() >= amplitude-amplitude*0.15
+ (double)result.numberOfPulses() <= amplitude+amplitude*0.25 &&
+ (double)result.numberOfPulses() >= amplitude-amplitude*0.25
);
}
}
@@ -86,40 +129,39 @@ public void testSeveralPulsesOnTopOfEachOtherNoNoise() {
@Test
public void testSeveralPulsesInARowNoNoise() {
- double[] timeLine = new double[300];
+ SinglePulseExtractor.Config config = new SinglePulseExtractor.Config();
+ config.maxIterations = 100;
+ SinglePulseExtractor spe = new SinglePulseExtractor(config);
+
+ double[] timeSeries = new double[300];
AddFirstArrayToSecondArray.at(
TemplatePulse.factSinglePePulse(300),
- timeLine,
+ timeSeries,
50);
AddFirstArrayToSecondArray.at(
TemplatePulse.factSinglePePulse(300),
- timeLine,
+ timeSeries,
125);
AddFirstArrayToSecondArray.at(
TemplatePulse.factSinglePePulse(300),
- timeLine,
+ timeSeries,
200);
- SinglePulseExtractor.applyAcCoupling(timeLine);
+ SinglePulseExtractor.Result result = spe.extractFromTimeSeries(timeSeries);
- final int maxIterations = 100;
- ArrayList arrivalSlices = SinglePulseExtractor.
- getArrivalSlicesOnTimeline(
- timeLine,
- maxIterations);
- Assert.assertEquals(3, arrivalSlices.size());
+ Assert.assertEquals(3, result.pulseArrivalSlices.length);
- Assert.assertTrue((double)arrivalSlices.get(0) >= 200-2);
- Assert.assertTrue((double)arrivalSlices.get(0) <= 200+2);
+ Assert.assertTrue((double)result.pulseArrivalSlices[0] >= 50-2);
+ Assert.assertTrue((double)result.pulseArrivalSlices[0] <= 50+2);
- Assert.assertTrue((double)arrivalSlices.get(1) >= 125-2);
- Assert.assertTrue((double)arrivalSlices.get(1) <= 125+2);
+ Assert.assertTrue((double)result.pulseArrivalSlices[1] >= 125-2);
+ Assert.assertTrue((double)result.pulseArrivalSlices[1] <= 125+2);
- Assert.assertTrue((double)arrivalSlices.get(2) >= 50-2);
- Assert.assertTrue((double)arrivalSlices.get(2) <= 50+2);
+ Assert.assertTrue((double)result.pulseArrivalSlices[2] >= 200-2);
+ Assert.assertTrue((double)result.pulseArrivalSlices[2] <= 200+2);
}
}