content: /*
   * Copyright (C) 2010-2014 Rotimi X Ojo, Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */
  package edu.stanford.rsl.conrad.physics.materials.utils;
  
  import java.util.Iterator;
  import java.util.TreeMap;
  
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  import edu.stanford.rsl.conrad.physics.materials.database.ElementalMassAttenuationData;
  import edu.stanford.rsl.conrad.physics.materials.database.FormulaToNameMap;
  import edu.stanford.rsl.conrad.utils.interpolation.NumberInterpolatingTreeMap;
  
  /**
   * Calculates the mass attenuation coefficient of a material given its formula or weighted atomic composition.
   * @see WeightedAtomicComposition
   * @author Rotimi X Ojo
   */
  public class LocalMassAttenuationCalculator {
  	
  	private static final TreeMap<String, TreeMap<AttenuationType, NumberInterpolatingTreeMap> > cache = new TreeMap<String, TreeMap<AttenuationType,NumberInterpolatingTreeMap>>();
  	
  	/**
  	 * Calculates the mass attenuation coefficient of a material given its formula
  	 * @param formula is the chemical formula of the material
  	 * @param energy is the energy of interest
  	 * @param attType is the {@link AttenuationType} of interest
  	 * @return the mass attenuation coefficient of a material given its formula
  	 */
  	public static double getMassAttenuationData(String formula,
  			double energy, AttenuationType attType) {
  		return getMassAttenuationData(new WeightedAtomicComposition(formula), energy, attType);
  	}
  	
  	/**
  	 * Calculates the mass attenuation coefficient of a material given its formula
  	 * @param formula is the chemical formula of the material
  	 * @param energies is the set of energy of interest
  	 * @param attType is the {@link AttenuationType} of interest
  	 * @return the mass attenuation coefficient of a material given its formula
  	 */
  	public static NumberInterpolatingTreeMap getMassAttenuationData(String formula,
  			double [] energies, AttenuationType attType) {
  		NumberInterpolatingTreeMap num = new NumberInterpolatingTreeMap();
  		for(double energy:energies){
  			num.put(energy, getMassAttenuationData(new WeightedAtomicComposition(formula), energy, attType));
  		}
  		return num;
  	}
  	
  	/**
  	 * Calculates the mass attenuation coefficient of a material given its {@link WeightedAtomicComposition}
  	 * @param comp is the weighted atomic composition of the material
  	 * @param energies is the set of energy of interest
  	 * @param attType is the {@link AttenuationType} of interest
  	 * @return the mass attenuation coefficient of a material given its formula
  	 */
  	public static NumberInterpolatingTreeMap getMassAttenuationData(WeightedAtomicComposition comp,
  			double [] energies, AttenuationType attType) {
  		NumberInterpolatingTreeMap num = new NumberInterpolatingTreeMap();
  		for(double energy:energies){
  			num.put(energy, getMassAttenuationData(comp, energy, attType));
  		}
  		return num;
  	}
  	
  	/**
  	 * Calculates the mass attenuation coefficient of a material given its weighted atomic composition.
  	 * This method uses an internal static cache to inhibit excessive file access. However, this
  	 * requires the method to be synchronized. This may lead to quite slow performance in parallel use.
  	 * 
  	 * @param comp is the {@link WeightedAtomicComposition} of the material
  	 * @param energy is the energy of interest
  	 * @param attType is the {@link AttenuationType} of interest
  	 * @return the mass attenuation coefficient of a material given its weighted atomic composition.
  	 */
  	public static synchronized double getMassAttenuationData(WeightedAtomicComposition comp,
  			double energy, AttenuationType attType) {
  		SimpleVector vec = getNormalizedComposition(comp);
  		Iterator<String> it = comp.keysIterator();
  		double value = 0;
  		int counter = 0;
  		while(it.hasNext()){
  			TreeMap<AttenuationType, NumberInterpolatingTreeMap> massAtt = null;
  			String name = FormulaToNameMap.getName(it.next());
  			if((massAtt = cache.get(name))== null){
  				massAtt= ElementalMassAttenuationData.get(name);
  				cache.put(name, massAtt);
  			}
  			double buff = massAtt.get(attType).interpolateValue(energy).doubleValue();
  			value+=vec.getElement(counter)* buff;
  			counter++;
  		}
  		return value;
  	}
  
  	private static SimpleVector getNormalizedComposition(WeightedAtomicComposition comp) {
  		SimpleVector vec = new SimpleVector(comp.size());
  		Iterator<Double> it = comp.valuesIterator();
  		int i =0;
  		double sum = 0;
  		while(it.hasNext()){
  			vec.setElementValue(i, it.next());
  			sum+=vec.getElement(i);
  			i++;
  		}
  		vec.divideBy(sum);
  		return vec;
  	}
  
  
  
  
  
  }
  