uk.ac.diamond.scisoft.analysis.fitting.functions.FanoGaussian.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.diamond.scisoft.analysis.fitting.functions.FanoGaussian.java

Source

/*-
 * Copyright (c) 2015 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.complex.Complex;
import org.eclipse.dawnsci.analysis.api.fitting.functions.IParameter;
import org.eclipse.dawnsci.analysis.dataset.impl.DoubleDataset;

import uk.ac.diamond.scisoft.analysis.utils.Faddeeva;

/**
 * Class for a modified Fano profile convolved with a Gaussian
 */
public class FanoGaussian extends AFunction {
    private static final String NAME = "Fano-Gaussian";
    private static final String DESC = "A modified Fano profile convolved Gaussian function."
            + "\n    y(x) = Convolve(MFano(x; posn, l_fwhm, q), Gaussian(x; 0, g_fwhm, area)"
            + "\nwhere MFano(x; posn, fw, q) = (1/(pi*fw*(q^2-1))) * [ (q fw / 2 + (x-posn))^2 / (fw^2/4 + (x-posn)^2) - 1],"
            + "\nposn is the resonant position, l_fwhm is the Lorentzian full width, and q is the Fano parameter and > 1.";

    private static final String[] PARAM_NAMES = new String[] { "posn", "l_fwhm", "area", "g_fwhm", "q" };
    private static final int POSN = 0;
    private static final int FWHM = 1;
    private static final int AREA = 2;
    private static final int FWHMG = 3;
    private static final int FANO = 4;

    private static final double[] PARAMS = new double[] { 0, 1, 2, 1.5, 2 };
    private static final double Q_LOWER = 1.0 + Math.ulp(1.);

    public FanoGaussian() {
        this(PARAMS);
    }

    /**
     * Constructor which takes the five parameters required, which are
     * 
     * <pre>
     *     posn - resonant position
     *     l_fwhm - Lorentzian line width
     *     area - Gaussian area
     *     g_fwhm - Gaussian width
     *     q - Fano parameter, > 1
     * </pre>
     * 
     * @param params
     */
    public FanoGaussian(double... params) {
        super(PARAMS.length);
        if (params.length != PARAMS.length) {
            throw new IllegalArgumentException(
                    "A Fano-Gaussian function requires 5 parameters, and it has been given " + params.length);
        }

        if (params[FANO] <= 1) {
            throw new IllegalArgumentException("Fano parameter must be greater than 1");
        }
        setParameterValues(params);
        getParameter(FWHM).setLowerLimit(0.0);
        getParameter(AREA).setLowerLimit(0.0);
        getParameter(FWHMG).setLowerLimit(0.0);
        getParameter(FANO).setLowerLimit(Q_LOWER);
    }

    public FanoGaussian(IParameter... params) {
        super(PARAMS.length);
        if (params.length != PARAMS.length) {
            throw new IllegalArgumentException(
                    "A Fano-Gaussian function requires 5 parameters, and it has been given " + params.length);
        }

        if (params[FANO].getValue() < 1) {
            throw new IllegalArgumentException("Fano parameter must be greater than 1");
        }
        setParameters(params);
        getParameter(FWHM).setLowerLimit(0.0);
        getParameter(AREA).setLowerLimit(0.0);
        getParameter(FWHMG).setLowerLimit(0.0);
        getParameter(FANO).setLowerLimit(Q_LOWER);
    }

    @Override
    protected void setNames() {
        setNames(NAME, DESC, PARAM_NAMES);
    }

    private static final double CONST = Math.sqrt(8 * Math.log(2.));

    private transient double r, ft, fr, fq, zi;

    protected void calcCachedParameters() {
        r = getParameterValue(POSN);
        double l = getParameterValue(FWHM) / 2.;
        double sigma = getParameterValue(FWHMG) / CONST;
        if (sigma < 5 * Double.MIN_NORMAL) { // fix Lorentzian limit
            sigma = 10 * Double.MIN_NORMAL;
        }
        fr = Math.sqrt(0.5) / sigma;
        zi = fr * l;
        ft = fr * getParameterValue(AREA) / Math.sqrt(Math.PI);
        double q = getParameterValue(FANO);
        fq = 2 * q / (q * q - 1);
        setDirty(false);
    }

    @Override
    public double val(double... values) {
        if (isDirty()) {
            calcCachedParameters();
        }

        Complex z = new Complex(fr * (values[0] - r), zi);
        Complex w = Faddeeva.w(z, 0);

        double result = ft * (w.getReal() + fq * w.getImaginary());
        return result;
    }

    @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()) {
            Complex z = new Complex(fr * (coords[0] - r), zi);
            Complex w = Faddeeva.w(z, 0);

            buffer[i++] = ft * (w.getReal() + fq * w.getImaginary());
        }

    }
}