diff --git a/src/org.eclipse.ice.reflectivity/META-INF/MANIFEST.MF b/src/org.eclipse.ice.reflectivity/META-INF/MANIFEST.MF index 529c04f7c..893c947f6 100644 --- a/src/org.eclipse.ice.reflectivity/META-INF/MANIFEST.MF +++ b/src/org.eclipse.ice.reflectivity/META-INF/MANIFEST.MF @@ -7,6 +7,7 @@ Service-Component: OSGI-INF/ReflectivityModelComponent.xml Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Import-Package: org.apache.commons.math;version="2.1.0", org.apache.commons.math.complex;version="2.1.0", + org.apache.commons.math.special;version="2.1.0", org.eclipse.ice.item, org.eclipse.ice.item.model, org.eclipse.ice.materials diff --git a/src/org.eclipse.ice.reflectivity/src/org/eclipse/ice/reflectivity/ReflectivityCalculator.java b/src/org.eclipse.ice.reflectivity/src/org/eclipse/ice/reflectivity/ReflectivityCalculator.java index 8cbea0ffb..50c41bfbf 100644 --- a/src/org.eclipse.ice.reflectivity/src/org/eclipse/ice/reflectivity/ReflectivityCalculator.java +++ b/src/org.eclipse.ice.reflectivity/src/org/eclipse/ice/reflectivity/ReflectivityCalculator.java @@ -11,7 +11,9 @@ *******************************************************************************/ package org.eclipse.ice.reflectivity; +import org.apache.commons.math.MathException; import org.apache.commons.math.complex.Complex; +import org.apache.commons.math.special.Erf; /** * This class performs all of the operations necessary to calculate the @@ -30,6 +32,12 @@ public class ReflectivityCalculator { */ public static final int maxPoints = 2000; + /** + * The maximum number of layers of roughness that can be created when + * generating the interfacial profile. + */ + public static final int maxRoughSize = 101; + /** * This operation returns the value of the squared modulus of the specular * reflectivity for a single wave vector Q. @@ -145,7 +153,7 @@ public void convolute(double[] waveVector, double delQ0, double delQ1oQ, boolean lFinish = false, hFinish = false; // Perform convolution over nPnts between nLow and nHigh extensions - for (int i = numLowPoints; i < numLowPoints + numPoints; i++) { + for (int i = numLowPoints; i <= numLowPoints + numPoints - 1; i++) { // Calculate resolution width and initialize resolution loop if (waveVector[i] < 1.0e-10) { qEff = 1.0e-10; @@ -201,7 +209,7 @@ public void convolute(double[] waveVector, double delQ0, double delQ1oQ, refTemp[i - numLowPoints] = refTemp[i - numLowPoints] / rNorm; } // Transfer convoluted values from refTemp to refFit - for (int i = 0; i < 10; i++) { + for (int i = 0; i < numPoints; i++) { refFit[i] = refTemp[i]; } @@ -285,4 +293,69 @@ public int getHighExtensionLength(double[] waveVector, double delQ0, return numHighPoints; } + + /** + * This operation generates the interfacial profile using an error function + * of numRough ordinate steps based on those of the hyperbolic tangent. + * + * @param numRough + * the number of ordinate steps + * @param zInt + * FIXME! This array must be preallocated with a size n = + * maxRoughSize. + * @param rufInt + * FIXME! This array must be preallocated with a size n = + * maxRoughSize. + * @throws MathException + */ + public void getInterfacialProfile(int numRough, double[] zInt, + double[] rufInt) throws MathException { + + // cE ensures Gaussian = 0.5 when z = zhwhm + final double cE = 1.665; + double dist = 0.0, step = 0.0, oHalfstep = 0.0, zTemp = 0.0; + int j; + + // Check nRough to make sure it is legitimate + if (numRough < 1) { + numRough = 1; + } + // Set the step size + step = 2.0 / ((double) (numRough + 1)); + + // Evaluate the lower half of the interface + dist = -step / 2.0; + // Steps calculated from inverse tanh + zInt[numRough / 2 + 1] = Math.log((1.0 + dist) / (1.0 - dist)) + / (2.0 * cE); + rufInt[numRough / 2 + 1] = Erf.erf(cE * zInt[numRough / 2 + 1]); + for (j = numRough / 2; j == 1; j--) { + dist = dist - step; + zInt[j] = Math.log((1.0 + dist) / (1.0 - dist)) / (2.0 * cE); + rufInt[j] = Erf.erf(cE * zInt[j]); + } + + // Evaluate the upper half of the interface + dist = step / 2.0; + // Steps calculated from inverse tanh + zInt[numRough / 2 + 2] = Math.log((1.0 + dist) / (1.0 - dist)) + / (2.0 * cE); + rufInt[numRough / 2 + 2] = Erf.erf(cE * zInt[numRough / 2 + 2]); + for (j = numRough / 2 + 3; j < numRough+1; j++) { + dist = dist + step; + zInt[j] = Math.log((1.0 + dist) / (1.0 - dist)) / (2.0 * cE); + rufInt[j] = Erf.erf(cE * zInt[j]); + } + + // Calculate step widths + oHalfstep = 0.5*(zInt[2] - zInt[1]); + for (j = 1; j < numRough/2 + 1; j++) { + zTemp = zInt[j]; + zInt[j] = oHalfstep + 0.5 * (zInt[j + 1] - zInt[j]); + zInt[numRough + 2 - j]= zInt[j]; + oHalfstep = 0.5 * (zInt[j + 1] - zTemp); + } + + return; + } } diff --git a/tests/org.eclipse.ice.reflectivity.test/META-INF/MANIFEST.MF b/tests/org.eclipse.ice.reflectivity.test/META-INF/MANIFEST.MF index 15583c82a..9ef0ff75a 100644 --- a/tests/org.eclipse.ice.reflectivity.test/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.ice.reflectivity.test/META-INF/MANIFEST.MF @@ -7,7 +7,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Require-Bundle: org.junit;bundle-version="4.11.0", org.eclipse.ice.item;bundle-version="2.0.0", org.eclipse.ice.datastructures;bundle-version="2.0.0" -Import-Package: org.eclipse.core.resources, +Import-Package: org.apache.commons.math;version="2.1.0", + org.eclipse.core.resources, org.eclipse.core.runtime;version="3.4.0", org.eclipse.ice.io.csv, org.eclipse.ice.materials, diff --git a/tests/org.eclipse.ice.reflectivity.test/src/org/eclipse/ice/reflectivity/test/ReflectivityCalculatorTester.java b/tests/org.eclipse.ice.reflectivity.test/src/org/eclipse/ice/reflectivity/test/ReflectivityCalculatorTester.java index c555b0a56..69c917d15 100644 --- a/tests/org.eclipse.ice.reflectivity.test/src/org/eclipse/ice/reflectivity/test/ReflectivityCalculatorTester.java +++ b/tests/org.eclipse.ice.reflectivity.test/src/org/eclipse/ice/reflectivity/test/ReflectivityCalculatorTester.java @@ -30,6 +30,7 @@ import org.eclipse.ice.reflectivity.Tile; import org.junit.BeforeClass; import org.junit.Test; +import org.apache.commons.math.MathException; /** * This class tests {@link org.eclipse.ice.reflectivity.ReflectivityCalculator}. @@ -55,6 +56,11 @@ public class ReflectivityCalculatorTester { */ private static IProject project; + /** + * A default tolerance for the tests. + */ + private double tol = 1.0e-3; + /** * This class loads the files for the test. * @@ -139,10 +145,10 @@ public void testGetExtensionLengths() { // Call the function int numLowPoints = 0, numHighPoints = 0; ReflectivityCalculator calculator = new ReflectivityCalculator(); - numLowPoints = calculator.getLowExtensionLength(waveVector, delQ0, delQ1oQ, - numPoints); - numHighPoints = calculator.getHighExtensionLength(waveVector, delQ0, delQ1oQ, - numPoints); + numLowPoints = calculator.getLowExtensionLength(waveVector, delQ0, + delQ1oQ, numPoints); + numHighPoints = calculator.getHighExtensionLength(waveVector, delQ0, + delQ1oQ, numPoints); // Check the high and low extension lengths assertEquals(refNumLowPoints, numLowPoints); @@ -192,7 +198,9 @@ public void testConvolute() { Tile[] tiles = loadTiles(tileLines); assertEquals(173, tiles.length); - // Compute the initial value of refFit + // Compute the initial value of refFit. This code was adapted from the + // original VB code and it is called, in that code, right before + // ManConFixedLambda. double[] refFit = new double[lines.size() - 1]; double qEff = 0.0; ReflectivityCalculator calculator = new ReflectivityCalculator(); @@ -205,12 +213,15 @@ public void testConvolute() { refFit[i] = calculator.getModSqrdSpecRef(qEff, wavelength, tiles); } - // Do the convolution and check the result + // Do the convolution and check the result against the reference values. calculator.convolute(waveVector, delQ0, delQ1oQ, wavelength, numPoints, numLowPoints, numHighPoints, refFit); for (int i = 0; i < refFit.length; i++) { + // Most of these results agree to roughly 1e-4, but some of them + // disagree by as much as 3.2%. They are clustered around 90 <= i <= + // 101. assertEquals(refRefFit[i], refFit[i], - Math.abs(refRefFit[i]) / 1.0e-4); + Math.abs(refRefFit[i]) * 3.2e-2); } return; @@ -249,7 +260,7 @@ public void testGetSpecRefSqrdMod() { System.out.println("RERR = " + (specRefSqrd - expectedSpecRefSqrd) / expectedSpecRefSqrd); assertEquals(expectedSpecRefSqrd, specRefSqrd, - Math.abs(expectedSpecRefSqrd) / 1.0e-4); + Math.abs(expectedSpecRefSqrd) * tol); // Get the two single parameters and the final result out of the data // for the second test case @@ -268,7 +279,7 @@ public void testGetSpecRefSqrdMod() { System.out.println("RERR = " + (specRefSqrd - expectedSpecRefSqrd) / expectedSpecRefSqrd); assertEquals(expectedSpecRefSqrd, specRefSqrd, - Math.abs(expectedSpecRefSqrd / 1.0e-4)); + Math.abs(expectedSpecRefSqrd) * tol); return; } @@ -301,4 +312,53 @@ private Tile[] loadTiles(ListComponent lines) { return tiles; } + /** + * This class tests + * {@link ReflectivityCalculator#getInterfacialProfile(int, double[], double[])} + * . + * + * @throws MathException + * This exception is thrown if the erf can't be computed during + * the calculation. + */ + @Test + public void testGetInterfacialProfile() throws MathException { + // Get the file holding the test values + Form form = reader.read(project.getFile("genErf.csv")); + ListComponent lines = (ListComponent) form + .getComponent(1); + assertEquals(101, lines.size()); + + // Create the reference data. Start by getting the number of roughness + // steps to make and then get the zInt and rufInt arrays. + int numRough = Integer.valueOf(lines.get(0)[2]); + double[] refZInt = new double[ReflectivityCalculator.maxRoughSize]; + double[] refRufInt = new double[ReflectivityCalculator.maxRoughSize]; + + // Load the reference arrays + for (int i = 0; i < ReflectivityCalculator.maxRoughSize; i++) { + String[] line = lines.get(i); + refZInt[i] = Double.valueOf(line[0]); + refRufInt[i] = Double.valueOf(line[1]); + } + + // Create the test arrays + double[] zInt = new double[ReflectivityCalculator.maxRoughSize]; + double[] rufInt = new double[ReflectivityCalculator.maxRoughSize]; + + // Create the calculator and get the interfacial profile + ReflectivityCalculator calc = new ReflectivityCalculator(); + calc.getInterfacialProfile(numRough, zInt, rufInt); + + // Check the results + for (int i = 0; i < ReflectivityCalculator.maxRoughSize; i++) { + System.out.println("GenErf: " + refZInt[i] + " " + zInt[i] + " " + + Math.abs(refZInt[i]) * tol); + assertEquals(refZInt[i], zInt[i], Math.abs(refZInt[i]) * tol); + assertEquals(refRufInt[i], rufInt[i], Math.abs(refRufInt[i]) * tol); + } + + return; + } + }