/*-
* Copyright (c) 2012 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.eclipse.dawnsci.analysis.api.fitting.functions.IParameter;
import org.eclipse.january.dataset.DoubleDataset;
/**
* Class that wraps the double-step function:
*
* <pre>
* _______
* | |
* ____| |_______
* _____| |_________
*
* </pre>
*
*
* Parameters are
* <ol>
* <li>base</li>
* <li>start of outer step</li>
* <li>end of outer step</li>
* <li>step from base</li>
* <li>step from outer</li>
* <li>width of inner step as fraction of outer step</li>
* <li>offset of inner step as fraction of remaining outer step (0 = left justified, 1 = right)</li>
* </ol>
*/
public class Step extends AFunction {
private static String NAME = "Step";
private static String DESC = "A step function with inner and outer levels."
+ "\n y(x) = base, if x < pmin or x > pmax,"
+ "\n = base + outer + inner, if x in [left, right),"
+ "\n = base + outer, otherwise"
+ "\nwhere left = pmin + offset*(pmax - pmin - width), width = (pmax - pmin)*frac"
+ "\nand right = left + width.";
private static final String[] PARAM_NAMES = new String[] { "base", "pmin", "pmax", "outer", "inner",
"frac", "offset" };
public Step() {
super(new double[]{0,0,0,0,0,0,0});
}
public Step(IParameter... params) {
super(params);
}
/**
* Constructor that allows for the positioning of all the parameter bounds
*
* @param minY
* minimum Y value
* @param maxY
* maximum Y value
* @param minX1
* minimum X1 value
* @param maxX1
* maximum X1 value
* @param minX2
* minimum X2 value
* @param maxX2
* maximum X2 value
* @param minH1
* minimum height of outer peak/trough
* @param maxH1
* maximum height outer peak/trough
* @param minH2
* minimum height of inner peak/trough
* @param maxH2
* maximum height inner peak/trough
* @param minW
* minimum proportional width of inner peak/trough ( 0 < width < 1 )
* @param maxW
* maximum proportional width of inner peak/trough ( 0 < width < 1 )
* @param minPos
* minimum position of inner peak/trough with respect to outer one ( 0 (left) <= pos <= 1 (right))
* @param maxPos
* maximum position of inner peak/trough with respect to outer one ( 0 (left) <= pos <= 1 (right))
*/
public Step(double minY, double maxY, double minX1, double maxX1, double minX2, double maxX2, double minH1,
double maxH1, double minH2, double maxH2, double minW, double maxW, double minPos, double maxPos) {
super(7);
IParameter p;
p = getParameter(0);
p.setLowerLimit(minY);
p.setUpperLimit(maxY);
p.setValue((minY + maxY) / 2.0);
p = getParameter(1);
p.setLowerLimit(minX1);
p.setUpperLimit(maxX1);
p.setValue((minX1 + maxX1) / 2.0);
p = getParameter(2);
p.setLowerLimit(minX2);
p.setUpperLimit(maxX2);
p.setValue((minX2 + maxX2) / 2.0);
p = getParameter(3);
p.setLowerLimit(minH1);
p.setUpperLimit(maxH1);
p.setValue((minH1 + maxH1) / 2.0);
p = getParameter(4);
p.setLowerLimit(minH2);
p.setUpperLimit(maxH2);
p.setValue((minH2 + maxH2) / 2.0);
p = getParameter(5);
p.setLowerLimit(minW);
p.setUpperLimit(maxW);
p.setValue((minW + maxW) / 2.0);
p = getParameter(6);
p.setLowerLimit(minPos);
p.setUpperLimit(maxPos);
p.setValue((minPos + maxPos) / 2.0);
}
@Override
protected void setNames() {
setNames(NAME, DESC, PARAM_NAMES);
}
private transient double base, pmin, pmax, width, start, outer, inner;
private void calcCachedParameters() {
base = getParameterValue(0);
pmin = getParameterValue(1);
pmax = getParameterValue(2);
// Calculate width and start of inner peak
width = (pmax - pmin) * getParameterValue(5);
start = pmin + (pmax - pmin - width) * getParameterValue(6);
outer = base + getParameterValue(3);
inner = outer + getParameterValue(4);
setDirty(false);
}
@Override
public double val(double... values) {
if (isDirty())
calcCachedParameters();
double position = values[0];
// Test if outside outer peak
if (position <= pmin || position >= pmax) {
return base;
}
// Inside outer peak; now test if outside inner peak
if (position <= start || position >= start + width) {
return outer;
}
// Inside outer and inner peak
return inner;
}
@Override
public void fillWithValues(DoubleDataset data, CoordinatesIterator it) {
if (isDirty())
calcCachedParameters();
it.reset();
double[] coords = it.getCoordinates();
int i = 0;
double[] buffer = data.getData();
while (it.hasNext()) {
double position = coords[0];
double x;
if (position <= pmin || position >= pmax) { // Test if outside outer peak
x = base;
} else if (position <= start || position >= start + width) { // Inside outer peak; now test if outside inner peak
x = outer;
} else { // Inside outer and inner peak
x = inner;
}
buffer[i++] = x;
}
}
}