/*-
* Copyright 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.xpdf;
import java.util.stream.IntStream;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.IndexIterator;
import org.eclipse.january.dataset.Maths;
/**
* Performs the q² integrals.
* <p>
* Performs the q² integrals required to calculate total scattering, having had
* the momentum transfer array and the beam energy set.
*
* @author Timothy Spain timothy.spain@diamond.ac.uk
*
*/
public class XPDFQSquaredIntegrator {
private Dataset q, dq;
private XPDFElectronCrossSections eXSections;
/**
* Empty constructor.
*/
public XPDFQSquaredIntegrator() {
q = null;
dq = null;
eXSections = null;
}
/**
* Constructor using the coordinates object.
* @param coordinates
*/
public XPDFQSquaredIntegrator(XPDFCoordinates coordinates) { //Dataset twoTheta, XPDFBeamData beamData) {
q = coordinates.getQ();
dq = coordinates.getQIncrement();
// q = beamData.getQFromTwoTheta(twoTheta);
eXSections = new XPDFElectronCrossSections();
eXSections.setCoordinates(coordinates);
// eXSections.setAngles(twoTheta);
// eXSections.setBeamEnergy(beamData.getBeamEnergy());
}
/**
* Copy constructor.
* @param qq
* object to be copied.
*/
public XPDFQSquaredIntegrator(XPDFQSquaredIntegrator qq) {
this.q = qq.q;
this.dq = qq.dq;
this.eXSections = (qq.eXSections != null) ? qq.eXSections : null;
}
//
/**
* Calculates the q² integral.
* <p>
* Calculate an integral over q², given a function and some angles.
* @param fn
* the function to be integrated.
* @return the integral over q².
*/
public double qSquaredIntegral(Dataset fn) {
// Dataset dq = XPDFQSquaredIntegrator.differentiate1DDataset(q);
double integral;
if (fn.getShape().length == 1) {
double dqScalar = dq.getDouble(0);
Dataset integrand = Maths.multiply(Maths.multiply(Maths.multiply(q, q), fn), dqScalar);
integral = quadrate1DDataset(integrand);
} else {
// Dataset integrand = Maths.multiply(Maths.multiply(Maths.multiply(q, q), fn), dq);
// integral = quadrate2DDataset(integrand);
// Integrate by the 2D rectangle rule, summing values as they are calculated
// using Java 8 streams, in parallel, (for now)
integral = IntStream.range(0, fn.getSize()).parallel().mapToDouble(i -> fn.getElementDoubleAbs(i) * q.getElementDoubleAbs(i) * q.getElementDoubleAbs(i) * dq.getElementDoubleAbs(i)).sum();
}
return integral;
}
/**
* Calculates q² integral of the ratios of a function and the Thomson
* scattering cross-section.
* @param fn
* the function to be integrated and used as the numerator.
* @return the ratio of the q² integrals of the given function and the
* Thomson scattering cross-section.
*/
public double ThomsonIntegral(Dataset fn) {
double qqIntegral = qSquaredIntegral(Maths.divide(fn, eXSections.getThomsonCrossSection()));
return qqIntegral;
}
// TODO: a more sophisticated quadrature formula than the rectangle rule
/**
* Calculates the quadrature of a function.
* @param integrand
* integrand to be calculated.
* @return quadrature of the integrand over the stored angles.
*/
private static double quadrate1DDataset(Dataset integrand) {
return (double) integrand.sum();
}
// TODO: a more sophisticated quadrature formula than the rectangle rule
/**
* Calculates the 2 dimensional quadrature of a function.
* @param integrand
* integrand to be calculated.
* @return quadrature of the integrand over the pixel positions.
*/
@SuppressWarnings("unused")
private static double quadrate2DDataset(Dataset integrand) {
return (double) integrand.sum();
}
// /**
// * Finite difference approximation to a 1d Dataset.
// * <p>
// * Second order correct finite difference approximation to the first
// * derivative of a 1-d Dataset, with respect to the index
// * @param y
// * Values of the function.
// * @return second-order correct approximation to the function.
// */
// private static Dataset differentiate1DDataset(Dataset y) {
// Dataset deriv = DatasetFactory.zeros(y, DoubleDataset.class);
// if (y.getSize() > 1) {
// if (y.getSize() == 2) {
// double dderiv = y.getDouble(1) - y.getDouble(0);
// deriv.set(dderiv, 0);
// deriv.set(dderiv, 1);
// } else {
// // Three points or more
// int iLast = y.getSize()-1;
// // End points
// deriv.set((-3*y.getDouble(0) + 4*y.getDouble(1) - y.getDouble(2))/2, 0);
// deriv.set((y.getDouble(iLast-2) - 4*y.getDouble(iLast-1) + 3*y.getDouble(iLast))/2, iLast);
// // The rest of the points
// for (int i = 1; i < iLast; i++)
// deriv.set((y.getDouble(i+1) - y.getDouble(i-1))/2, i);
// }
// }
// return deriv;
// }
}