diff --git a/examples/27s.xml b/examples/27s.xml index a145fef9dc..f79e072c07 100644 --- a/examples/27s.xml +++ b/examples/27s.xml @@ -3,9 +3,11 @@ - + + + diff --git a/examples/apply_model.xml b/examples/apply_model.xml index 072d5b3337..756865626f 100644 --- a/examples/apply_model.xml +++ b/examples/apply_model.xml @@ -5,7 +5,6 @@ - @@ -14,6 +13,7 @@ + diff --git a/examples/fellwalker_example.xml b/examples/fellwalker_example.xml index 29ec8c8856..cd093ffc62 100644 --- a/examples/fellwalker_example.xml +++ b/examples/fellwalker_example.xml @@ -5,13 +5,13 @@ - + diff --git a/examples/forErna/std_analysis_erna_observations.xml b/examples/forErna/std_analysis_erna_observations.xml index 8ac8ec1ec1..d9c0dc0528 100644 --- a/examples/forErna/std_analysis_erna_observations.xml +++ b/examples/forErna/std_analysis_erna_observations.xml @@ -7,11 +7,11 @@ - + diff --git a/examples/forErna/std_analysis_erna_simulations.xml b/examples/forErna/std_analysis_erna_simulations.xml index cfb8731d96..0a91621eb4 100644 --- a/examples/forErna/std_analysis_erna_simulations.xml +++ b/examples/forErna/std_analysis_erna_simulations.xml @@ -7,11 +7,11 @@ - + diff --git a/examples/mc_viewer.xml b/examples/mc_viewer.xml index 913667ae77..5f1695df5d 100644 --- a/examples/mc_viewer.xml +++ b/examples/mc_viewer.xml @@ -7,10 +7,10 @@ - + diff --git a/examples/measure_performance.xml b/examples/measure_performance.xml index dd45c58316..ae8dc2cfcc 100644 --- a/examples/measure_performance.xml +++ b/examples/measure_performance.xml @@ -3,11 +3,12 @@ - + + diff --git a/examples/save_dl1.xml b/examples/save_dl1.xml index ac4af5d50c..adebd2e1dc 100644 --- a/examples/save_dl1.xml +++ b/examples/save_dl1.xml @@ -6,10 +6,10 @@ - + diff --git a/examples/stdAnalysis.xml b/examples/stdAnalysis.xml index 198d81a878..ba72995353 100644 --- a/examples/stdAnalysis.xml +++ b/examples/stdAnalysis.xml @@ -5,13 +5,13 @@ - + diff --git a/examples/studies/closedShutterGainCalibration.xml b/examples/studies/closedShutterGainCalibration.xml index 001cd91e62..d7e74ce8f8 100644 --- a/examples/studies/closedShutterGainCalibration.xml +++ b/examples/studies/closedShutterGainCalibration.xml @@ -4,11 +4,12 @@ - + + diff --git a/examples/studies/extractionTest.xml b/examples/studies/extractionTest.xml index 5d03d62729..c3c9023fc7 100644 --- a/examples/studies/extractionTest.xml +++ b/examples/studies/extractionTest.xml @@ -3,10 +3,11 @@ - + + diff --git a/examples/studies/jumpStudy.xml b/examples/studies/jumpStudy.xml index b6edcbc60f..f5105cd089 100644 --- a/examples/studies/jumpStudy.xml +++ b/examples/studies/jumpStudy.xml @@ -3,7 +3,7 @@ - + diff --git a/examples/studies/muon_fitting.xml b/examples/studies/muon_fitting.xml index 1b826baf4d..cafb41b84c 100644 --- a/examples/studies/muon_fitting.xml +++ b/examples/studies/muon_fitting.xml @@ -7,11 +7,11 @@ - + diff --git a/examples/studies/muon_identification.xml b/examples/studies/muon_identification.xml index e7ee579a59..2032be0b50 100644 --- a/examples/studies/muon_identification.xml +++ b/examples/studies/muon_identification.xml @@ -5,12 +5,12 @@ - + diff --git a/examples/studies/pedestalNsbStudy.xml b/examples/studies/pedestalNsbStudy.xml index f15ea18446..23d8e882a1 100644 --- a/examples/studies/pedestalNsbStudy.xml +++ b/examples/studies/pedestalNsbStudy.xml @@ -3,10 +3,11 @@ - + + @@ -17,7 +18,7 @@ - diff --git a/examples/studies/pedestalStudies.xml b/examples/studies/pedestalStudies.xml index c4e800d1db..a164e596d3 100644 --- a/examples/studies/pedestalStudies.xml +++ b/examples/studies/pedestalStudies.xml @@ -6,7 +6,7 @@ - + diff --git a/examples/studies/simulations_pass4.xml b/examples/studies/simulations_pass4.xml index 736dbad0e1..03ad25d517 100644 --- a/examples/studies/simulations_pass4.xml +++ b/examples/studies/simulations_pass4.xml @@ -4,7 +4,7 @@ - + diff --git a/examples/studies/singlePeExtractor/singlePeMinimalExample.xml b/examples/studies/singlePeExtractor/singlePeMinimalExample.xml index 9e31142dbd..e819048903 100644 --- a/examples/studies/singlePeExtractor/singlePeMinimalExample.xml +++ b/examples/studies/singlePeExtractor/singlePeMinimalExample.xml @@ -5,7 +5,6 @@ - @@ -14,6 +13,7 @@ + diff --git a/examples/studies/singlePeExtractor/std_analysis_on_reconstructed_data.xml b/examples/studies/singlePeExtractor/std_analysis_on_reconstructed_data.xml index 422917eef6..d70fb53819 100644 --- a/examples/studies/singlePeExtractor/std_analysis_on_reconstructed_data.xml +++ b/examples/studies/singlePeExtractor/std_analysis_on_reconstructed_data.xml @@ -5,7 +5,6 @@ - @@ -14,6 +13,7 @@ + diff --git a/examples/studies/test_saturated_pulses.xml b/examples/studies/test_saturated_pulses.xml index ee01be5e2f..6873167512 100644 --- a/examples/studies/test_saturated_pulses.xml +++ b/examples/studies/test_saturated_pulses.xml @@ -3,9 +3,12 @@ - + + + + @@ -19,7 +22,7 @@ - @@ -27,7 +30,7 @@ - diff --git a/examples/viewer.xml b/examples/viewer.xml index 3f3e93c97b..c7e8b9b596 100644 --- a/examples/viewer.xml +++ b/examples/viewer.xml @@ -3,12 +3,13 @@ - + + diff --git a/src/main/java/fact/calibrationservice/ConstantCalibService.java b/src/main/java/fact/calibrationservice/ConstantCalibService.java index 7b4951e4a0..a0fa572069 100644 --- a/src/main/java/fact/calibrationservice/ConstantCalibService.java +++ b/src/main/java/fact/calibrationservice/ConstantCalibService.java @@ -86,20 +86,20 @@ public void init() { config20141115.notUsablePixels.addAll(brokenDrsBoard20142015); // in the night of 2015-01-08, two pixels were broken additionally (729 & 750) - HardwareConfiguration config20150108 = new HardwareConfiguration(ZonedDateTime.of(2015, 01, 8, 12, 0, 0, 0, ZoneOffset.UTC)); + HardwareConfiguration config20150108 = new HardwareConfiguration(ZonedDateTime.of(2015, 1, 8, 12, 0, 0, 0, ZoneOffset.UTC)); config20150108.badPixels.addAll(badPixelsFromBeginning); config20150108.badPixels.addById(729); config20150108.badPixels.addById(750); config20150108.notUsablePixels.addAll(brokenDrsBoard20142015); // On 2015-01-09, pixel 729 recovered - HardwareConfiguration config20150109 = new HardwareConfiguration(ZonedDateTime.of(2015, 01, 9, 12, 0, 0, 0, ZoneOffset.UTC)); + HardwareConfiguration config20150109 = new HardwareConfiguration(ZonedDateTime.of(2015, 1, 9, 12, 0, 0, 0, ZoneOffset.UTC)); config20150109.badPixels.addAll(badPixelsFromBeginning); config20150109.badPixels.addById(750); config20150109.notUsablePixels.addAll(brokenDrsBoard20142015); // On 2015-01-31, pixel 750 recovered - HardwareConfiguration config20150131 = new HardwareConfiguration(ZonedDateTime.of(2015, 01, 31, 12, 0, 0, 0, ZoneOffset.UTC)); + HardwareConfiguration config20150131 = new HardwareConfiguration(ZonedDateTime.of(2015, 1, 31, 12, 0, 0, 0, ZoneOffset.UTC)); config20150131.badPixels.addAll(badPixelsFromBeginning); config20150131.notUsablePixels.addAll(brokenDrsBoard20142015); diff --git a/src/main/java/fact/datacorrection/InterpolatePixelArray.java b/src/main/java/fact/datacorrection/InterpolatePixelArray.java index b350cddb83..15e0566aa4 100644 --- a/src/main/java/fact/datacorrection/InterpolatePixelArray.java +++ b/src/main/java/fact/datacorrection/InterpolatePixelArray.java @@ -26,16 +26,16 @@ public class InterpolatePixelArray implements Processor { static Logger log = LoggerFactory.getLogger(InterpolatePixelArray.class); @Service(required = true, description = "The calibration service which provides the information about the bad pixels") - CalibrationService calibService; + public CalibrationService calibService; @Parameter(required = true, description = "The photoncharge key to work on") - private String inputKey = null; + public String inputKey = null; @Parameter(required = true, description = "The name of the interpolated photoncharge output") - private String outputKey = null; + public String outputKey = null; @Parameter(description = "The minimum number of neighboring pixels required for interpolation", defaultValue="3") - private int minPixelToInterpolate = 3; + public int minPixelToInterpolate = 3; FactPixelMapping pixelMap = FactPixelMapping.getInstance(); diff --git a/src/main/java/fact/extraction/BasicExtraction.java b/src/main/java/fact/extraction/BasicExtraction.java index 144e2d7f6b..bf042f83e2 100644 --- a/src/main/java/fact/extraction/BasicExtraction.java +++ b/src/main/java/fact/extraction/BasicExtraction.java @@ -2,15 +2,19 @@ import fact.Constants; import fact.Utils; +import fact.gainservice.GainService; import org.jfree.chart.plot.IntervalMarker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import stream.Data; import stream.Processor; import stream.annotations.Parameter; +import stream.annotations.Service; import stream.io.CsvStream; import stream.io.SourceURL; +import java.time.ZonedDateTime; + /** * This processor performs a basic extraction on the data array. It contains three steps: * 1. Calculates the position of the max amplitude in [startSearchWindow,startSearchWindow+rangeSearchWindow[ @@ -34,8 +38,8 @@ public class BasicExtraction implements Processor { @Parameter(required = true, description = "outputKey for the calculated photoncharge") public String outputKeyPhotonCharge = null; - @Parameter(required = false, description = "The url to the inputfiles for the gain calibration constants", defaultValue = "file:src/main/resources/defaultIntegralGains.csv") - public SourceURL url = null; + @Service(description = "Gain Service that delivers the integral gains") + public GainService gainService = null; @Parameter(required = false, description = "start slice of the search window for the max amplitude", defaultValue = "35") public int startSearchWindow = 35; @@ -52,15 +56,19 @@ public class BasicExtraction implements Processor { @Parameter(required = false, description = "minimal slice with valid values (we want to ignore slices below this value", defaultValue = "10") public int validMinimalSlice = 10; - double[] integralGains = null; - @Override public Data process(Data item) { Utils.mapContainsKeys(item, dataKey, "NROI"); - if (integralGains == null) { - integralGains = loadIntegralGainFile(url); + + double[] integralGains; + int[] unixTimeUTC = (int[]) item.get("UnixTimeUTC"); + if (unixTimeUTC == null) { + integralGains = gainService.getSimulationGains(); + } else { + ZonedDateTime timestamp = Utils.unixTimeUTCToZonedDateTime(unixTimeUTC); + integralGains = gainService.getGains(timestamp); } int roi = (Integer) item.get("NROI"); @@ -137,26 +145,4 @@ public double calculateIntegral(int px, int startingPosition, int integralSize, } return integral; } - - - public double[] loadIntegralGainFile(SourceURL inputUrl) { - double[] integralGains = new double[Constants.N_PIXELS]; - Data integralGainData = null; - try { - CsvStream stream = new CsvStream(inputUrl, " "); - stream.setHeader(false); - stream.init(); - integralGainData = stream.readNext(); - - for (int i = 0; i < Constants.N_PIXELS; i++) { - String key = "column:" + (i); - integralGains[i] = (Double) integralGainData.get(key); - } - return integralGains; - - } catch (Exception e) { - log.error("Failed to load integral Gain data: {}", e.getMessage()); - throw new RuntimeException(e); - } - } } diff --git a/src/main/java/fact/gainservice/GainService.java b/src/main/java/fact/gainservice/GainService.java new file mode 100644 index 0000000000..dbddd73456 --- /dev/null +++ b/src/main/java/fact/gainservice/GainService.java @@ -0,0 +1,150 @@ +package fact.gainservice; + +import fact.Constants; +import fact.io.hdureader.BinTable; +import fact.io.hdureader.BinTableReader; +import fact.io.hdureader.FITS; +import fact.io.hdureader.OptionalTypesMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import stream.Data; +import stream.annotations.Parameter; +import stream.io.CsvStream; +import stream.io.SourceURL; +import stream.service.Service; + + +import java.io.IOException; +import java.io.Serializable; +import java.net.URL; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Map; +import java.util.TreeMap; + +/** + * This Service provides gains for each pixel for a given timestamp + * It needs a fits file with a BinTable "Gain" which contains the columns "timestamp" and "gain" + * timestamp needs to be an ISO-8601 datetime string and "gain" needs to be a length 1440 double array + * with the gain values for each pixel. + * + * You can create this file using https://github.com/fact-project/spe_analysis + */ +public class GainService implements Service{ + + @Parameter(defaultValue = "classpath:/gains_20120503-20171103.fits.gz") + public URL gainFile = GainService.class.getResource("/gains_20120503-20171103.fits.gz"); + + TreeMap gains; + private double[] gainsSimulations = null; + + private static final Logger log = LoggerFactory.getLogger(GainService.class); + + /** + * Get the closest gain measurement for a given timestamp + * @param timestamp + * @return gain array for given timestamp + */ + public double[] getGains(ZonedDateTime timestamp) { + if (gains == null) { + try { + loadGains(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + Map.Entry ceiling = gains.ceilingEntry(timestamp); + Map.Entry floor = gains.floorEntry(timestamp); + + Duration diff; + double[] gain; + + if (ceiling == null) { + diff = Duration.between(floor.getKey(), timestamp).abs(); + gain = floor.getValue(); + } else { + if (floor == null) { + diff = Duration.between(ceiling.getKey(), timestamp).abs(); + gain = ceiling.getValue(); + } else { + Duration ceilingDiff = Duration.between(timestamp, ceiling.getKey()).abs(); + Duration floorDiff = Duration.between(timestamp, floor.getKey()).abs(); + + if (ceilingDiff.compareTo(floorDiff) < 0) { + diff = ceilingDiff; + gain = ceiling.getValue(); + } else { + diff = floorDiff; + gain = floor.getValue(); + } + } + } + + if (diff.toDays() >= 5) { + log.warn("Time difference to closest gain measurement is more than 5 days"); + } + return gain; + } + + + public double[] getSimulationGains() { + if (gainsSimulations == null) { + loadGainsSimulations(); + } + return gainsSimulations; + } + + private void loadGainsSimulations() { + double[] integralGains = new double[Constants.N_PIXELS]; + + SourceURL url = new SourceURL(GainService.class.getResource("/defaultIntegralGains.csv")); + try { + CsvStream stream = new CsvStream(url, " "); + stream.setHeader(false); + stream.init(); + Data integralGainData = stream.readNext(); + for (int i = 0; i < Constants.N_PIXELS; i++) { + String key = "column:" + (i); + integralGains[i] = (double) integralGainData.get(key); + } + gainsSimulations = integralGains; + } catch (Exception e) { + log.error("Failed to load integral Gain data: {}", e.getMessage()); + throw new RuntimeException(e); + } + } + + + void loadGains() throws Exception { + FITS fits = new FITS(gainFile); + + BinTable table = fits.getBinTableByName("Gain").orElseThrow( + () -> new IOException("Gain file has no BinTable 'Gain'") + ); + BinTableReader reader = BinTableReader.forBinTable(table); + + gains = new TreeMap<>(); + OptionalTypesMap row; + + while (reader.hasNext()) { + row = reader.getNextRow(); + String timestampString = row.getString("timestamp").orElseThrow( + () -> new RuntimeException("Column 'timestamp' not in row") + ); + + ZonedDateTime timestamp = LocalDateTime.parse(timestampString).atZone(ZoneOffset.UTC); + double[] gain = row.getDoubleArray("gain").orElseThrow( + () -> new RuntimeException("Column 'Gain' not in row") + ); + gains.put(timestamp, gain); + } + } + + + @Override + public void reset() { + gains = null; + } +} diff --git a/src/main/java/fact/io/hdureader/OptionalTypesMap.java b/src/main/java/fact/io/hdureader/OptionalTypesMap.java index d973ee5bd3..4cb2530dde 100644 --- a/src/main/java/fact/io/hdureader/OptionalTypesMap.java +++ b/src/main/java/fact/io/hdureader/OptionalTypesMap.java @@ -18,6 +18,13 @@ public class OptionalTypesMap extends ForwardingMap { private final Map delegateMap = new HashMap<>(); + public Optional getString (K key) { + try { + return Optional.ofNullable((String) delegate().get(key)); + } catch (ClassCastException e) { + return Optional.empty(); + } + } /** * Get the value for the given key if it exists and the value can be cast to Short. diff --git a/src/main/resources/analysis/extraction.xml b/src/main/resources/analysis/extraction.xml index f4f106c7de..9208a13a0f 100644 --- a/src/main/resources/analysis/extraction.xml +++ b/src/main/resources/analysis/extraction.xml @@ -3,7 +3,7 @@ dataKey="DataCalibrated" outputKeyMaxAmplPos="maxPos" outputKeyPhotonCharge="photoncharge" - url="${integralGainFile}" + gainService="gainService" startSearchWindow="${BasicExtraction.startSearchWindow}" rangeSearchWindow="${BasicExtraction.rangeSearchWindow}" rangeHalfHeightWindow="${BasicExtraction.rangeHalfHeigthWindow}" @@ -35,7 +35,7 @@ dataKey="DataCalibrated" outputKeyMaxAmplPos="maxPos" outputKeyPhotonCharge="photoncharge" - url="${integralGainFile}" + gainService="gainService" startSearchWindow="${BasicExtraction.startSearchWindow}" rangeSearchWindow="${BasicExtraction.rangeSearchWindow}" rangeHalfHeightWindow="${BasicExtraction.rangeHalfHeigthWindow}" diff --git a/src/main/resources/gains_20120503-20171103.fits.gz b/src/main/resources/gains_20120503-20171103.fits.gz new file mode 100644 index 0000000000..782f4c7ae0 Binary files /dev/null and b/src/main/resources/gains_20120503-20171103.fits.gz differ diff --git a/src/test/java/fact/features/BasicExtractionTest.java b/src/test/java/fact/features/BasicExtractionTest.java index 2315331107..ed71553e61 100644 --- a/src/test/java/fact/features/BasicExtractionTest.java +++ b/src/test/java/fact/features/BasicExtractionTest.java @@ -2,6 +2,7 @@ import fact.datacorrection.DrsCalibration; import fact.extraction.BasicExtraction; +import fact.gainservice.GainService; import fact.io.FITSStreamTest; import fact.io.hdureader.FITSStream; import org.junit.Before; @@ -33,7 +34,7 @@ public void setup() throws Exception { extraction.dataKey = "test"; extraction.outputKeyMaxAmplPos = positionsKey; extraction.outputKeyPhotonCharge = photonChargeKey; - extraction.url = new SourceURL(FITSStreamTest.class.getResource("/defaultIntegralGains.csv")); + extraction.gainService = new GainService(); } @Test diff --git a/src/test/java/fact/gainservice/GainServiceTest.java b/src/test/java/fact/gainservice/GainServiceTest.java new file mode 100644 index 0000000000..21fe68cb35 --- /dev/null +++ b/src/test/java/fact/gainservice/GainServiceTest.java @@ -0,0 +1,37 @@ +package fact.gainservice; + +import org.junit.Test; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.TreeMap; + +import static org.junit.Assert.assertEquals; + +public class GainServiceTest { + + @Test + public void testLoadGains () throws Exception { + + GainService gainService = new GainService(); + + gainService.loadGains(); + + } + + @Test + public void testGetNearest () { + GainService gainService = new GainService(); + + gainService.gains = new TreeMap<>(); + gainService.gains.put(ZonedDateTime.of(2017, 1, 1, 22, 0, 0, 0, ZoneOffset.UTC), new double[]{1}); + gainService.gains.put(ZonedDateTime.of(2017, 1, 1, 22, 30, 0, 0, ZoneOffset.UTC), new double[]{2}); + + double[] gains = gainService.getGains(ZonedDateTime.of(2017, 1, 1, 22, 10, 0, 0, ZoneOffset.UTC)); + assertEquals(1, gains[0], 1e-12); + + gains = gainService.getGains(ZonedDateTime.of(2017, 1, 1, 22, 20, 0, 0, ZoneOffset.UTC)); + assertEquals(2, gains[0], 1e-12); + + } +} diff --git a/src/test/java/fact/parameter/ParameterTest.java b/src/test/java/fact/parameter/ParameterTest.java index 7e6e5c4e0f..52bb22b572 100644 --- a/src/test/java/fact/parameter/ParameterTest.java +++ b/src/test/java/fact/parameter/ParameterTest.java @@ -3,10 +3,12 @@ import fact.calibrationservice.ConstantCalibService; import fact.cleaning.TwoLevelTimeMedian; import fact.datacorrection.DrsCalibration; +import fact.datacorrection.InterpolatePixelArray; import fact.extraction.BasicExtraction; import fact.extraction.RisingEdgeForPositions; import fact.features.HillasParameters; import fact.features.source.SourcePosition; +import fact.gainservice.GainService; import fact.io.FITSStreamTest; import fact.io.hdureader.FITSStream; import org.junit.Before; @@ -53,12 +55,11 @@ public void setUp() throws Exception { stream.init(); item = stream.read(); } catch (Exception e) { - fail("could not start stream with test file"); e.printStackTrace(); + fail("could not start stream with test file"); } - URL drsUrl = FITSStreamTest.class - .getResource("/testDrsFile.drs.fits.gz"); + URL drsUrl = FITSStreamTest.class.getResource("/testDrsFile.drs.fits.gz"); DrsCalibration pr = new DrsCalibration(); pr.url = drsUrl; pr.outputKey = key; @@ -69,9 +70,15 @@ public void setUp() throws Exception { bE.dataKey = key; bE.outputKeyMaxAmplPos = positions; bE.outputKeyPhotonCharge = photonCharge; - bE.url = new SourceURL(FITSStreamTest.class.getResource("/defaultIntegralGains.csv")); + bE.gainService = new GainService(); bE.process(item); + InterpolatePixelArray interpolatePhotoncharge = new InterpolatePixelArray(); + interpolatePhotoncharge.calibService = new ConstantCalibService(); + interpolatePhotoncharge.inputKey = "photoncharge"; + interpolatePhotoncharge.outputKey = "photoncharge"; + interpolatePhotoncharge.process(item); + RisingEdgeForPositions pR = new RisingEdgeForPositions(); pR.dataKey = key; pR.amplitudePositionsKey = positions; @@ -90,7 +97,6 @@ public void setUp() throws Exception { poser.process(item); - HillasParameters dist = new HillasParameters(); dist.pixelSetKey = shower; dist.weightsKey = photonCharge; diff --git a/src/test/java/fact/parameter/PhotonChargeParameterTest.java b/src/test/java/fact/parameter/PhotonChargeParameterTest.java index 7bf6ccd97d..c3aa5cbda3 100644 --- a/src/test/java/fact/parameter/PhotonChargeParameterTest.java +++ b/src/test/java/fact/parameter/PhotonChargeParameterTest.java @@ -1,6 +1,7 @@ package fact.parameter; import fact.extraction.BasicExtraction; +import fact.gainservice.GainService; import fact.io.FITSStreamTest; import org.junit.Rule; import org.junit.Test; @@ -30,7 +31,7 @@ public void testValidParameter() throws Exception { extraction.dataKey = key; extraction.outputKeyMaxAmplPos = positions; extraction.outputKeyPhotonCharge = outputKey; - extraction.url = new SourceURL(FITSStreamTest.class.getResource("/defaultIntegralGains.csv")); + extraction.gainService = new GainService(); extraction.process(item); assertTrue("Expecteds output not in data item but it should be there", item.containsKey(outputKey)); // item.remove(outputKey);