package edu.stanford.rsl.conrad.physics.materials.database; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.Scanner; import java.util.Set; import java.util.TreeMap; import edu.stanford.rsl.conrad.numerics.mathexpressions.Evaluator; import edu.stanford.rsl.conrad.physics.materials.utils.AttenuationType; import edu.stanford.rsl.conrad.physics.materials.utils.WeightedAtomicComposition; import edu.stanford.rsl.conrad.utils.interpolation.NumberInterpolatingTreeMap; /** * <p>This class provides access to NIST XCOM Database. * <br/>This can be used to retrieve the energy dependent mass attenuation of elements, and arbitrary combination of elements. * <br/>The NIST database supports energies between 1 keV - 100 GeV;</p> * @author Rotimi X Ojo */ public class OnlineMassAttenuationDB { private static String nistDBUrl = "http://physics.nist.gov"; public static double getMassAttenuationData(WeightedAtomicComposition comp, double energy, AttenuationType attType) { ArrayList<AttenuationType> ty = new ArrayList<AttenuationType>(); ty.add(attType); return getMassAttenuationData(comp, energy + ";", ty, false).get(attType).firstEntry().getValue().doubleValue(); } /** * Retrieves energy dependent mass attenuation data from NIST XCOM database * @param comp is atomic composition by weight of material to be retrieved * @param energies is semi-colon seperated list of energies(MEV) of interest. * @return energy dependent mass attenuation of supplied energies including K-Edges */ public static TreeMap<AttenuationType, NumberInterpolatingTreeMap> getMassAttenuationData( WeightedAtomicComposition comp, String energies, ArrayList<AttenuationType> att, boolean useDefaultEnergies) { return getMassAttenuationDataFromNIST(getCompositionAsString(comp),energies, att,useDefaultEnergies); } private static String buildURLLiteral(String composition, String energies, ArrayList<AttenuationType> att, boolean useDefaultEnergies) { String data = ""; composition= composition.trim(); try { data = URLEncoder.encode("WindowXmin", "UTF-8") + "=" + URLEncoder.encode(0.001 + "", "UTF-8"); data += "&" + URLEncoder.encode("WindowXmax", "UTF-8") + "=" + URLEncoder.encode(100000 + "", "UTF-8"); data += "&" + URLEncoder.encode("Formulae", "UTF-8") + "=" + URLEncoder.encode(composition, "UTF-8"); data += "&" + URLEncoder.encode("Method", "UTF-8") + "=" + URLEncoder.encode("3", "UTF-8"); data += "&" + URLEncoder.encode("NumAdd", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8"); data += "&" + URLEncoder.encode("Energies", "UTF-8") + "=" + URLEncoder.encode(energies, "UTF-8"); if(useDefaultEnergies){ data += "&" + URLEncoder.encode("Output", "UTF-8") + "=" + URLEncoder.encode("on", "UTF-8"); }else{ data += "&" + URLEncoder.encode("Output", "UTF-8") + "=" + URLEncoder.encode("", "UTF-8"); } for(AttenuationType type:att){ data += "&" + URLEncoder.encode(type.getName(), "UTF-8") + "=" + URLEncoder.encode("on", "UTF-8"); } } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } return data; } /** * Retrieves Mass attenuation data from the NIST XCOM Database * @param composition is space separated list of atomic composition of material of interest * @param energies is semi-colon separated list of energies * @param att is array list containing the types of attenuation the developer is interested in retrieving * @return Mass attenuation data from the NIST XCOM Database */ private static TreeMap<AttenuationType, NumberInterpolatingTreeMap>getMassAttenuationDataFromNIST(String composition, String energies, ArrayList<AttenuationType> att, boolean useDefaultEnergies){ String urlSpec = buildURLLiteral(composition, energies, att, useDefaultEnergies); TreeMap<AttenuationType, NumberInterpolatingTreeMap> table = new TreeMap<AttenuationType, NumberInterpolatingTreeMap>(); table.put(AttenuationType.COHERENT_ATTENUATION, new NumberInterpolatingTreeMap()); table.put(AttenuationType.INCOHERENT_ATTENUATION, new NumberInterpolatingTreeMap()); table.put(AttenuationType.PHOTOELECTRIC_ABSORPTION, new NumberInterpolatingTreeMap()); table.put(AttenuationType.ELECTRON_FIELD_PAIRPRODUCTION, new NumberInterpolatingTreeMap()); table.put(AttenuationType.NUCLEAR_FIELD_PAIRPRODUCTION, new NumberInterpolatingTreeMap()); table.put(AttenuationType.TOTAL_WITH_COHERENT_ATTENUATION, new NumberInterpolatingTreeMap()); table.put(AttenuationType.TOTAL_WITHOUT_COHERENT_ATTENUATION, new NumberInterpolatingTreeMap()); try { URL url = new URL(nistDBUrl + "/cgi-bin/Xcom/data.pl"); URLConnection conn = url.openConnection(); conn.setDoOutput(true); OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); wr.write(urlSpec); wr.flush(); BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while(true){ line = rd.readLine(); if (line != null) { if (line.length()> 0) { String substr = line.substring(0,1); if (substr != null){ if(line.length()> 0 && line.substring(0,1).matches("\\p{Digit}+")){ break; } } } } else { System.out.println("No attenuation coefficients found for "+ composition); return null; } } do{ addEntryToMap(table,line, att); }while ((line = rd.readLine()) != null); } catch (Exception e) { e.printStackTrace(); return null; } return table; } private static String getCompositionAsString( WeightedAtomicComposition comp) { TreeMap<String, Double> table = comp.getCompositionTable(); String composition = ""; Set<String> keys = table.keySet(); Iterator<String> it =keys.iterator(); NumberFormat f = NumberFormat.getInstance(); f.setGroupingUsed(false); while(it.hasNext()){ String text = it.next(); text += (" " + f.format(table.get(text))+ " "); composition+=text; } return composition; } private static void addEntryToMap( TreeMap<AttenuationType, NumberInterpolatingTreeMap> table, String line, ArrayList<AttenuationType> att) { Scanner s = new Scanner(line); double energy = Evaluator.getValue(s.next().trim()); NumberInterpolatingTreeMap mp; if(att.contains(AttenuationType.COHERENT_ATTENUATION)){ mp = table.get(AttenuationType.COHERENT_ATTENUATION); mp.put(energy, Evaluator.getValue(s.next().trim())); } if(att.contains(AttenuationType.INCOHERENT_ATTENUATION)){ mp = table.get(AttenuationType.INCOHERENT_ATTENUATION); mp.put(energy, Evaluator.getValue(s.next().trim())); } if(att.contains(AttenuationType.PHOTOELECTRIC_ABSORPTION)){ mp = table.get(AttenuationType.PHOTOELECTRIC_ABSORPTION); mp.put(energy, Evaluator.getValue(s.next().trim())); } if(att.contains(AttenuationType.NUCLEAR_FIELD_PAIRPRODUCTION)){ mp = table.get(AttenuationType.NUCLEAR_FIELD_PAIRPRODUCTION); mp.put(energy, Evaluator.getValue(s.next().trim())); } if(att.contains(AttenuationType.ELECTRON_FIELD_PAIRPRODUCTION)){ mp = table.get(AttenuationType.ELECTRON_FIELD_PAIRPRODUCTION); mp.put(energy, Evaluator.getValue(s.next().trim())); } if(att.contains(AttenuationType.TOTAL_WITH_COHERENT_ATTENUATION)){ mp = table.get(AttenuationType.TOTAL_WITH_COHERENT_ATTENUATION); mp.put(energy, Evaluator.getValue(s.next().trim())); } if(att.contains(AttenuationType.TOTAL_WITHOUT_COHERENT_ATTENUATION)){ mp = table.get(AttenuationType.TOTAL_WITHOUT_COHERENT_ATTENUATION); mp.put(energy, Evaluator.getValue(s.next().trim())); } } } /* * Copyright (C) 2010-2014 Rotimi X Ojo * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */