542 lines
20 KiB
Java
542 lines
20 KiB
Java
|
|
import ch.psi.pshell.device.AccessType;
|
|
import ch.psi.pshell.device.CameraImageDescriptor;
|
|
import ch.psi.pshell.device.MatrixCalibration;
|
|
import ch.psi.pshell.device.Device;
|
|
import ch.psi.pshell.device.Writable;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import ch.psi.pshell.epics.*;
|
|
import ch.psi.utils.Arr;
|
|
|
|
/**
|
|
* Implementation of Scienta spectrometer analyser.
|
|
*/
|
|
public class Scienta extends AreaDetector {
|
|
final ChannelInteger acquire;
|
|
final ChannelInteger energyCount, ThetaYCount, ThetaXCount;
|
|
final ChannelDouble energyWidth, ThetaYWidth, lowThetaX, highThetaX, stepSizeThetaX, ThetaXWidth;
|
|
final ControlledVariable lowEnergy, centerEnergy, highEnergy, stepSize, lowThetaY, centerThetaY, highThetaY, stepSizeThetaY, centerThetaX;
|
|
final ControlledVariable excitationEnergy;
|
|
final GenericArray data;
|
|
final ChannelInteger totalSteps, currentStep, exposuresComplete;
|
|
final DiscretePositioner lensMode, acquisitionMode, energyMode, detectorMode, elementSet, passEnergy;
|
|
final ChannelString estTime, detectorState;
|
|
final ChannelByteArray status;
|
|
final ChannelInteger slices, slicesReadback, channels, channelsReadback;
|
|
final Stats[] stats;
|
|
final String channelCtrl;
|
|
final Device[] monitoredChildren;
|
|
final boolean test;
|
|
final ChannelDouble exposureDev;
|
|
|
|
public Scienta(final String name, final String channelPrefix, boolean test) {
|
|
this(name, channelPrefix + ":cam1", channelPrefix + ":image1", test);
|
|
}
|
|
|
|
public Scienta(String name, String channelCtrl, String channelData, boolean test) {
|
|
super(name, channelCtrl, channelData);
|
|
this.test=test;
|
|
this.channelCtrl = channelCtrl;
|
|
|
|
acquire = new ChannelInteger(name + " aquire", channelCtrl + ":Acquire", false);
|
|
|
|
lowEnergy = new ControlledVariable(name + " low energy", channelCtrl + ":LOW_ENERGY", channelCtrl + ":LOW_ENERGY_RBV", false);
|
|
centerEnergy = new ControlledVariable(name + " center energy", channelCtrl + ":CENTRE_ENERGY", channelCtrl + ":CENTRE_ENERGY_RBV", false);
|
|
highEnergy = new ControlledVariable(name + " high energy", channelCtrl + ":HIGH_ENERGY", channelCtrl + ":HIGH_ENERGY_RBV", false);
|
|
stepSize = new ControlledVariable(name + " step size", channelCtrl + ":STEP_SIZE", channelCtrl + ":STEP_SIZE_RBV", false);
|
|
energyWidth = new ChannelDouble(name + " energy width", channelCtrl + ":ENERGY_WIDTH_RBV", 3, false);
|
|
energyWidth.setAccessType(AccessType.Read);
|
|
energyCount = new ChannelInteger(name + " energy count", channelCtrl + ":COUNT_RBV", false);
|
|
energyCount.setAccessType(AccessType.Read);
|
|
exposureDev = new ChannelDouble(name + " exposure time", channelCtrl + ":AcquireTime", 3, false);
|
|
|
|
lowThetaY = new ControlledVariable(name + " low Theta Y", channelCtrl + ":LOW_THETA_Y", channelCtrl + ":LOW_THETA_Y_RBV", false);
|
|
centerThetaY = new ControlledVariable(name + " center Theta Y", channelCtrl + ":CENTRE_THETA_Y", channelCtrl + ":CENTRE_THETA_Y_RBV", false);
|
|
highThetaY = new ControlledVariable(name + " high Theta Y", channelCtrl + ":HIGH_THETA_Y", channelCtrl + ":HIGH_THETA_Y_RBV", false);
|
|
stepSizeThetaY = new ControlledVariable(name + " Theta Y step size", channelCtrl + ":THETA_Y_STEP_SIZE", channelCtrl + ":THETA_Y_STEP_SIZE_RBV", false);
|
|
ThetaYWidth = new ChannelDouble(name + " Theta Y width", channelCtrl + ":THETA_Y_WIDTH_RBV", 3, false);
|
|
ThetaYWidth.setAccessType(AccessType.Read);
|
|
ThetaYCount = new ChannelInteger(name + " Theta Y count", channelCtrl + ":THETA_Y_COUNT_RBV", false);
|
|
ThetaYCount.setAccessType(AccessType.Read);
|
|
|
|
lowThetaX = new ChannelDouble(name + " low Theta X", channelCtrl + ":LOW_SLICE_RBV", 3, false);
|
|
lowThetaX.setAccessType(AccessType.Read);
|
|
centerThetaX = new ControlledVariable(name + " center Theta X", channelCtrl + ":CENTRE_SLICE", channelCtrl + ":CENTRE_SLICE_RBV", false);
|
|
highThetaX = new ChannelDouble(name + " high Theta X", channelCtrl + ":HIGH_SLICE_RBV", 3, false);
|
|
highThetaX.setAccessType(AccessType.Read);
|
|
stepSizeThetaX = new ChannelDouble(name + " Theta X step size", channelCtrl + ":SLICE_STEP_SIZE_RBV", 3, false);
|
|
stepSizeThetaX.setAccessType(AccessType.Read);
|
|
ThetaXWidth = new ChannelDouble(name + " ThetaX width", channelCtrl + ":SLICE_WIDTH_RBV", 3, false);
|
|
ThetaXWidth.setAccessType(AccessType.Read);
|
|
ThetaXCount = new ChannelInteger(name + " Theta count", channelCtrl + ":SLICE_COUNT_RBV", false);
|
|
ThetaXCount.setAccessType(AccessType.Read);
|
|
|
|
passEnergy = new DiscretePositioner(name + " pass energy", channelCtrl + ":PASS_ENERGY", channelCtrl + ":PASS_ENERGY_RBV");
|
|
lensMode = new DiscretePositioner(name + " lens mode", channelCtrl + ":LENS_MODE", channelCtrl + ":LENS_MODE_RBV");
|
|
acquisitionMode = new DiscretePositioner(name + " acquisition mode", channelCtrl + ":ACQ_MODE", channelCtrl + ":ACQ_MODE_RBV");
|
|
energyMode = new DiscretePositioner(name + " energy mode", channelCtrl + ":ENERGY_MODE", channelCtrl + ":ENERGY_MODE_RBV");
|
|
detectorMode = new DiscretePositioner(name + " detector mode", channelCtrl + ":DETECTOR_MODE", channelCtrl + ":DETECTOR_MODE_RBV");
|
|
elementSet = new DiscretePositioner(name + " element set", channelCtrl + ":ELEMENT_SET_RBV", channelCtrl + ":ELEMENT_SET_RBV");
|
|
elementSet.setAccessType(AccessType.Read);
|
|
|
|
slices = new ChannelInteger(name + " slices", channelCtrl + ":SLICES", false);
|
|
slicesReadback = new ChannelInteger(name + " slices rbv", channelCtrl + ":SLICES_RBV", false);
|
|
slicesReadback.setAccessType(AccessType.Read);
|
|
channels = new ChannelInteger(name + " channels", channelCtrl + ":CHANNELS", false);
|
|
channelsReadback = new ChannelInteger(name + " channels rbv", channelCtrl + ":CHANNELS_RBV", false);
|
|
channelsReadback.setAccessType(AccessType.Read);
|
|
excitationEnergy = new ControlledVariable(name + " excitation energy", channelCtrl + ":EXCITATION_ENERGY", channelCtrl + ":EXCITATION_ENERGY_RBV", false);
|
|
|
|
data = new GenericArray(name + " data", channelData + ":ArrayData", SIZE_MAX, false); //If nullable on invalidd value, read blocks on Scienta.
|
|
data.setAutoResolveType(false);
|
|
|
|
totalSteps = new ChannelInteger(name + " total steps", channelCtrl + ":STEPS_RBV", false);
|
|
totalSteps.setAccessType(AccessType.Read);
|
|
currentStep = new ChannelInteger(name + " current step", channelCtrl + ":STEPS_COUNTER_RBV", false);
|
|
currentStep.setAccessType(AccessType.Read);
|
|
exposuresComplete = new ChannelInteger(name + " exp complete", channelCtrl + ":NumExposuresCounter_RBV", false);
|
|
exposuresComplete.setAccessType(AccessType.Read);
|
|
estTime = new ChannelString(name + " estimated time", channelCtrl + ":ETA_STR", false);
|
|
estTime.setAccessType(AccessType.Read);
|
|
detectorState= new ChannelString(name + " detector state", channelCtrl + ":DetectorState_RBV", false);
|
|
detectorState.setAccessType(AccessType.Read);
|
|
status= new ChannelByteArray(name + " status", channelCtrl + ":StatusMessage_RBV", -1, false){
|
|
protected void onReadout(Object value){
|
|
this.setCache((value==null)?"":new String((byte[])value));
|
|
}
|
|
//protected Object convertFromRead(byte[] value){
|
|
// return (value==null) ? "" : new String((byte[])value);
|
|
//}
|
|
|
|
};
|
|
status.setAccessType(AccessType.Read);
|
|
|
|
monitoredChildren = new Device[]{acquire,
|
|
lowEnergy,centerEnergy,highEnergy,energyWidth,energyCount,
|
|
lowThetaY, centerThetaY, highThetaY, stepSizeThetaY, ThetaYWidth,ThetaYCount,
|
|
lowThetaX, centerThetaX, highThetaX, stepSizeThetaX, ThetaXWidth,ThetaXCount,
|
|
stepSize,totalSteps,currentStep, exposuresComplete, passEnergy,
|
|
lensMode, acquisitionMode, energyMode, detectorMode, elementSet,
|
|
slices, slicesReadback, channels, channelsReadback, excitationEnergy,
|
|
exposureDev, estTime, detectorState, status
|
|
};
|
|
addChildren(monitoredChildren);
|
|
addChildren(new Device[]{
|
|
data,
|
|
});
|
|
|
|
stats = new Stats[5];
|
|
stats[0] = new Stats("CountsR1", 1);
|
|
stats[1] = new Stats("CountsR2", 2);
|
|
stats[2] = new Stats("CountsR3", 3);
|
|
stats[3] = new Stats("CountsR4", 4);
|
|
stats[4] = new Stats("Counts", 5);
|
|
addChildren(stats);
|
|
}
|
|
|
|
@Override
|
|
protected void doStart() throws IOException, InterruptedException {
|
|
|
|
acquire.write(1);
|
|
}
|
|
|
|
|
|
@Override
|
|
protected void doSetSimulated() {
|
|
super.doSetSimulated();
|
|
setCache(passEnergy, "2");
|
|
setCache(lensMode, "Transmission");
|
|
setCache(acquisitionMode, "Fixed");
|
|
setCache(energyMode, "Binding");
|
|
setCache(detectorMode, "ADC");
|
|
setCache(elementSet, "High_Pass_XPS");
|
|
}
|
|
|
|
@Override
|
|
protected void doInitialize() throws IOException, InterruptedException {
|
|
super.doInitialize();
|
|
}
|
|
|
|
@Override
|
|
protected void doUpdate() throws IOException, InterruptedException {
|
|
super.doUpdate();
|
|
for (Device dev : monitoredChildren){
|
|
dev.update();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void doSetMonitored(boolean value) {
|
|
super.doSetMonitored(value);
|
|
for (Device dev : monitoredChildren){
|
|
dev.setMonitored(value);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected CameraImageDescriptor doReadImageDescriptor() throws IOException, InterruptedException {
|
|
CameraImageDescriptor ret = super.doReadImageDescriptor();
|
|
List<Double> channelRange = getChannelRange();
|
|
List<Double> sliceRange = getSliceRange();
|
|
|
|
Double cb = channelRange.get(0);
|
|
Double ce = channelRange.get(1);
|
|
Double sb = sliceRange.get(0);
|
|
Double se = sliceRange.get(1);
|
|
|
|
if ((cb == null) || (ce == null) || (sb == null) || (se == null) || (ret.width == 0) || (ret.height == 0)) {
|
|
ret.calibration = null;
|
|
} else {
|
|
double scaleX = (ce - cb) / Math.max(ret.width - 1, 1);
|
|
double offsetX = cb;
|
|
double scaleY = (se - sb) / Math.max(ret.height - 1, 1);
|
|
double offsetY = sb;
|
|
|
|
ret.calibration = new MatrixCalibration(scaleX, scaleY, offsetX, offsetY);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//Modes
|
|
|
|
public void setAcquisitionMode(String mode) throws IOException, InterruptedException { //acquisitionMode.write(String.valueOf(mode).replaceAll("_", " "));
|
|
acquisitionMode.write(mode);
|
|
}
|
|
|
|
public String getAcquisitionMode() throws IOException, InterruptedException {
|
|
return acquisitionMode.getValue();
|
|
}
|
|
|
|
public void setEnergyMode(String mode) throws IOException, InterruptedException {
|
|
energyMode.write(mode);
|
|
}
|
|
|
|
public String getEnergyMode() throws IOException, InterruptedException {
|
|
return energyMode.getValue();
|
|
}
|
|
|
|
public void setLensMode(String mode) throws IOException, InterruptedException {
|
|
lensMode.write(mode);
|
|
}
|
|
|
|
public String getLensMode() throws IOException, InterruptedException {
|
|
return lensMode.getValue();
|
|
}
|
|
|
|
public String[] getLensModes() throws IOException, InterruptedException {
|
|
return lensMode.getPositions();
|
|
}
|
|
|
|
public void setDetectorMode(String mode) throws IOException, InterruptedException {
|
|
detectorMode.write(mode);
|
|
}
|
|
|
|
public String getDetectorMode() throws IOException, InterruptedException {
|
|
return detectorMode.getValue();
|
|
}
|
|
|
|
public void setElementSet(String mode) throws IOException, InterruptedException {
|
|
throw new IOException("Read-only value");
|
|
}
|
|
|
|
public String getElementSet() throws IOException, InterruptedException {
|
|
return elementSet.getValue();
|
|
}
|
|
|
|
|
|
public void setPassEnergy(int energy) throws IOException, InterruptedException {
|
|
setPassEnergy(String.valueOf(energy));
|
|
}
|
|
|
|
public void setPassEnergy(String energy) throws IOException, InterruptedException {
|
|
passEnergy.write(energy);
|
|
}
|
|
|
|
public String getPassEnergy() throws IOException, InterruptedException {
|
|
return passEnergy.getValue();
|
|
}
|
|
|
|
public DiscretePositioner getPassEnergyDev(){
|
|
return passEnergy;
|
|
}
|
|
|
|
public DiscretePositioner getElementSetDev(){
|
|
return elementSet;
|
|
}
|
|
|
|
public DiscretePositioner getDetectorModeDev(){
|
|
return detectorMode;
|
|
}
|
|
|
|
public DiscretePositioner getLensModeDev(){
|
|
return lensMode;
|
|
}
|
|
|
|
public DiscretePositioner getAcquisitionModeDev(){
|
|
return acquisitionMode;
|
|
}
|
|
|
|
public DiscretePositioner getEnergyModeDev(){
|
|
return energyMode;
|
|
}
|
|
|
|
public Writable getRangeDev(){
|
|
return (Writable) (Object value) -> {
|
|
Integer[] range = (Integer[]) value;
|
|
int[] roi = getROI();
|
|
if ((range[0]!=null) && (range[1]!=null)){
|
|
int from = Math.min(range[0], range[1]);
|
|
int to = Math.max(range[0], range[1]);
|
|
roi[0]=from;
|
|
roi[2]=(to-from);
|
|
}
|
|
if ((range[2]!=null) && (range[3]!=null)){
|
|
int from = Math.min(range[2], range[3]);
|
|
int to = Math.max(range[2], range[3]);
|
|
roi[1]=from;
|
|
roi[3]=(to-from);
|
|
}
|
|
setROI(roi);
|
|
};
|
|
}
|
|
|
|
public void zeroSupplies() throws IOException, InterruptedException {
|
|
writeCtrl("ZERO_SUPPLIES", 1);
|
|
}
|
|
|
|
|
|
//Progress
|
|
//Disconnected operations
|
|
public double getProgress() {
|
|
Double cur = currentStep.take().doubleValue();
|
|
Double total = totalSteps.take().doubleValue();
|
|
if ((cur == null) || (total == null) || (total == 0)) {
|
|
return 0.0;
|
|
}
|
|
return cur / total;
|
|
}
|
|
|
|
|
|
//Direct register access
|
|
public ChannelInteger getAcquire() {
|
|
return acquire;
|
|
}
|
|
|
|
public ControlledVariable getLowEnergy() {
|
|
return lowEnergy;
|
|
}
|
|
|
|
public ControlledVariable getCenterEnergy() {
|
|
return centerEnergy;
|
|
}
|
|
|
|
public ControlledVariable getHighEnergy() {
|
|
return highEnergy;
|
|
}
|
|
|
|
public ControlledVariable getEnergyStepSize() {
|
|
return stepSize;
|
|
}
|
|
|
|
public ChannelDouble getEnergyWidth() {
|
|
return energyWidth;
|
|
}
|
|
|
|
public ChannelInteger getEnergyCount() {
|
|
return energyCount;
|
|
}
|
|
|
|
public ChannelDouble getExposureDev() {
|
|
return exposureDev;
|
|
}
|
|
|
|
public ControlledVariable getLowThetaY() {
|
|
return lowThetaY;
|
|
}
|
|
|
|
public ControlledVariable getCenterThetaY() {
|
|
return centerThetaY;
|
|
}
|
|
|
|
public ControlledVariable getHighThetaY() {
|
|
return highThetaY;
|
|
}
|
|
|
|
public ControlledVariable getThetaYStepSize() {
|
|
return stepSizeThetaY;
|
|
}
|
|
|
|
public ChannelDouble getThetaYWidth() {
|
|
return ThetaYWidth;
|
|
}
|
|
|
|
public ChannelInteger getThetaYCount() {
|
|
return ThetaYCount;
|
|
}
|
|
|
|
public ChannelDouble getLowThetaX() {
|
|
return lowThetaX;
|
|
}
|
|
|
|
public ControlledVariable getCenterThetaX() {
|
|
return centerThetaX;
|
|
}
|
|
|
|
public ChannelDouble getHighThetaX() {
|
|
return highThetaX;
|
|
}
|
|
|
|
public ChannelDouble getThetaXStepSize() {
|
|
return stepSizeThetaX;
|
|
}
|
|
|
|
public ChannelDouble getThetaXWidth() {
|
|
return ThetaXWidth;
|
|
}
|
|
|
|
public ChannelInteger getThetaXCount() {
|
|
return ThetaXCount;
|
|
}
|
|
|
|
public ChannelString getEstTime() {
|
|
return estTime;
|
|
}
|
|
|
|
public ChannelString getDetectorState() {
|
|
return detectorState;
|
|
}
|
|
|
|
public ChannelByteArray getStatus() {
|
|
return status;
|
|
}
|
|
|
|
public ChannelInteger getSlices() {
|
|
return slices;
|
|
}
|
|
|
|
public ChannelInteger getSlicesReadback() {
|
|
return slicesReadback;
|
|
}
|
|
|
|
public ChannelInteger getChannels() {
|
|
return channels;
|
|
}
|
|
|
|
public ChannelInteger getChannelsReadback() {
|
|
return channelsReadback;
|
|
}
|
|
|
|
public ChannelInteger getTotalSteps() {
|
|
return totalSteps;
|
|
}
|
|
|
|
public ChannelInteger getCurrentStep() {
|
|
return currentStep;
|
|
}
|
|
|
|
public ChannelInteger getExposuresComplete() {
|
|
return exposuresComplete;
|
|
}
|
|
|
|
public ControlledVariable getExcitationEnergy() {
|
|
return excitationEnergy;
|
|
}
|
|
|
|
|
|
public List<Double> getChannelRange() throws IOException, InterruptedException {
|
|
ArrayList<Double> ret = new ArrayList<>();
|
|
try {
|
|
if (isSimulated()){
|
|
ret.add(100.0);
|
|
ret.add(200.0);
|
|
} else {
|
|
ret.add(lowEnergy.getReadback().getValue());
|
|
ret.add(highEnergy.getReadback().getValue());
|
|
}
|
|
} catch (Exception ex) {
|
|
ret.add(Double.NaN);
|
|
ret.add(Double.NaN);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public List<Double> getSliceRange() throws IOException, InterruptedException {
|
|
ArrayList<Double> ret = new ArrayList<>();
|
|
try {
|
|
if (isSimulated()){
|
|
ret.add(200.0);
|
|
ret.add(400.0);
|
|
} else {
|
|
String lens=getLensMode();
|
|
if (lens.startsWith("D")){
|
|
ret.add(lowThetaY.getReadback().getValue());
|
|
ret.add(highThetaY.getReadback().getValue());
|
|
} else {
|
|
ret.add(lowThetaX.getValue());
|
|
ret.add(highThetaX.getValue());
|
|
}
|
|
}
|
|
} catch (Exception ex) {
|
|
ret.add(Double.NaN);
|
|
ret.add(Double.NaN);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
public Integer readNumExposures() throws IOException, InterruptedException{
|
|
return (Integer) readCtrl("NumExposures_RBV", Integer.class);
|
|
}
|
|
|
|
public Double readAcqTime() throws IOException, InterruptedException{
|
|
return (Double) readCtrl("AcquireTime_RBV", Double.class);
|
|
}
|
|
|
|
public Stats[] getStats() {
|
|
return stats;
|
|
}
|
|
|
|
public class Stats extends ChannelDouble {
|
|
|
|
final int index;
|
|
final ChannelInteger uid;
|
|
|
|
Stats(String name, int index) {
|
|
super(name, channelCtrl.split(":")[0] + ":Stats" + index + ":Total_RBV", 3, false);
|
|
this.index = index;
|
|
uid = new ChannelInteger(name + " uid", channelCtrl.split(":")[0] + ":Stats" + index + ":UniqueId_RBV", false);
|
|
//setParent(Scienta.this);
|
|
addChild(uid);
|
|
}
|
|
|
|
@Override
|
|
public boolean isReady() throws IOException, InterruptedException {
|
|
Integer imageCounter = getImageCounter().getValue();
|
|
if (imageCounter == null) {
|
|
return false;
|
|
}
|
|
/*
|
|
Integer id = uid.take();
|
|
if ((id == null) || (!imageCounter.equals(id))) {
|
|
uid.update();
|
|
}
|
|
return imageCounter.equals(uid.take());
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public Double read() throws IOException, InterruptedException {
|
|
assertInitialized();
|
|
waitReady(10000);
|
|
return super.read();
|
|
}
|
|
|
|
public int getUID() throws IOException, InterruptedException {
|
|
return uid.getValue();
|
|
}
|
|
}
|
|
}
|