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 + 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); } }