/* * Copyright (C) 2010-2014 Andreas Maier, * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */ package edu.stanford.rsl.conrad.physics.absorption; import java.util.ArrayList; import java.util.HashMap; import edu.stanford.rsl.conrad.physics.PhysicalObject; import edu.stanford.rsl.conrad.physics.detector.XRayDetector; import edu.stanford.rsl.conrad.physics.materials.Material; import edu.stanford.rsl.conrad.utils.UserUtil; import edu.stanford.rsl.conrad.utils.VisualizationUtil; public class PathLengthHistogramCreatingAbsorptionModel extends AbsorptionModel { /** * */ private static final long serialVersionUID = 2227409836615130529L; private boolean configured = false; private boolean debug = true; private AbsorptionModel internalModel; private HashMap<Material,int[]> histogramMap; private boolean doesNotFit = false; /** * Bin size in [mm] */ private int binSize = 1; /** * number of bins */ private int numberOfBins = 250; @Override public void configure() throws Exception { internalModel = null; binSize = UserUtil.queryInt("Enter bin size [mm]", binSize); numberOfBins = UserUtil.queryInt("Enter number of Bins:", numberOfBins); AbsorptionModel [] models = AbsorptionModel.getAvailableAbsorptionModels(); internalModel = (AbsorptionModel) UserUtil.chooseObject("Select Absorption Model: ", "Absorption Model", models, models[0]); internalModel.configure(); histogramMap = new HashMap<Material, int[]>(); configured = true; } @Override public boolean isConfigured() { return configured; } private synchronized void addMaterial(Material mat){ if (!histogramMap.containsKey(mat)){ int [] newHistogram = new int[numberOfBins]; histogramMap.put(mat, newHistogram); } } private void increment(Material mat, double pathLength){ int [] histo = histogramMap.get(mat); if (histo == null) { addMaterial(mat); histo = histogramMap.get(mat); } int index = (int) Math.round(pathLength / binSize); if (index < numberOfBins){ increment(histo, index); } else { if (!doesNotFit){ System.out.println("PathLengthHistogramCreatingAbsorptionModel: Histogram does not fit " + pathLength + " mm of " + mat); doesNotFit = true; } } } private synchronized void increment(int [] histo, int index){ histo[index]++; } @Override public double evaluateLineIntegral(ArrayList<PhysicalObject> segments) { /** * Store all path lengths in the internal histogram. * Note that this part of the code is called in parallel. * Thus, it needs to be thread-safe. */ HashMap<Material, Double> localMap = XRayDetector.accumulatePathLenghtForEachMaterial(segments); for (Material material :localMap.keySet()){ increment(material, localMap.get(material)); } // use the internal model to create the correct absorption values; return internalModel.evaluateLineIntegral(segments); } @Override public void notifyEndOfRendering(){ if (debug) System.out.println("Rendering End."); /** * Rendering has ended. Now, we can show the histogram contents. */ double [] xValues = new double [numberOfBins]; for (int i = 0; i < numberOfBins; i++){ xValues[i]=i*binSize; } for (Material mat: histogramMap.keySet()){ int [] histo = histogramMap.get(mat); double [] yValues = new double [numberOfBins]; for (int i = 0; i < numberOfBins; i++){ yValues[i]=histo[i]; } VisualizationUtil.createPlot(xValues, yValues, "Path lengths in " + mat, "length [mm]", "count").show(); } } @Override public String toString() { if (configured) return "Histgram of " + internalModel.toString(); return "Path length histogram creating model"; } /** * @return the debug */ public boolean isDebug() { return debug; } /** * @param debug the debug to set */ public void setDebug(boolean debug) { this.debug = debug; } /** * @return the internalModel */ public AbsorptionModel getInternalModel() { return internalModel; } /** * @param internalModel the internalModel to set */ public void setInternalModel(AbsorptionModel internalModel) { this.internalModel = internalModel; } /** * @return the histogramMap */ public HashMap<Material, int[]> getHistogramMap() { return histogramMap; } /** * @param histogramMap the histogramMap to set */ public void setHistogramMap(HashMap<Material, int[]> histogramMap) { this.histogramMap = histogramMap; } /** * @return the doesNotFit */ public boolean isDoesNotFit() { return doesNotFit; } /** * @param doesNotFit the doesNotFit to set */ public void setDoesNotFit(boolean doesNotFit) { this.doesNotFit = doesNotFit; } /** * @return the binSize */ public int getBinSize() { return binSize; } /** * @param binSize the binSize to set */ public void setBinSize(int binSize) { this.binSize = binSize; } /** * @return the numberOfBins */ public int getNumberOfBins() { return numberOfBins; } /** * @param numberOfBins the numberOfBins to set */ public void setNumberOfBins(int numberOfBins) { this.numberOfBins = numberOfBins; } /** * @param configured the configured to set */ public void setConfigured(boolean configured) { this.configured = configured; } }