/*
* 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.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.measure.quantity.Length;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import org.jscience.physics.amount.Amount;
public class CalibrantGenerator {
public final static Unit<Length> NANO = SI.NANO(SI.METER);
public static enum Cubic {
SIMPLE,BCC,FCC,DIAMOND;
}
public static CalibrantSpacing createCubicStandard(String name, double a, int nReflections, Cubic type) {
CalibrantSpacing calibrant = new CalibrantSpacing(name);
List<HKL> listHKL = new ArrayList<HKL>();
int h = 0;
int k = 0;
int l = 1;
while (listHKL.size() < nReflections) {
if (isAllowedCubic(h,k,l, type)) {
HKL hkl = calculateCubicLatticeSpacing(a, h, k, l);
boolean duplicate = false;
for (HKL i: listHKL) {
if (i.getDNano() == hkl.getDNano()) {
duplicate = true;
break;
}
}
if (!duplicate) listHKL.add(hkl);
}
if (l == k && l == h) {
l++;
k = 0;
h = 0;
}
else if (k < l && k == h) {
k++;
h = 0;
}
else h++;
}
Collections.sort(listHKL, new Comparator<HKL>() {
@Override
public int compare(HKL h1, HKL h2) {
return (int)Math.signum((h2.getDNano() - h1.getDNano()));
}
});
for (int i = 0; i < listHKL.size(); i++) listHKL.get(i).setRingName("Position " + i);
calibrant.setHKLs(listHKL);
return calibrant;
}
private static boolean isAllowedCubic(int h, int k, int l, Cubic type){
switch (type) {
case SIMPLE:
return true;
case BCC:
int testBcc = (h + k + l)%2;
if (testBcc == 0) return true;
break;
case DIAMOND:
int testd1 = h%2 + k%2 + l%2;
int testd2 = (h+k+l)%4;
if (testd1 == 0 && testd2 == 0) return true;
if (testd1 == 3) return true;
break;
case FCC:
int testFcc = h%2 + k%2 + l%2;
if (testFcc == 0) return true;
if (testFcc == 3) return true;
break;
default:
break;
}
return false;
}
public static CalibrantSpacing createRhombohedralStandard(String name, double a, double c, int maxhkl) {
CalibrantSpacing calibrant = new CalibrantSpacing(name);
List<HKL> listHKL = new ArrayList<HKL>();
for (int l = -maxhkl; l < maxhkl; l++) {
for (int k = -maxhkl; k < maxhkl; k++) {
for (int h = -maxhkl; h < maxhkl; h++) {
if (h==0 && k == 0) continue;
if (!isAllowedRhombohedral(h,k,l)) continue;
HKL hkl = calculateHexagonalLatticeSpacing(a, c, h, k, l);
boolean duplicate = false;
for (HKL i: listHKL) {
if (i.getDNano() == hkl.getDNano()) {
duplicate = true;
break;
}
}
if (duplicate) continue;
listHKL.add(hkl);
}
}
}
Collections.sort(listHKL, new Comparator<HKL>() {
@Override
public int compare(HKL h1, HKL h2) {
return (int)Math.signum((h2.getDNano() - h1.getDNano()));
}
});
for (int i = 0; i < listHKL.size(); i++) listHKL.get(i).setRingName("Position " + i);
calibrant.setHKLs(listHKL.subList(0, maxhkl));
return calibrant;
}
private static boolean isAllowedRhombohedral(int h, int k, int l) {
if (h != k && k != l && h != l && h != -k && h != 0 && k != 0 && l != 0)
if ((-h+k+l)%3 == 0) return true;
if (l == 0 && h != k && h != 0 && k != 0)
if ((-h + k)%3 == 0) return true;
int i = -(h+k);
if (h == k && i == -2 * h && h != 0)
if ((l)%3 == 0) return true;
if (h == -k && i == 0 && h != 0 && l != 0)
if ((h+l)%3 == 0 && (l)%2 == 0) return true;
if (h == 0 && k == 0 && i == 0 && l != 0)
if ((l)%6 == 0) return true;
if (h == -k && i == 0 && l == 0 && h != 0)
if ((h)%3 == 0) return true;
return false;
}
private static HKL calculateCubicLatticeSpacing(double a, int h, int k, int l) {
double d = a/(Math.sqrt((Math.pow(h, 2)+Math.pow(k, 2)+Math.pow(l, 2))));
return new HKL(h, k, l, Amount.valueOf(d, NANO));
}
private static HKL calculateHexagonalLatticeSpacing(double a, double c, int h, int k, int l) {
double d = Math.sqrt(1/((4./3.)*(Math.pow(h, 2)+(h*k)+Math.pow(k, 2))/Math.pow(a, 2)+(Math.pow(l, 2)/Math.pow(c, 2))));
return new HKL(h, k, l, Amount.valueOf(d, NANO));
}
}