/*- * Copyright (c) 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.operations.saxs; import org.eclipse.january.DatasetException; // Imports from java import java.net.URL; import java.io.IOException; // Imports from org.apache import org.apache.commons.math3.analysis.UnivariateFunction; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; import org.apache.commons.math3.analysis.interpolation.SplineInterpolator; import org.apache.commons.math3.analysis.interpolation.UnivariateInterpolator; // Imports from org.eclipse.core import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.FileLocator; // Imports from org.eclipse.january import org.eclipse.january.IMonitor; import org.eclipse.january.dataset.Slice; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.IDataset; import org.eclipse.january.MetadataException; import org.eclipse.january.dataset.DatasetUtils; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.metadata.AxesMetadata; import org.eclipse.january.metadata.MetadataFactory; // Imports from org.eclipse.dawnsci import org.eclipse.dawnsci.analysis.api.processing.OperationData; import org.eclipse.dawnsci.analysis.api.processing.OperationRank; import org.eclipse.dawnsci.analysis.api.io.ScanFileHolderException; import org.eclipse.dawnsci.analysis.api.processing.PlotAdditionalData; import org.eclipse.dawnsci.analysis.api.processing.OperationException; import org.eclipse.dawnsci.analysis.dataset.operations.AbstractOperation; // Imports from org.osgi import org.osgi.framework.Bundle; // Imports from uk.ac.diamond import uk.ac.diamond.scisoft.analysis.io.DatLoader; import uk.ac.diamond.scisoft.analysis.io.DataHolder; import uk.ac.diamond.scisoft.analysis.io.LoaderFactory; // @author Tim Snow // The operation for a DAWN process to calculate the intensity scaling value between gathered data from a known standard // As in: F.Ilavsky G. Long J. Quintana A. Allen & P. Jemian, Metallurgical and Materials Transactions A, 2010, 41, 1151-1158, DOI: 10.1007/s11661-009-9950-x @PlotAdditionalData(onInput = false, dataName = "Calibrant") public class AbsoluteIntensityCalibrationOperation extends AbstractOperation<AbsoluteIntensityCalibrationModel, OperationData> { // Let's give this process an ID tag @Override public String getId() { return "uk.ac.diamond.scisoft.analysis.processing.operations.saxs.AbsoluteIntensityCalibrationOperation"; } // Before we start, let's make sure we know how many dimensions of data are going in... @Override public OperationRank getInputRank() { return OperationRank.ONE; } // ...and out @Override public OperationRank getOutputRank() { return OperationRank.ONE; } // Now let's define the main calculation process @Override public OperationData process(IDataset inputDataset, IMonitor monitor) throws OperationException { // We should be returning: // 1) The data // 2) The calibration lineplot // 3) The scaling factor between 1 & 2 // First we shall set up some variables for the calibrant DoubleDataset calibrantQdataset = null; DoubleDataset calibrantIdataset = null; // and input datasets DoubleDataset inputQdataset = null; DoubleDataset inputIdataset = null; // alongside a home for the final scaling factor. double absoluteScalingFactor = 0.00; double absoluteScalingFactorStdDev = 0.00; // Next we shall populate the calibrant dataset try { if (model.getUseInternalCalibrant() == true) { // By opening the default file Bundle bundle = Platform.getBundle("uk.ac.diamond.scisoft.analysis.processing"); URL calibrantFileURL = bundle.getEntry("data/GlassyCarbon_T.dat"); DataHolder calibrantData = (DataHolder) LoaderFactory.getData(FileLocator.resolve(calibrantFileURL).getPath()); // and extracting out the relevant datasets calibrantQdataset = (DoubleDataset) calibrantData.getDataset(0).squeezeEnds(); calibrantIdataset = (DoubleDataset) calibrantData.getDataset(1).squeezeEnds(); } else { // Or by opening a different file String filePath = model.getAbsoluteScanFilePath(); DataHolder calibrantData = (DataHolder) LoaderFactory.getData(filePath); // and extracting out the relevant datasets calibrantQdataset = (DoubleDataset) calibrantData.getDataset(0).squeezeEnds(); calibrantIdataset = (DoubleDataset) calibrantData.getDataset(1).squeezeEnds(); } } // Performing error handling where required catch (IOException ioError) { throw new OperationException(this, ioError); } // Throwing the appropriate OperationExceptions catch (ScanFileHolderException fileError) { throw new OperationException(this, fileError); } catch (Exception loaderFactoryError) { throw new OperationException(this, loaderFactoryError); } // Then we shall populate the input datasets inputIdataset = (DoubleDataset) inputDataset.getSlice(new Slice()).squeeze(); try { inputQdataset = (DoubleDataset) DatasetUtils.sliceAndConvertLazyDataset(inputDataset.getFirstMetadata(AxesMetadata.class).getAxes()[0]); } catch (DatasetException noAxisException) { throw new OperationException(this, noAxisException); } // Then create an interpolator for where we need data but don't have any UnivariateInterpolator splineIinterpolator = new SplineInterpolator(); UnivariateFunction calibrantInterpolator = splineIinterpolator.interpolate((double[])calibrantQdataset.getBuffer(),(double[])calibrantIdataset.getBuffer()); // Now we'll get the radial range double[] radialRange = model.getRadialRange(); // Or create our own if need be from the min/max values available if (radialRange == null) { radialRange = new double[2]; radialRange[0] = Math.max(calibrantQdataset.min().doubleValue(), inputQdataset.min().doubleValue()); radialRange[1] = Math.min(calibrantQdataset.max().doubleValue(), inputQdataset.min().doubleValue()); } // And then define the minimum and maximum q values and indexes double qMin = Math.max(calibrantQdataset.min().doubleValue(), radialRange[0]); double qMax = Math.min(calibrantQdataset.max().doubleValue(), radialRange[1]); int inputQStart = Math.min(inputQdataset.getSize() - 1, DatasetUtils.findIndexGreaterThanOrEqualTo(inputQdataset, qMin)); int inputQStop = Math.min(inputQdataset.getSize() - 1, DatasetUtils.findIndexGreaterThanOrEqualTo(inputQdataset, qMax)); // Then create a home for the statistics SummaryStatistics stats = new SummaryStatistics(); // Then find the correlation between the calibrant and the data for (int loopIter = inputQStart; loopIter <= inputQStop; loopIter++) { // Get the ratio between the calibrant and real data's values if (inputIdataset.getDouble(loopIter) != 0) { stats.addValue(calibrantInterpolator.value(inputQdataset.getDouble(loopIter)) / inputIdataset.getDouble(loopIter)); } } // Then we'll get out the statistics we care about absoluteScalingFactor = stats.getMean(); absoluteScalingFactorStdDev = stats.getStandardDeviation(); // Now we can create a home for the scaling factor and standard deviation Dataset absoluteScalingFactorDataset = DatasetFactory.zeros(1); Dataset absoluteScalingFactorErrorDataset = DatasetFactory.zeros(1); // Then fill them with descriptive titles! String datasetTitle = "Scaling Factor is " + Double.toString(absoluteScalingFactor); absoluteScalingFactorDataset.setName(datasetTitle); absoluteScalingFactorDataset.set(absoluteScalingFactor, 0); String errorDatasetTitle = "Scaling Standard Deviation is " + Double.toString(absoluteScalingFactorStdDev); absoluteScalingFactorErrorDataset.setName(errorDatasetTitle); absoluteScalingFactorErrorDataset.set(absoluteScalingFactorStdDev, 0); // Also, sneakily, update the UI model.setScalingFactor(absoluteScalingFactor); model.setScalingFactorError(absoluteScalingFactorStdDev); // Now we create a dataset for the calibrant data AxesMetadata axisMetadata = null; // Which has to be passed through a try/catch statement try { axisMetadata = MetadataFactory.createMetadata(AxesMetadata.class, 1); axisMetadata.addAxis(0, calibrantQdataset); } catch (MetadataException metadataError) { throw new OperationException(this, metadataError); } // Then shave down, and correct, the output dataset DoubleDataset outputIdataset = (DoubleDataset) inputIdataset.getSlice(new Slice(inputQStart, inputQStop)); outputIdataset = outputIdataset.imultiply(absoluteScalingFactor); // Now we can rework the calibrant data for plotting IDataset calibrantDataset = DatasetFactory.createFromObject(calibrantIdataset); calibrantDataset.setMetadata(axisMetadata); calibrantDataset.setName("Calibrant"); // Then we can return EVERYTHING return new OperationData(outputIdataset, calibrantDataset, absoluteScalingFactorDataset, absoluteScalingFactorErrorDataset); } }