/*-
* 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 org.eclipse.january.dataset.Dataset;
/**
* A class that performs a given function at a reduced resolution.
* <p>
* Each subclass has a defined calculate method, which takes two
* {@link Dataset}s and returns another as a result. The calculation is
* performed at a reduced resolution compared, and the result scaled back up to
* the original resolution.
* @author Timothy Spain timothy.spain@diamond.ac.uk
*
*/
abstract public class XPDFScaled2DCalculation {
int maxGridSize;
/**
* Constructor specifying a maximum grid size.
* @param maxGridSize
* reduce the resolution of the calculation if the inputs
* are larger than this size in total size
*/
public XPDFScaled2DCalculation(int maxGridSize) {
this.maxGridSize = maxGridSize;
}
/**
* Performs a calculation taking two {@link Dataset}s and returning a third.
* @param gamma
* the first two dimensional parameter.
* @param delta
* the second two dimensional parameter.
* @return the result of the specified function.
*/
protected Dataset calculate(Dataset gamma, Dataset delta) {
return null;
}
/**
* Provides the grid resizing for the scaled calculation.
* @param gamma
* the first two dimensional parameter of the {@link calculate()} method.
* @param delta
* the second two dimensional parameter of the {@link calculate()} method.
* @return
* the full resolution result of the calculation.
*/
final public Dataset run(Dataset gamma, Dataset delta) {
// Grid size for the high resolution data
int nXHigh = delta.getShape()[0];
int nYHigh = delta.getShape()[1];
int[] nXYLow = new int[2];
restrictGridSize(maxGridSize, nXHigh, nYHigh, nXYLow);
int nXLow = nXYLow[0];
int nYLow = nXYLow[1];
// Down sampling of the angular coordinates for faster calculations
Dataset gammaDown = XPDFRegrid.two(gamma, nXLow, nYLow);
Dataset deltaDown = XPDFRegrid.two(delta, nXLow, nYLow);
Dataset resultLow = calculate(gammaDown, deltaDown);
// Up-sample the absorption back to the original resolution and return
return XPDFRegrid.two(resultLow, nXHigh, nYHigh);
}
/**
* Performs a calculation taking a {@link Dataset} and returning a second.
* @param twoTheta
* the two dimensional parameter.
* @return the result of the specified function.
*/
protected Dataset calculateTwoTheta(Dataset twoTheta) {
return null;
}
/**
* Provides the grid resizing for the scaled calculation.
* @param twoTheta
* the two dimensional parameter of the {@link calculateTwoTheta()} method.
* @return
* the full resolution result of the calculation.
*/
final public Dataset runTwoTheta(Dataset twoTheta) {
// Grid shape for the high resolution data
int nXHigh = twoTheta.getShape()[0];
int nYHigh = twoTheta.getShape()[1];
int[] nXYLow = new int[2];
restrictGridSize(maxGridSize, nXHigh, nYHigh, nXYLow);
int nXLow = nXYLow[0];
int nYLow = nXYLow[1];
// Down-sampling of the angular coordinate for faster calculations
Dataset twoThetaLow = XPDFRegrid.two(twoTheta, nXLow, nYLow);
Dataset resultLow = calculateTwoTheta(twoThetaLow);
// Up-sample the result back to the original resolution and return
return XPDFRegrid.two(resultLow, nXHigh, nYHigh);
}
/**
* Returns smaller grid axes, based on the lengths of the originals and the maximum grid size.
* @param maxGrid
* maximum number of grid points to use.
* @param nXHigh
* original length of the x axis (dimension 0)
* @param nYHigh
* original length of the y axis (dimension 1)
* @param nXYLow
* return the values of the axis lengths using a 2 element int
* array, since Java has no pass by reference
*/
private void restrictGridSize(int maxGrid, int nXHigh, int nYHigh, int[] nXYLow) {
int nXLow, nYLow;
// Grid size for the low resolution calculations
if (nXHigh*nYHigh < maxGrid) {
nXLow = nXHigh;
nYLow = nYHigh;
} else {
// Sort the axes
int smallerDim, largerDim;
boolean isXSmaller = nXHigh < nYHigh;
if (isXSmaller) {
smallerDim = nXHigh;
largerDim = nYHigh;
} else {
smallerDim = nYHigh;
largerDim = nXHigh;
}
// Deal with one axis being rather short
if (smallerDim <= 2) {
largerDim = (largerDim*smallerDim > maxGrid) ? maxGrid/smallerDim : largerDim;
} else {
double scale = maxGrid/(1.0*smallerDim*largerDim);
smallerDim = (int) Math.ceil(Math.sqrt(scale) * smallerDim);
smallerDim = (smallerDim < 2) ? 2 : smallerDim;
largerDim = maxGrid/smallerDim;
}
// Unsort the axes
if (isXSmaller) {
nXLow = smallerDim;
nYLow = largerDim;
} else {
nXLow = largerDim;
nYLow = smallerDim;
}
}
nXYLow[0] = nXLow;
nXYLow[1] = nYLow;
}
}