/* * 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.diffraction.powder; import java.util.Arrays; import java.util.List; import org.eclipse.dawnsci.analysis.api.roi.IROI; import org.eclipse.january.dataset.BooleanDataset; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DatasetUtils; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.IDataset; import org.eclipse.january.dataset.Maths; import org.eclipse.january.dataset.PositionIterator; import org.eclipse.january.dataset.Slice; import org.eclipse.dawnsci.analysis.api.metadata.IDiffractionMetadata; import uk.ac.diamond.scisoft.analysis.diffraction.QSpace; import uk.ac.diamond.scisoft.analysis.roi.XAxis; public abstract class AbstractPixelIntegration { int nbins; double[] radialRange = null; double[] azimuthalRange = null; DoubleDataset binEdges = null; Dataset[] radialArray; Dataset[] azimuthalArray; Dataset mask; Dataset maskRoiCached; QSpace qSpace = null; XAxis xAxis = XAxis.Q; IROI roi = null; public AbstractPixelIntegration(IDiffractionMetadata metadata) { this.qSpace = new QSpace(metadata.getDetector2DProperties(), metadata.getDiffractionCrystalEnvironment()); int[] shape = new int[]{metadata.getDetector2DProperties().getPy(), metadata.getDetector2DProperties().getPx()}; this.nbins = calculateNumberOfBins(metadata.getDetector2DProperties().getBeamCentreCoords(), shape); } public AbstractPixelIntegration(IDiffractionMetadata metadata, int numBins) { this.qSpace = new QSpace(metadata.getDetector2DProperties(), metadata.getDiffractionCrystalEnvironment()); this.nbins = numBins; } public abstract List<Dataset> integrate(IDataset dataset); /** * Set minimum and maximum of radial range * @param range */ public void setRadialRange(double[] range) { if (range == null) { radialRange = null; binEdges = null; return; } if (range.length != 2) throw new IllegalArgumentException("Range array should be of length 2"); if (xAxis == XAxis.RESOLUTION) { range[0] = (2*Math.PI)/range[0]; range[1] = (2*Math.PI)/range[1]; } if (range[0] > range[1]) { Arrays.sort(range); } radialRange = range; binEdges = null; } /** * Set minimum and maximum of azimuthal range (-180 to + 180) * @param range */ public void setAzimuthalRange(double[] range) { if (range == null) { azimuthalRange = null; binEdges = null; return; } if (range.length != 2) throw new IllegalArgumentException("Range array should be of length 2"); if (range[0] > range[1]) { Arrays.sort(range); } if (range[0] < -180) throw new IllegalArgumentException("Min cannot be less than -Pi"); if (range[1] > 180) throw new IllegalArgumentException("Max cannot be greater than +Pi"); azimuthalRange = range; binEdges = null; } public void setNumberOfBins(int nBins) { if (nBins < 1) throw new IllegalArgumentException("Must be 1 or more"); this.nbins = nBins; binEdges = null; } public void setAxisType(XAxis axis) { if (this.xAxis == axis) return; this.xAxis = axis; radialArray = null; binEdges = null; } public void generateRadialArray(int[] shape, boolean centre) { if (qSpace == null) return; XAxis x = xAxis == XAxis.RESOLUTION ? XAxis.Q : xAxis; if (centre) radialArray = new Dataset[]{PixelIntegrationUtils.generateRadialArray(shape, qSpace, x)}; else radialArray = PixelIntegrationUtils.generateMinMaxRadialArray(shape, qSpace, x); } protected void generateAzimuthalArray(double[] beamCentre, int[] shape) { azimuthalArray = new Dataset[]{PixelIntegrationUtils.generateAzimuthalArray(beamCentre, shape, false)}; } protected void generateMinMaxAzimuthalArray(double[] beamCentre, int[] shape) { azimuthalArray = PixelIntegrationUtils.generateMinMaxAzimuthalArray(beamCentre, shape, false); } protected Slice[] getSlice() { // if (roi != null) { // IRectangularROI bounds = roi.getBounds(); // int[] s = bounds.getIntPoint(); // int e0 = (int)bounds.getLength(0) + s[0]; // int e1 = (int)bounds.getLength(1)+s[1]; // // s[0] = Math.max(s[0], 0); // s[0] = Math.min(s[0], radialArray.getShape()[1]); // s[1] = Math.max(s[1], 0); // s[1] = Math.min(s[1], radialArray.getShape()[0]); // e0 = Math.max(e0, 0); // e0 = Math.min(e0, radialArray.getShape()[1]); // e1 = Math.max(e1, 0); // e1 = Math.min(e1, radialArray.getShape()[0]); // // Slice s1 = new Slice(s[1], e1, 1); // Slice s2 = new Slice(s[0], e0, 1); // return new Slice[]{s1,s2}; // } return null; } protected void processAndAddToResult(Dataset intensity, Dataset histo, List<Dataset> result, double[] binRange, String name) { Dataset axis = null; if (binRange == null) { axis = Maths.add(binEdges.getSlice(new int[]{1}, null ,null), binEdges.getSlice(null, new int[]{-1},null)); axis.idivide(2); } else { axis = DatasetFactory.createLinearSpace(binRange[0], binRange[1], nbins, Dataset.FLOAT64); } switch (xAxis) { case Q: axis.setName("q"); break; case ANGLE: axis.setName("2theta"); break; case RESOLUTION: axis = Maths.divide((2*Math.PI), axis); axis.setName("d-spacing"); break; case PIXEL: axis.setName("pixel"); break; } intensity.idivide(histo); DatasetUtils.makeFinite(intensity); intensity.setName(name + "_integrated"); result.add(axis); result.add(intensity); } public void setMask(Dataset mask) { this.mask = mask; maskRoiCached = null; if (mask == null) return; // binEdges = null; if (radialArray != null && !Arrays.equals(radialArray[0].getShape(), mask.getShape())) radialArray = null; } // public void setROI(IROI roi) { // this.roi = roi; // maskRoiCached = null; // } public static int calculateNumberOfBins(double[] beamCentre, int[] shape) { //within image if (beamCentre[1] < shape[0] && beamCentre[1] > 0 && beamCentre[0] < shape[1] && beamCentre[0] > 0) { double[] farCorner = new double[]{0,0}; if (beamCentre[1] < shape[0]/2.0) farCorner[0] = shape[0]; if (beamCentre[0] < shape[1]/2.0) farCorner[1] = shape[1]; return (int)Math.hypot(beamCentre[0]-farCorner[1], beamCentre[1]-farCorner[0]); } else if (beamCentre[1] < shape[0] && beamCentre[1] > 0 && (beamCentre[0] > shape[1] || beamCentre[0] < 0)) { return shape[1]; } else if (beamCentre[0] < shape[1] && beamCentre[0] > 0 && (beamCentre[1] > shape[0] || beamCentre[1] < 0)) { return shape[0]; } else { return (int)Math.hypot(shape[1], shape[0]); } } protected Dataset mergeMaskAndRoi(int[] shape) { Dataset out; if (mask == null) out = DatasetFactory.zeros(BooleanDataset.class, shape); else out = mask.clone(); PositionIterator pit = out.getPositionIterator(); int[] pos = pit.getPos(); while (pit.hasNext()) { if (mask == null) { if (roi.containsPoint(pos[1], pos[0])) out.set(true, pos); } else { if (!roi.containsPoint(pos[1], pos[0])) out.set(false, pos); } } return out; } protected DoubleDataset calculateBins(Dataset[] arrays, Dataset mask, double[] binRange, int numBins) { if (binRange != null) { //range corresponds to bin centres double shift = (binRange[1]- binRange[0])/(2*numBins); return (DoubleDataset) DatasetFactory.createLinearSpace(binRange[0]-shift, binRange[1]+shift, numBins + 1, Dataset.FLOAT64); } double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; for (Dataset a : arrays) { Dataset data = a; if (mask != null) data = DatasetUtils.select(new BooleanDataset[]{(BooleanDataset)DatasetUtils.cast(mask,Dataset.BOOL)}, new Object[]{a}, Double.NaN); double n = data.min(true).doubleValue(); double x = data.max(true).doubleValue(); min = n < min ? n : min; max = x > max ? x : max; } return (DoubleDataset) DatasetFactory.createLinearSpace(min, max, numBins + 1, Dataset.FLOAT64); } }