/*
* Copyright (c) 2012 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package uk.ac.diamond.scisoft.analysis.crystallography;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.measure.quantity.Length;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import org.jscience.physics.amount.Amount;
/**
* Since we cannot have eclipse preferences in this plugin, but
* we should access them here, we use the user.home to store the
* properties and to register them here.
*
* This class is a bean which is persisted to disk and can be deep
* cloned by the UI when the user is creating another calibrant list.
*/
public class CalibrationStandards implements Serializable, Cloneable {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((cal2peaks == null) ? 0 : cal2peaks.hashCode());
result = prime * result + ((selectedCalibrant == null) ? 0 : selectedCalibrant.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CalibrationStandards other = (CalibrationStandards) obj;
if (cal2peaks == null) {
if (other.cal2peaks != null)
return false;
} else if (!cal2peaks.equals(other.cal2peaks))
return false;
if (selectedCalibrant == null) {
if (other.selectedCalibrant != null)
return false;
} else if (!selectedCalibrant.equals(other.selectedCalibrant))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
public final static Unit<Length> NANOMETRE = SI.NANO(SI.METRE);
public final static Unit<Length> ANGSTROM = NonSI.ANGSTROM;
private Map<String, CalibrantSpacing> cal2peaks;
private String version;
private String selectedCalibrant;
@Override
public CalibrationStandards clone() {
final CalibrationStandards ret = new CalibrationStandards();
ret.cal2peaks = new HashMap<String, CalibrantSpacing>(cal2peaks.size());
for (String key : cal2peaks.keySet()) {
ret.cal2peaks.put(key, cal2peaks.get(key).clone());
}
ret.version = version;
ret.selectedCalibrant = selectedCalibrant;
return ret;
}
/**
* Used for bean contract, use CalibrationStandards.getInstance() instead.
*/
public CalibrationStandards() {
version = null;
cal2peaks = null;
}
/**
* @return list of calibrants' names
*/
public List<String> getCalibrantList() {
// cal2peaks must be a LinkedHashMap for this to work.
return new ArrayList<String>(cal2peaks.keySet());
}
/**
* Get calibrant from given name
* @param calibrant
* @return calibrant
*/
public CalibrantSpacing getCalibrationPeakMap(String calibrant) {
return cal2peaks.get(calibrant);
}
/**
*
* @param cs
* @return calibrant
*/
public CalibrantSpacing addCalibrant(CalibrantSpacing cs) {
return cal2peaks.put(cs.getName(), cs);
}
public CalibrantSpacing removeCalibrant(String calibrantName) {
return cal2peaks.remove(calibrantName);
}
/**
* Calling this method saves this CalibrationStandards as the persisted one
* for all of Dawn. Only call when sure that this is the required standards.
* @throws Exception
*/
public void save() throws Exception {
CalibrationFactory.saveCalibrationStandards(this);
}
// **Update** this when default calibrants have changed
static final String CURRENT_VERSION = "1.0.5";
/**
* Default list of calibrants TODO add whatever Alun needs.
*
* @return map
*/
static Map<String, CalibrantSpacing> createDefaultCalibrants() {
LinkedHashMap<String, CalibrantSpacing> tmp = new LinkedHashMap<String, CalibrantSpacing>();
CalibrantSpacing calibrant = new CalibrantSpacing("Collagen Wet"); // FIXME reference
calibrant.addHKL(new HKL(0, 0, 1, Amount.valueOf(67.0, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 2, Amount.valueOf(33.5, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 3, Amount.valueOf(22.3, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 4, Amount.valueOf(16.75, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 5, Amount.valueOf(13.4, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 6, Amount.valueOf(11.6, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 7, Amount.valueOf(9.6, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 8, Amount.valueOf(8.4, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 9, Amount.valueOf(7.4, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 10, Amount.valueOf(6.7, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 11, Amount.valueOf(6.1, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 12, Amount.valueOf(5.6, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 13, Amount.valueOf(5.15, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 15, Amount.valueOf(4.46, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 20, Amount.valueOf(3.35, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 21, Amount.valueOf(3.2, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 22, Amount.valueOf(3.05, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 30, Amount.valueOf(2.2, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 35, Amount.valueOf(1.9, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 41, Amount.valueOf(1.6, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 52, Amount.valueOf(1.3, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 71, Amount.valueOf(0.95, NANOMETRE)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("Collagen Dry"); // FIXME reference
calibrant.addHKL(new HKL(0, 0, 1, Amount.valueOf(65.3, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 2, Amount.valueOf(32.7, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 3, Amount.valueOf(21.8, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 4, Amount.valueOf(16.3, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 5, Amount.valueOf(13.1, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 6, Amount.valueOf(10.9, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 7, Amount.valueOf(9.33, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 8, Amount.valueOf(8.16, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 9, Amount.valueOf(7.26, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 10, Amount.valueOf(6.53, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 11, Amount.valueOf(5.94, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 12, Amount.valueOf(5.44, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 13, Amount.valueOf(5.02, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 14, Amount.valueOf(4.66, NANOMETRE)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("Ag Behenate"); // Huang, Toraya, Blanton & Wu, 1993 (58.380)
calibrant.addHKL(new HKL(0, 0, 1, Amount.valueOf(5.8380, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 2, Amount.valueOf(2.9190, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 3, Amount.valueOf(1.9460, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 4, Amount.valueOf(1.4595, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 5, Amount.valueOf(1.1676, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 6, Amount.valueOf(0.97300, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 7, Amount.valueOf(0.83400, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 8, Amount.valueOf(0.72975, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 9, Amount.valueOf(0.64867, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 10, Amount.valueOf(0.58380, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 11, Amount.valueOf(0.53073, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 12, Amount.valueOf(0.48650, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 13, Amount.valueOf(0.44908, NANOMETRE)));
calibrant.addHKL(new HKL(0, 0, 14, Amount.valueOf(0.417, NANOMETRE)));
//doublet from gisax.com
calibrant.addHKL(new HKL(Amount.valueOf(0.458996, NANOMETRE)));
calibrant.addHKL(new HKL(Amount.valueOf(0.45300, NANOMETRE)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("HDPE"); // FIXME reference
calibrant.addHKL(new HKL(1, 1, 0, Amount.valueOf(0.4166, NANOMETRE)));
calibrant.addHKL(new HKL(2, 0, 0, Amount.valueOf(0.378 , NANOMETRE)));
calibrant.addHKL(new HKL(2, 1, 0, Amount.valueOf(0.3014, NANOMETRE)));
calibrant.addHKL(new HKL(0, 2, 0, Amount.valueOf(0.249 , NANOMETRE)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("Silicon"); // 2010 CODATA (5.4310205, Diamond FCC)
calibrant.addHKL(new HKL(1, 1, 1, Amount.valueOf(3.1356011, ANGSTROM)));
calibrant.addHKL(new HKL(2, 2, 0, Amount.valueOf(1.9201557, ANGSTROM)));
calibrant.addHKL(new HKL(3, 1, 1, Amount.valueOf(1.6375143, ANGSTROM)));
calibrant.addHKL(new HKL(4, 0, 0, Amount.valueOf(1.3577551, ANGSTROM)));
calibrant.addHKL(new HKL(3, 3, 1, Amount.valueOf(1.2459616, ANGSTROM)));
calibrant.addHKL(new HKL(4, 2, 2, Amount.valueOf(1.1086024, ANGSTROM)));
calibrant.addHKL(new HKL(3, 3, 3, Amount.valueOf(1.0452004, ANGSTROM))); // 511
calibrant.addHKL(new HKL(4, 4, 0, Amount.valueOf(0.96007786, ANGSTROM)));
calibrant.addHKL(new HKL(5, 3, 1, Amount.valueOf(0.91801002, ANGSTROM)));
calibrant.addHKL(new HKL(6, 2, 0, Amount.valueOf(0.85871974, ANGSTROM)));
calibrant.addHKL(new HKL(5, 3, 3, Amount.valueOf(0.82822286, ANGSTROM)));
calibrant.addHKL(new HKL(4, 4, 4, Amount.valueOf(0.78390029, ANGSTROM)));
calibrant.addHKL(new HKL(5, 5, 1, Amount.valueOf(0.76049498, ANGSTROM))); // 711
calibrant.addHKL(new HKL(6, 4, 2, Amount.valueOf(0.72575064, ANGSTROM)));
calibrant.addHKL(new HKL(5, 5, 3, Amount.valueOf(0.70705864, ANGSTROM))); // 731
calibrant.addHKL(new HKL(8, 0, 0, Amount.valueOf(0.67887756, ANGSTROM)));
calibrant.addHKL(new HKL(7, 3, 3, Amount.valueOf(0.66350476, ANGSTROM)));
calibrant.addHKL(new HKL(5, 5, 5, Amount.valueOf(0.62712023, ANGSTROM))); // 751
calibrant.addHKL(new HKL(8, 4, 0, Amount.valueOf(0.60720655, ANGSTROM)));
// calibrant.addHKL(new HKL(, Amount.valueOf(, ANGSTROM)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("Cr2O3"); // NIST SRM 674 (4.95916(12), 13.5972(6),
// trigonal - hexagonal scalenohedral; IUCR space group #166)
calibrant.addHKL(new HKL(Amount.valueOf(3.645, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(2.672, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(2.487, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(2.181, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(1.819, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(1.676, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(1.467, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(1.433, ANGSTROM)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("CeO2"); // NIST SRM 674 (5.41129, FCC)
calibrant.addHKL(new HKL(1, 1, 1, Amount.valueOf(3.12421, ANGSTROM)));
calibrant.addHKL(new HKL(2, 0, 0, Amount.valueOf(2.70565, ANGSTROM)));
calibrant.addHKL(new HKL(2, 2, 0, Amount.valueOf(1.91318, ANGSTROM)));
calibrant.addHKL(new HKL(3, 1, 1, Amount.valueOf(1.63157, ANGSTROM)));
calibrant.addHKL(new HKL(2, 2, 2, Amount.valueOf(1.56210, ANGSTROM)));
calibrant.addHKL(new HKL(4, 0, 0, Amount.valueOf(1.35282, ANGSTROM)));
calibrant.addHKL(new HKL(3, 3, 1, Amount.valueOf(1.24144, ANGSTROM)));
calibrant.addHKL(new HKL(4, 2, 0, Amount.valueOf(1.21000, ANGSTROM)));
calibrant.addHKL(new HKL(4, 2, 2, Amount.valueOf(1.10457, ANGSTROM)));
calibrant.addHKL(new HKL(3, 3, 3, Amount.valueOf(1.04140, ANGSTROM))); // 511
calibrant.addHKL(new HKL(4, 4, 0, Amount.valueOf(0.956590, ANGSTROM)));
calibrant.addHKL(new HKL(5, 3, 1, Amount.valueOf(0.914675, ANGSTROM)));
calibrant.addHKL(new HKL(4, 4, 2, Amount.valueOf(0.901882, ANGSTROM))); // 600
calibrant.addHKL(new HKL(6, 2, 0, Amount.valueOf(0.855600, ANGSTROM)));
calibrant.addHKL(new HKL(5, 3, 3, Amount.valueOf(0.825214, ANGSTROM)));
calibrant.addHKL(new HKL(6, 2, 2, Amount.valueOf(0.815783, ANGSTROM)));
calibrant.addHKL(new HKL(5, 5, 1, Amount.valueOf(0.757732, ANGSTROM))); // 711
calibrant.addHKL(new HKL(6, 4, 0, Amount.valueOf(0.750411, ANGSTROM)));
calibrant.addHKL(new HKL(6, 4, 2, Amount.valueOf(0.723114, ANGSTROM)));
calibrant.addHKL(new HKL(5, 5, 3, Amount.valueOf(0.704490, ANGSTROM))); // 731
calibrant.addHKL(new HKL(8, 0, 0, Amount.valueOf(0.676411, ANGSTROM)));
calibrant.addHKL(new HKL(7, 3, 3, Amount.valueOf(0.661094, ANGSTROM)));
calibrant.addHKL(new HKL(6, 4, 4, Amount.valueOf(0.656215, ANGSTROM))); // 820
calibrant.addHKL(new HKL(6, 6, 0, Amount.valueOf(0.637727, ANGSTROM))); // 822
calibrant.addHKL(new HKL(7, 5, 1, Amount.valueOf(0.624842, ANGSTROM)));
calibrant.addHKL(new HKL(6, 6, 2, Amount.valueOf(0.620718, ANGSTROM)));
// calibrant.addHKL(new HKL(, Amount.valueOf(, ANGSTROM)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("Bees Wax"); // FIXME reference
calibrant.addHKL(new HKL(Amount.valueOf(3.6, ANGSTROM)));
calibrant.addHKL(new HKL(Amount.valueOf(2.4, ANGSTROM)));
tmp.put(calibrant.getName(), calibrant);
calibrant = new CalibrantSpacing("LaB6"); // NIST SRM 660a (4.1569162, Cubic)
calibrant.addHKL(new HKL(1, 0, 0, Amount.valueOf(4.156916, ANGSTROM)));
calibrant.addHKL(new HKL(1, 1, 0, Amount.valueOf(2.939383, ANGSTROM)));
calibrant.addHKL(new HKL(1, 1, 1, Amount.valueOf(2.399996, ANGSTROM)));
calibrant.addHKL(new HKL(2, 0, 0, Amount.valueOf(2.078458, ANGSTROM)));
calibrant.addHKL(new HKL(2, 1, 0, Amount.valueOf(1.859029, ANGSTROM)));
calibrant.addHKL(new HKL(2, 1, 1, Amount.valueOf(1.697053, ANGSTROM)));
calibrant.addHKL(new HKL(2, 2, 0, Amount.valueOf(1.469691, ANGSTROM)));
calibrant.addHKL(new HKL(3, 0, 0, Amount.valueOf(1.385638, ANGSTROM)));
calibrant.addHKL(new HKL(3, 1, 0, Amount.valueOf(1.314532, ANGSTROM)));
calibrant.addHKL(new HKL(3, 1, 1, Amount.valueOf(1.253357, ANGSTROM)));
calibrant.addHKL(new HKL(2, 2, 2, Amount.valueOf(1.199998, ANGSTROM)));
calibrant.addHKL(new HKL(3, 2, 0, Amount.valueOf(1.152921, ANGSTROM)));
calibrant.addHKL(new HKL(3, 2, 1, Amount.valueOf(1.110982, ANGSTROM)));
calibrant.addHKL(new HKL(4, 0, 0, Amount.valueOf(1.039229, ANGSTROM)));
calibrant.addHKL(new HKL(4, 1, 0, Amount.valueOf(1.008200, ANGSTROM)));
calibrant.addHKL(new HKL(3, 3, 0, Amount.valueOf(0.979794, ANGSTROM)));
calibrant.addHKL(new HKL(3, 3, 1, Amount.valueOf(0.953661, ANGSTROM)));
calibrant.addHKL(new HKL(4, 2, 0, Amount.valueOf(0.929514, ANGSTROM)));
calibrant.addHKL(new HKL(4, 2, 1, Amount.valueOf(0.907113, ANGSTROM)));
calibrant.addHKL(new HKL(3, 3, 2, Amount.valueOf(0.886257, ANGSTROM)));
calibrant.addHKL(new HKL(4, 2, 2, Amount.valueOf(0.848526, ANGSTROM)));
calibrant.addHKL(new HKL(4, 2, 2, Amount.valueOf(0.848526, ANGSTROM)));
calibrant.addHKL(new HKL(5, 0, 0, Amount.valueOf(0.831383, ANGSTROM)));
calibrant.addHKL(new HKL(5, 0, 0, Amount.valueOf(0.815238, ANGSTROM)));
calibrant.addHKL(new HKL(5, 1, 1, Amount.valueOf(0.799998, ANGSTROM)));
tmp.put(calibrant.getName(), calibrant);
return tmp;
}
public Map<String, CalibrantSpacing> getCal2peaks() {
return cal2peaks;
}
public String getVersion() {
return version;
}
public void setCal2peaks(Map<String, CalibrantSpacing> cal2peaks) {
this.cal2peaks = cal2peaks;
}
public void setVersion(String version) {
this.version = version;
}
/**
* @return name of selected calibrant (can be null)
*/
public String getSelectedCalibrant() {
return selectedCalibrant;
}
/**
* Set name of selected calibrant
* @param selectedCalibrant
*/
public void setSelectedCalibrant(String selectedCalibrant) {
setSelectedCalibrant(selectedCalibrant, false);
}
/**
* Set name of selected calibrant
* @param selCal
* @param fireListeners
*/
public void setSelectedCalibrant(String selCal, boolean fireListeners) {
this.selectedCalibrant = selCal;
if (fireListeners) CalibrationFactory.fireCalibrantSelectionListeners(this, selectedCalibrant);
}
/**
* @return the current selected calibrant
*/
public CalibrantSpacing getCalibrant() {
return getCalibrationPeakMap(getSelectedCalibrant());
}
/**
* Default get default calibrant spacing for named calibrant
* If not a default calibrant null returned.
* @param name
* @return calibrant
*/
public CalibrantSpacing getDefaultSpacing(String name) {
Map<String, CalibrantSpacing> cal = createDefaultCalibrants();
if (cal.containsKey(name)) {
return cal.get(name);
}
return null;
}
/**
* Set modifiability of standard
* @param isModifiable if true then adding more calibrants will throw an exception
*/
public void setModifiable(boolean isModifiable) {
if (isModifiable) {
cal2peaks = new LinkedHashMap<String, CalibrantSpacing>(cal2peaks);
} else {
cal2peaks = Collections.unmodifiableMap(cal2peaks);
}
}
public boolean isEmpty() {
return cal2peaks==null || cal2peaks.isEmpty();
}
}