/*-
* Copyright (c) 2015 Gero Flucke, DESY.
*
* 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 for a square variant of the Lorentzian function <br>
* that has smaller tails: <br>
* f(x; N, G, x0) = 4*N/(G*pi) * 1/(1 + ( ( x-x0 ) / (G/2) )^2 )^2 <br>
* where : <br>
* * N is the peak area (= height * G/2 * pi/2),<br>
* * x0 is the position of the peak (posn) and <br>
* * G is a width parameter, related to the full width at half maximum
* via G = fwhm / sqrt(sqrt(2.) - 1.).
*
* Literature:
* Gibaud et al., J. Phys. Condens. Matter - 10.1088/0953-8984/7/14/005
* Langridge et al., Phys Rev. B, 49, 12022 - 10.1103/PhysRevB.49.12022
* Christianson et al., Phys. Rev. B, 66, 174105 - 10.1103/PhysRevB.66.174105
*/
public class LorentzianSqr extends APeak {
private static final String NAME = "LorentzianSqr";
private static final String DESC = "Similar to a Lorentzian, but smaller tails."
+ "\n y(x) = A / [1 + ((x-posn)/a)^2 ]^2"
+ "\nwhere fwhm = 2*a*sqrt(sqrt(2) - 1), and area = pi * a * A / 2." + PEAK_DESC;
private static final double[] PARAMS = new double[] { 0, 0, 0 };
public LorentzianSqr() {
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 LorentzianSqr(double... params) {
super(params);
}
public LorentzianSqr(IParameter... params) {
super(params);
}
public LorentzianSqr(IdentifiedPeak peakParameters) {
super(peakParameters);
}
/**
* Constructor which takes more sensible values for the parameters, which also incorporates the limits which they
* can be in, reducing the overall complexity of the problem
*
* @param minPeakPosition
* The minimum value of the peak position
* @param maxPeakPosition
* The maximum value of the peak position
* @param maxFWHM
* Full width at half maximum
* @param maxArea
* The maximum area of the peak
*/
public LorentzianSqr(double minPeakPosition, double maxPeakPosition, double maxFWHM, double maxArea) {
super(PARAMS.length);
internalSetPeakParameters(minPeakPosition, maxPeakPosition, maxFWHM, maxArea);
}
@Override
protected void setNames() {
setNames(NAME, DESC, PARAM_NAMES);
}
private transient double halfWidthPar, pos; // 'height' already declared in APeak
// conversion between FWHM and parameter G in function:
private static final double CONST = 0.5/Math.sqrt(Math.sqrt(2.0) - 1.);
@Override
protected void calcCachedParameters() {
pos = getParameterValue(POSN);
halfWidthPar = getParameterValue(FWHM) * CONST;
height = getParameterValue(AREA) / (0.5 * Math.PI * halfWidthPar);
setDirty(false);
}
@Override
public double val(double... values) {
if (isDirty())
calcCachedParameters();
double dist = (values[0] - pos) / halfWidthPar;
double denominatorSqrt = (dist * dist + 1);
return height / (denominatorSqrt * denominatorSqrt);
}
@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 dist = (coords[0] - pos) / halfWidthPar;
double denominatorSqrt = (dist * dist + 1);
buffer[i++] = height / (denominatorSqrt * denominatorSqrt);
}
}
}