/*- * Copyright 2016 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.processing.test; import static org.junit.Assert.*; import org.eclipse.dawnsci.analysis.api.processing.OperationData; import org.eclipse.dawnsci.analysis.api.processing.OperationRank; import org.eclipse.dawnsci.analysis.dataset.operations.AbstractOperation; import org.eclipse.dawnsci.analysis.dataset.slicer.SliceFromSeriesMetadata; import org.eclipse.dawnsci.analysis.dataset.slicer.SliceInformation; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DatasetUtils; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.Maths; import org.eclipse.january.dataset.Slice; import org.eclipse.january.dataset.SliceND; import org.junit.Before; import org.junit.Test; import uk.ac.diamond.scisoft.analysis.processing.operations.oned.InterpolateMissingDataModel; import uk.ac.diamond.scisoft.analysis.processing.operations.oned.InterpolateMissingDataOperation; public class MissingDataTest { private Dataset fullSine; @Before public void setUp() throws Exception { // Make sinus data fullSine = Maths.sin(Maths.multiply(2*Math.PI, DatasetFactory.createRange(DoubleDataset.class, 0.0, 1.0, 0.01))); } @Test public void testProcess() { int start = 23, stop = 28, step = 1; Slice missingSlice = new Slice(start, stop, step); // positive infinity Dataset infSine = fullSine.clone(); infSine.setSlice(Double.POSITIVE_INFINITY, missingSlice); infSine.addMetadata(new SliceFromSeriesMetadata(new SliceInformation(new SliceND(infSine.getShape()), new SliceND(infSine.getShape()), new SliceND(infSine.getShape()), infSine.getShape(), 1, 1))); // Missing data indicator double mdi = 2e30; Dataset mdiSine = fullSine.clone(); mdiSine.setSlice(mdi, missingSlice); mdiSine = InterpolateMissingDataOperation.interpolateMissingData(mdiSine, mdi); mdiSine.addMetadata(new SliceFromSeriesMetadata(new SliceInformation(new SliceND(infSine.getShape()), new SliceND(infSine.getShape()), new SliceND(infSine.getShape()), infSine.getShape(), 1, 1))); // What the answer should be Dataset interpolSine = fullSine.clone(); for (int i = start; i < stop; i+=step) { interpolSine.set((i-start+1) * (fullSine.getDouble(stop) - fullSine.getDouble(start-1)) / (stop - (start-1)) + fullSine.getDouble(start-1), i); } AbstractOperation<InterpolateMissingDataModel, OperationData> theOp = new InterpolateMissingDataOperation(); theOp.setModel(new InterpolateMissingDataModel()); Dataset processedInfSine = DatasetUtils.convertToDataset(theOp.execute(infSine, null).getData()); checkAllElements(interpolSine, processedInfSine, "inifity"); AbstractOperation<InterpolateMissingDataModel, OperationData> theOpWithMDI = new InterpolateMissingDataOperation(); theOpWithMDI.setModel(new FakeInterpolateMissingDataModel()); Dataset processedMDISine = DatasetUtils.convertToDataset(theOpWithMDI.execute(mdiSine, null).getData()); checkAllElements(interpolSine, processedMDISine, "inifity"); } @Test public void testGetId() { assertEquals("ID string has changed", "uk.ac.diamond.scisoft.analysis.processing.operations.oned.InterpolateMissingDataOperation", new InterpolateMissingDataOperation().getId()); } @Test public void testGetInputRank() { assertEquals("Input should be one dimensional", OperationRank.ONE, new InterpolateMissingDataOperation().getInputRank()); } @Test public void testGetOutputRank() { assertEquals("Output should be one dimensional", OperationRank.ONE, new InterpolateMissingDataOperation().getOutputRank()); } @Test public void testInterpolateMissingData() { // Lop off the top of the maximum: missing data around i=25 int start = 23, stop = 28, step = 1; Slice missingSlice = new Slice(start, stop, step); // positive infinity Dataset infSine = fullSine.clone(); infSine.setSlice(Double.POSITIVE_INFINITY, missingSlice); infSine = InterpolateMissingDataOperation.interpolateMissingData(infSine, null); // negative infinity Dataset minfSine = fullSine.clone(); minfSine.setSlice(Double.NEGATIVE_INFINITY, missingSlice); minfSine = InterpolateMissingDataOperation.interpolateMissingData(minfSine, null); // NaN Dataset nanSine = fullSine.clone(); nanSine.setSlice(Double.NaN, missingSlice); nanSine = InterpolateMissingDataOperation.interpolateMissingData(nanSine, null); // Missing data indicator double mdi = 2e30; Dataset mdiSine = fullSine.clone(); mdiSine.setSlice(mdi, missingSlice); mdiSine = InterpolateMissingDataOperation.interpolateMissingData(mdiSine, mdi); // What the answer should be Dataset interpolSine = fullSine.clone(); for (int i = start; i < stop; i+=step) { interpolSine.set((i-start+1) * (fullSine.getDouble(stop) - fullSine.getDouble(start-1)) / (stop - (start-1)) + fullSine.getDouble(start-1), i); } for (int i = 0; i < fullSine.getSize(); i++) { checkAllElements(interpolSine, infSine, "+infinity"); checkAllElements(interpolSine, minfSine, "-infinity"); checkAllElements(interpolSine, nanSine, "NaN"); checkAllElements(interpolSine, mdiSine, "MDI"); } } private static void checkAllElements(Dataset expected, Dataset actual, String name) { for (int i = 0; i < expected.getSize(); i++) assertEquals("Error in " + name + " missing data interpolation", expected.getDouble(i), actual.getDouble(i), 1e-12); } @Test public void endpointReplacementTest() { int firstData = 10, lastData = 87; Dataset interpolatedStart = fullSine.clone(), missingStart = fullSine.clone(); Slice startSlice = new Slice(0, firstData); interpolatedStart.setSlice(fullSine.getDouble(firstData), startSlice); missingStart.setSlice(Double.NaN, startSlice); missingStart = InterpolateMissingDataOperation.interpolateMissingData(missingStart, null); Dataset interpolatedFinish = fullSine.clone(), missingFinish = fullSine.clone(); Slice finishSlice = new Slice(lastData+1, fullSine.getSize()); interpolatedFinish.setSlice(fullSine.getDouble(lastData), finishSlice); missingFinish.setSlice(Double.POSITIVE_INFINITY, finishSlice); missingFinish = InterpolateMissingDataOperation.interpolateMissingData(missingFinish, null); checkAllElements(interpolatedStart, missingStart, "starting"); checkAllElements(interpolatedFinish, missingFinish, "finishing"); } class FakeInterpolateMissingDataModel extends InterpolateMissingDataModel { @Override public Double getMdi() { return 2e30; } } }