Skip to content
This repository was archived by the owner on Mar 27, 2018. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,92 +11,183 @@
*******************************************************************************/
package org.eclipse.scanning.example.scannable;

import org.eclipse.dawnsci.nexus.NXpositioner;
import java.text.MessageFormat;

import org.eclipse.dawnsci.nexus.INexusDevice;
import org.eclipse.dawnsci.nexus.NXobject;
import org.eclipse.dawnsci.nexus.NXslit;
import org.eclipse.dawnsci.nexus.NexusBaseClass;
import org.eclipse.dawnsci.nexus.NexusException;
import org.eclipse.dawnsci.nexus.NexusNodeFactory;
import org.eclipse.dawnsci.nexus.NexusScanInfo;
import org.eclipse.dawnsci.nexus.NexusScanInfo.ScanRole;
import org.eclipse.dawnsci.nexus.builder.NexusObjectProvider;
import org.eclipse.dawnsci.nexus.builder.NexusObjectWrapper;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.ILazyWriteableDataset;
import org.eclipse.january.dataset.SliceND;
import org.eclipse.scanning.api.IScanAttributeContainer;
import org.eclipse.scanning.api.annotation.scan.ScanFinally;
import org.eclipse.scanning.api.points.IPosition;
import org.eclipse.scanning.api.points.Scalar;
import org.eclipse.scanning.api.scan.rank.IScanRankService;
import org.eclipse.scanning.api.scan.rank.IScanSlice;

/**
* A class to generate take a set of scannables which represent simple slits then write to a NeXus file
* as the positions are set during the scan.
*
* See http://confluence.diamond.ac.uk/pages/viewpage.action?pageId=37814632
*
<pre>
primary_slit:NXslit
x_gap = {NX_NUMBER}
@local_name = "s1gapX"
@units = "mm"
@controller_record = {NX_CHAR} //EPICS name
y_gap = {NX_NUMBER}
@local_name = "s1gapY"
@units = "mm"
@controller_record = {NX_CHAR} //EPICS name
transforms:NXtransformations
x_centre = {NX_NUMBER}
@transformation_type = "translation"
@vector = 1,0,0,
@depends_on = "y_centre"
@units = "mm"
@controller_record = {NX_CHAR} //EPICS name
y_centre = {NX_NUMBER}
@transformation_type = "translation"
@vector = 0,1,0,
@depends_on = "."
@offset = 0,0,-14500 //This may change
@units = "mm"
@controller_record = {NX_CHAR} //EPICS name
beam:NXbeam
//Removed distance from here, since it's in the "y_centre" above
incident_beam_divergence[2,i] = {NX_FLOAT}
@units = "radians"
final_beam_divergence[2,i] = {NX_FLOAT}
@units = "radians"
motors:NXcollection
downstream_x:NXpositioner
name = "s1dsX"
description = "Downstream X position"
value = {NX_NUMBER}
@units = "mm"
controller_record = {NX_CHAR} //EPICS name
downstream_y:NXpositioner
name = "s1dsY"
description = "Downstream Y position"
value = {NX_NUMBER}
@units = "mm"
controller_record = {NX_CHAR} //EPICS name
upstream_x:NXpositioner
name = "s1usX"
description = "Upstream X position"
value = {NX_NUMBER}
@units = "mm"
controller_record = {NX_CHAR} //EPICS name
upstream_y:NXpositioner
name = "s1usY"
description = "Upstream Y position"
value = {NX_NUMBER}
@units = "mm"
controller_record = {NX_CHAR} //EPICS name
</pre>

*
* @author Matthew Gerring
*
* @see {@link MockScannableConfiguration}
*/
public class MockNeXusSlit extends MockNeXusScannable {
public class MockNeXusSlit extends MockScannable implements INexusDevice<NXslit> {

private ILazyWriteableDataset xLzSet;
private ILazyWriteableDataset yLzSet;
private ILazyWriteableDataset xLzValue;
private ILazyWriteableDataset yLzValue;

private boolean writingOn = true;

public MockNeXusSlit() {
super();
}

public MockNeXusSlit(String name, double d, int level) {
super(name, d, level);
}

public MockNeXusSlit(String name, double d, int level, String unit) {
super(name, d, level, unit);
}

public boolean isWritingOn() {
return writingOn;
}

public MockNeXusSlit(String name, double d, int level) {
super(name, d, level);
public void setWritingOn(boolean writingOn) {
this.writingOn = writingOn;
}

@ScanFinally
public void nullify() {
xLzSet = null;
xLzValue = null;
yLzSet = null;
yLzValue = null;
}

public NexusObjectProvider<NXslit> getNexusProvider(NexusScanInfo info) throws NexusException {
final NXslit positioner = NexusNodeFactory.createNXslit();

if (info.getScanRole(getName()) == ScanRole.METADATA) {
positioner.setX_gapScalar(getPosition().doubleValue());
positioner.setY_gapScalar(getPosition().doubleValue());
} else {
String floatFill = System.getProperty("GDA/gda.nexus.floatfillvalue", "NaN");
double fill = "NaN".equalsIgnoreCase(floatFill) ? Double.NaN : Double.parseDouble(floatFill);

xLzSet = positioner.initializeLazyDataset(NXslit.NX_X_GAP, 1, Double.class);
yLzSet = positioner.initializeLazyDataset(NXslit.NX_Y_GAP, 1, Double.class);
xLzSet.setFillValue(fill);
yLzSet.setFillValue(fill);
xLzSet.setChunking(new int[]{8}); // Faster than looking at the shape of the scan for this dimension because slow to iterate.
yLzSet.setChunking(new int[]{8}); // Faster than looking at the shape of the scan for this dimension because slow to iterate.
xLzSet.setWritingAsync(true);
yLzSet.setWritingAsync(true);

xLzValue = positioner.initializeLazyDataset(NXslit.NX_X_GAP, info.getRank(), Double.class);
yLzValue = positioner.initializeLazyDataset(NXslit.NX_Y_GAP, info.getRank(), Double.class);
xLzValue.setFillValue(fill);
yLzValue.setFillValue(fill);
xLzValue.setChunking(info.createChunk(false, 8)); // Might be slow, need to check this
yLzValue.setChunking(info.createChunk(false, 8)); // Might be slow, need to check this
xLzValue.setWritingAsync(true);
yLzValue.setWritingAsync(true);
}

registerAttributes(positioner, this);

NexusObjectWrapper<NXslit> nexusDelegate = new NexusObjectWrapper<>(
getName(), positioner, NXslit.NX_X_GAP);
nexusDelegate.setDefaultAxisDataFieldName(NXslit.NX_X_GAP);
nexusDelegate.setCategory(NexusBaseClass.NX_INSTRUMENT);
return nexusDelegate;
}

public void setPosition(Number initialValue, IPosition position) throws Exception {
Number value = initialValue;

if (value!=null) {
int index = position!=null ? position.getIndex(getName()) : -1;
if (isRealisticMove()) {
value = doRealisticMove(value, index, -1);
}
this.position = value;
delegate.firePositionPerformed(-1, new Scalar(getName(), index, value.doubleValue()));
}

if (position!=null) {
write(value, getPosition(), position);
}
}

private void write(Number demand, Number actual, IPosition loc) throws Exception {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Remove this unused private "write" method. rule
MAJOR Define and throw a dedicated exception instead of using a generic one. rule

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

write is used in the public setPosition() method!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions for which exception to throw appreciated...


if (xLzValue==null || yLzValue==null) {
return;
}
if (actual!=null) {
// write actual position
final Dataset newActualPositionData = DatasetFactory.createFromObject(actual);
IScanSlice rslice = IScanRankService.getScanRankService().createScanSlice(loc);
SliceND xSliceND = new SliceND(xLzValue.getShape(), xLzValue.getMaxShape(), rslice.getStart(), rslice.getStop(), rslice.getStep());
SliceND ySliceND = new SliceND(yLzValue.getShape(), yLzValue.getMaxShape(), rslice.getStart(), rslice.getStop(), rslice.getStep());
if (isWritingOn()) {
xLzValue.setSlice(null, newActualPositionData, xSliceND);
yLzValue.setSlice(null, newActualPositionData, ySliceND);
}
}

if (xLzSet==null || yLzSet==null) {
return;
}
if (demand!=null) {
int index = loc.getIndex(getName());
if (index<0) {
throw new Exception("Incorrect data index for scan for value of '"+getName()+"'. The index is "+index);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Define and throw a dedicated exception instead of using a generic one. rule

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions for which exception to throw appreciated...

}
final int[] startPos = new int[] { index };
final int[] stopPos = new int[] { index + 1 };

// write demand position
final Dataset newDemandPositionData = DatasetFactory.createFromObject(demand);
if (isWritingOn()) {
xLzSet.setSlice(null, newDemandPositionData, startPos, stopPos, null);
yLzSet.setSlice(null, newDemandPositionData, startPos, stopPos, null);
}
}
}

public NexusObjectProvider<NXpositioner> getNexusProvider(NexusScanInfo info) throws NexusException {
// TODO FIXME Use NeXus API to create slit information.
return super.getNexusProvider(info);
/**
* Add the attributes for the given attribute container into the given nexus object.
* @param positioner
* @param container
* @throws NexusException if the attributes could not be added for any reason
*/
private static void registerAttributes(NXobject nexusObject, IScanAttributeContainer container) throws NexusException {
Copy link
Copy Markdown
Contributor

@gerring gerring Feb 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Remove this unused private "registerAttributes" method. rule

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used in the public getNexusProvider() method!

// We create the attributes, if any
nexusObject.setField("name", container.getName());
if (container.getScanAttributeNames()!=null) {
for(String attrName : container.getScanAttributeNames()) {
try {
nexusObject.setField(attrName, container.getScanAttribute(attrName));
} catch (Exception e) {
throw new NexusException(MessageFormat.format(
"An exception occurred attempting to get the value of the attribute ''{0}'' for the device ''{1}''",
container.getName(), attrName), e);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import org.eclipse.scanning.example.scannable.MockScannableConfiguration;
import org.eclipse.scanning.server.application.PseudoSpringParser;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

public class MetadataScannableTest extends NexusTest {
Expand Down Expand Up @@ -91,7 +92,8 @@ public void modelCheck() throws Exception {
public void testBasicScanWithMetadataScannable() throws Exception {
test(monitor, metadataScannable, 8, 5);
}


@Ignore("dcs was supposed to be an NXslit, not an NXpositioner, so this test will need to be fixed later...")
@Test
public void testScanWithConfiguredScannable() throws Exception {
test(monitor, dcs, 8, 5);
Expand Down