package edu.stanford.rsl.conrad.physics;
import java.util.concurrent.CountDownLatch;
import edu.stanford.rsl.conrad.parallel.ParallelizableRunnable;
import edu.stanford.rsl.jpop.SimpleFunctionOptimizer;
import edu.stanford.rsl.jpop.SimpleOptimizableFunction;
/**
* Evaluates the lambda Function according to
* Joseph PM, Spital RD. �A method for correcting bone induced artifacts in computed tomography scanners�, JCAT 1978;2:100-108.
*
* @author akmaier
*
*/
public class LambdaFunction implements SimpleOptimizableFunction, ParallelizableRunnable {
private CountDownLatch latch = null;
private double [] xRaySpectrum;
private double [] softAttenuationCoefficients;
private double [] hardAttenuationCoefficients;
private double waterCorrectedValue;
private double passedHardMaterial;
private double epsilon;
private double optimalLambda;
/**
* Constructor for the lambda function.
* @param xRaySpectrum the incident x-ray spectrum
* @param softAttenuationCoefficients the energy dependent attenuation coefficients in the soft material
* @param hardAttenuationCoefficients the energy dependent attenuation coefficients in the hard material
* @param waterCorrectedValue the observed water corrected value
* @param passedHardMaterial the total amount of hard material which was passed in the observation.
*/
LambdaFunction(double [] xRaySpectrum, double [] softAttenuationCoefficients, double [] hardAttenuationCoefficients, double waterCorrectedValue, double passedHardMaterial){
this.xRaySpectrum = xRaySpectrum;
this.softAttenuationCoefficients = softAttenuationCoefficients;
this.hardAttenuationCoefficients = hardAttenuationCoefficients;
this.waterCorrectedValue = waterCorrectedValue;
this.passedHardMaterial = passedHardMaterial;
epsilon = 0;
for (int i = 0; i< xRaySpectrum.length; i++){
epsilon += xRaySpectrum[i] * Math.exp(-softAttenuationCoefficients[i]*waterCorrectedValue);
}
}
/**
* Constructor for the lambda function.
* @param xRaySpectrum the incident x-ray spectrum
* @param softAttenuationCoefficients the energy dependent attenuation coefficients in the soft material
* @param hardAttenuationCoefficients the energy dependent attenuation coefficients in the hard material
* @param waterCorrectedValue the observed water corrected value
* @param passedHardMaterial the total amount of hard material which was passed in the observation.
* @param epsilon the epsilon factor, i.e. right side of the integral equation.
*/
LambdaFunction(double [] xRaySpectrum, double [] softAttenuationCoefficients, double [] hardAttenuationCoefficients, double waterCorrectedValue, double passedHardMaterial, double epsilon){
this.xRaySpectrum = xRaySpectrum;
this.softAttenuationCoefficients = softAttenuationCoefficients;
this.hardAttenuationCoefficients = hardAttenuationCoefficients;
this.waterCorrectedValue = waterCorrectedValue;
this.passedHardMaterial = passedHardMaterial;
this.epsilon = epsilon;
}
@Override
public double evaluate(double lambda) {
double revan = 0;
for (int i = 0; i< xRaySpectrum.length; i++){
revan += xRaySpectrum[i] * Math.exp((-softAttenuationCoefficients[i]*waterCorrectedValue) + (softAttenuationCoefficients[i]*passedHardMaterial*lambda) - (hardAttenuationCoefficients[i]*passedHardMaterial));
}
return Math.abs(revan - epsilon);
}
@Override
public void setLatch(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
SimpleFunctionOptimizer optimizer = new SimpleFunctionOptimizer();
optimizer.setLeftEndPoint(-2.0);
optimizer.setRightEndPoint(2.0);
optimalLambda = optimizer.minimize(this);
latch.countDown();
}
/**
* Method to access the optimal lambda after optimization.
* @return the optimal value
*/
public double getOptimalLambda(){
return optimalLambda;
}
}
/*
* Copyright (C) 2010-2014 Andreas Maier
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/