/*- * Copyright (c) 2014 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.fitting.functions; import org.apache.commons.math3.analysis.interpolation.LinearInterpolator; import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction; import org.apache.commons.math3.stat.regression.SimpleRegression; import org.eclipse.dawnsci.analysis.api.fitting.functions.IDataBasedFunction; import org.eclipse.dawnsci.analysis.api.fitting.functions.IParameter; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetUtils; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.IDataset; import uk.ac.diamond.scisoft.analysis.fitting.functions.AFunction; import uk.ac.diamond.scisoft.analysis.fitting.functions.CoordinatesIterator; import uk.ac.diamond.scisoft.analysis.optimize.ApachePolynomial; public class SmoothGoldEdgeFunction extends AFunction implements IDataBasedFunction { /** * */ private static final long serialVersionUID = 1L; private static final String NAME = "Smooth Gold Edge"; private static final String DESC = "y(x) = Polyline with tails"; private static final String[] PARAM_NAMES = new String[]{"smoothing", "tail_proportion"}; private static final double[] PARAMS = new double[]{5, 0.2}; Dataset xds; Dataset yds; private transient IDataset smoothed; private transient PolynomialSplineFunction polySplineFunction; private transient SimpleRegression lowerFit; private transient SimpleRegression upperFit; public SmoothGoldEdgeFunction() { this(PARAMS); } /** * Constructor which takes the three properties required, which are * * <pre> * Parameter 1 - Position * Parameter 2 - FWHM (full width at half maximum) * Parameter 3 - Area * </pre> * * @param params */ public SmoothGoldEdgeFunction(double... params) { super(PARAMS.length); // make sure that there are 2 parameters, otherwise, throw a sensible error if (params.length != PARAMS.length) throw new IllegalArgumentException("A SmoothGoldEdgeFunction requires 2 parameters, and it has only been given "+params.length); setParameterValues(params); } public SmoothGoldEdgeFunction(IParameter... params) { super(PARAMS.length); if (params.length != PARAMS.length) throw new IllegalArgumentException("A SmoothGoldEdgeFunction requires 2 parameters, and it has only been given "+params.length); setParameters(params); } @Override protected void setNames() { setNames(NAME, DESC, PARAM_NAMES); } @Override public double val(double... values) { // TODO Auto-generated method stub return 0; } @Override public void setData(IDataset x, IDataset data) { this.xds = DatasetUtils.convertToDataset(x); this.yds = DatasetUtils.convertToDataset(data); try { // Smooth the data by the real ammount for the smoothed section of the process this.smoothed = ApachePolynomial.getPolynomialSmoothed(xds, yds, (int) Math.round(getParameterValue(0)), 3); // Fit a polyline to this to allow for easy interpolation IDataset arg2 = DatasetUtils.cast(smoothed, Dataset.FLOAT64); this.polySplineFunction = new LinearInterpolator().interpolate(DatasetUtils.cast(DoubleDataset.class, xds).getData(), ((DoubleDataset)arg2).getData()); lowerFit = new SimpleRegression(); double lowerProp = xds.getShape()[0]*getParameterValue(1); for (int i = 0; i < lowerProp; i++ ) { lowerFit.addData(xds.getDouble(i), yds.getDouble(i)); } lowerFit.regress(); upperFit = new SimpleRegression(); double upperProp = xds.getShape()[0]*(1.0-getParameterValue(1)); for (int i = xds.getShape()[0]-1; i > upperProp; i-- ) { upperFit.addData(xds.getDouble(i), yds.getDouble(i)); } upperFit.regress(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void fillWithValues(DoubleDataset data, CoordinatesIterator it) { it.reset(); double[] coords = it.getCoordinates(); int i = 0; double[] buffer = data.getData(); double midpoint = (double) xds.mean(); if (lowerFit == null || upperFit == null) return; double lowerPredict = lowerFit.predict(xds.getDouble(0)); double lowerEndValue = yds.getDouble(0); double lowerMatch = lowerPredict - lowerEndValue; double upperPredict = upperFit.predict(xds.getDouble(xds.getShape()[0]-1)); double upperEndValue = yds.getDouble(yds.getShape()[0]-1); double upperMatch = upperPredict - upperEndValue; while (it.hasNext()) { double pos = coords[0]; try { buffer[i] = polySplineFunction.value(pos); } catch (Exception e) { if (pos < midpoint) { buffer[i] = lowerFit.predict(pos) - lowerMatch; } else { buffer[i] = upperFit.predict(pos) - upperMatch; } } i++; } } }