/*-
* 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;
import org.eclipse.january.dataset.DoubleDataset;
import org.eclipse.january.dataset.IndexIterator;
import org.eclipse.january.dataset.Maths;
import com.github.tschoonj.xraylib.Xraylib;
/**
* Calculates the electron cross-sections as a function of angle
* @author Timothy Spain timothy.spain@diamond.ac.uk
* @since 2015-09-14
*
*/
public class XPDFElectronCrossSections {
// double beamEnergy;
// Dataset twoTheta;
private XPDFCoordinates coordinates;
private Dataset thomson;
private Dataset kleinNishina;
private static final double classicalElectronRadius = 1.0;
private static final double electronMasskeV = 510.998910;//(13)
private static final double breitDiracPower = 2.0;
/**
* Empty constructor
*/
public XPDFElectronCrossSections() {
coordinates = null;
thomson = null;
kleinNishina = null;
}
/**
* Copy constructor
* @param inXSect
* Cross-section object to be copied.
*/
public XPDFElectronCrossSections(XPDFElectronCrossSections inXSect){
this.coordinates = (inXSect.coordinates != null) ? inXSect.coordinates : null;
this.thomson = (inXSect.thomson != null) ? inXSect.thomson : null;
this.kleinNishina = (inXSect.kleinNishina != null) ? inXSect.kleinNishina : null;
}
/**
* Sets the beam energy.
* @param beamEnergy
* The beam energy at which the cross-sections are to be calculated.
*/
public void setBeamEnergy(double beamEnergy) {
if (this.coordinates == null)
this.coordinates = new XPDFCoordinates();
this.coordinates.setEnergy(beamEnergy);
// invalidate the Klein-Nishina value
kleinNishina = null;
}
/**
* Sets the scattering angles.
* @param twoTheta
* The scattering angles at which the cross-sections are to be calculated.
*/
public void setAngles(Dataset twoTheta) {
if (this.coordinates == null)
this.coordinates = new XPDFCoordinates();
this.coordinates.setTwoTheta(twoTheta);
// invalidate the Thomson and Klein-Nishima values
this.kleinNishina = null;
this.thomson = null;
}
/**
* Sets the energy and scattering angles.
* @param coordinates
* The coordinates object containing the beam energy and
* the scattering angles.
*/
public void setCoordinates(XPDFCoordinates coordinates) {
this.coordinates = coordinates;
// invalidate the Thomson and Klein-Nishima values
this.kleinNishina = null;
this.thomson = null;
}
/**
* Calculates and returns the elastic Thomson scattering cross-section.
* @return the elastic Thomson electron scattering cross-section at the
* selected scattering angles.
*/
public Dataset getThomsonCrossSection() {
if (this.thomson == null) {
thomson = Maths.multiply(
0.5*classicalElectronRadius*classicalElectronRadius,
Maths.add(1, Maths.square(coordinates.getCosTwoTheta()))
);
}
return this.thomson;
}
/**
* Returns the Thomson differential cross section.
* @param coords
* the coordinates object describing the angles of interest
* @return
* the differential Thomson cross-section in barns per atom per steradian
*/
public static Dataset getThomsonCrossSection(XPDFCoordinates coords) {
IndexIterator iter = coords.getTwoTheta().getIterator();
DoubleDataset jJ = coords.getTwoTheta().copy(DoubleDataset.class);
while (iter.hasNext())
jJ.setAbs(iter.index, Xraylib.DCS_Thoms(coords.getTwoTheta().getElementDoubleAbs(iter.index))/Xraylib.DCS_Thoms(0));
return jJ;
}
/**
* Calculates and returns the inelastic electron scattering cross-section.
* @return the inelastic electron scattering cross-section at the selected
* scattering angles, for the beam energy. As parameterized by
* Klein and Nishina.
*/
public Dataset getKleinNishinaCrossSection() {
if (this.kleinNishina == null) {
double gamma = coordinates.getEnergy()/electronMasskeV;
Dataset photonEnergyRatio = Maths.divide(
1.0,
Maths.add(
1.0,
Maths.multiply(
gamma,
Maths.subtract(
1,
Maths.cos(coordinates.getTwoTheta())
)
)
)
);
this.kleinNishina = Maths.multiply(0.5*classicalElectronRadius*classicalElectronRadius,
Maths.multiply(
Maths.power(
photonEnergyRatio,
breitDiracPower),
Maths.add(
Maths.add(
photonEnergyRatio,
Maths.divide(1, photonEnergyRatio)),
Maths.add(
-1,
Maths.square(
Maths.multiply(
Maths.cos(coordinates.getTwoTheta()),
Maths.cos(coordinates.getPhi())
)
)
)
)
)
);
// Maths.subtract(
// Maths.add(
// photonEnergyRatio,
// Maths.divide(1, photonEnergyRatio)),
// Maths.multiply(
// 2,
// Maths.multiply(
// Maths.square(Maths.sin(coordinates.getTwoTheta())),
// Maths.square(Maths.sin(DatasetFactory.zeros(coordinates.getTwoTheta()))) // The azimuthal scattering angle is zero
// )
// )
// )
// )
// );
}
return this.kleinNishina;
}
/**
* Returns the inelastic Klein-Nishina differential cross-section
* @param coords
* coordinates object describing the angles of interest
* @param beamEnergy
* energy of the incident photons in keV
* @return
* unpolarized Klein-Nishina differential cross section in barns per atom per steradian
*/
public static Dataset getKleinNishinaCrossSection(XPDFCoordinates coords, double beamEnergy) {
IndexIterator iter = coords.getTwoTheta().getIterator();
DoubleDataset oscarYoshio = coords.getTwoTheta().copy(DoubleDataset.class);
while (iter.hasNext())
oscarYoshio.setAbs(iter.index, Xraylib.DCS_KN(beamEnergy, coords.getTwoTheta().getElementDoubleAbs(iter.index))/Xraylib.DCS_KN(beamEnergy, 0.0));
return oscarYoshio;
}
}