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). */