/*- ******************************************************************************* * Copyright (c) 2015 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 * * Contributors: * Matthew Dickie - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.dawnsci.nexus.builder.impl; import java.util.ArrayList; import java.util.List; import org.eclipse.dawnsci.nexus.NXcollection; import org.eclipse.dawnsci.nexus.NXdetector; import org.eclipse.dawnsci.nexus.NXentry; import org.eclipse.dawnsci.nexus.NXpositioner; import org.eclipse.dawnsci.nexus.NXsource; import org.eclipse.dawnsci.nexus.NexusApplicationDefinition; import org.eclipse.dawnsci.nexus.NexusBaseClass; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.nexus.NexusNodeFactory; import org.eclipse.dawnsci.nexus.builder.AbstractNexusObjectProvider; import org.eclipse.dawnsci.nexus.builder.CustomNexusEntryModification; import org.eclipse.dawnsci.nexus.builder.NexusEntryBuilder; import org.eclipse.dawnsci.nexus.builder.NexusEntryModification; import org.eclipse.dawnsci.nexus.builder.appdef.impl.TomoApplicationBuilder; import org.eclipse.dawnsci.nexus.builder.data.NexusDataBuilder; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.IDataset; public class ComplexNexusFileBuilderTest extends AbstractNexusFileBuilderTestBase { private static class SimplePositioner extends AbstractNexusObjectProvider<NXpositioner> { public SimplePositioner(final String name) { super(name, NexusBaseClass.NX_POSITIONER, NXpositioner.NX_VALUE); } @Override public NXpositioner createNexusObject() { NXpositioner positioner = NexusNodeFactory.createNXpositioner(); positioner.initializeLazyDataset(NXpositioner.NX_VALUE, 1, Double.class); return positioner; } } private static final class TomoScanDevicePositioner extends AbstractNexusObjectProvider<NXpositioner> { public TomoScanDevicePositioner() { super("tomoScanDevice", NexusBaseClass.NX_POSITIONER, "ss1_rot"); setUseDeviceNameInNXdata(false); setAxisDataFieldNames("imageNumber", "image_key", "ss1_X", "ss1_rot", "tomography_shutter"); } @Override public NXpositioner createNexusObject() { NXpositioner positioner = NexusNodeFactory.createNXpositioner(); positioner.initializeLazyDataset("imageNumber", 1, Double.class); positioner.initializeLazyDataset("image_key", 1, Double.class); positioner.initializeLazyDataset("ss1_X", 1, Double.class); positioner.initializeLazyDataset("ss1_rot", 1, Double.class); positioner.initializeLazyDataset("tomography_shutter", 1, Double.class); return positioner; } } private static class TestDetector extends AbstractNexusObjectProvider<NXdetector> { public TestDetector() { super("pc01_hw_hdf", NexusBaseClass.NX_DETECTOR, NXdetector.NX_DATA, NXdetector.NX_COUNT_TIME, "start_time", "time_ms"); } @Override public NXdetector createNexusObject() { final NXdetector detector = NexusNodeFactory.createNXdetector(); detector.initializeLazyDataset(NXdetector.NX_DATA, 3, Short.class); detector.initializeLazyDataset(NXdetector.NX_COUNT_TIME, 1, Double.class); IDataset regionOrigin = DatasetFactory.createFromObject(new int[] {0, 0}, 1, 2); detector.setField("region_origin", regionOrigin); IDataset regionSize = DatasetFactory.createFromObject(new int[] {2560, 2160}, 1, 2); detector.setField("region_size", regionSize); detector.initializeLazyDataset("start_time", 1, Double.class); detector.initializeLazyDataset("time_ms", 1, Long.class); // unsigned int 32 in original nexus file // image_key required by NXtomo application definition detector.initializeLazyDataset("image_key", 1, Integer.class); detector.setAttribute("image_key", "target", "/entry/instrument/pc01_hw_hdf/image_key"); return detector; } } private static class TestSource extends AbstractNexusObjectProvider<NXsource> { public TestSource() { super("source", NexusBaseClass.NX_SOURCE); } @Override protected NXsource createNexusObject() { final NXsource source = NexusNodeFactory.createNXsource(); source.setCurrentScalar(-1.0); source.setEnergyScalar(-1.0); source.setNameScalar("DLS"); source.setProbeScalar("X-ray"); source.setTypeScalar("type"); return source; } } /** * In the real world the before_scan collection is used by GDA to store additional data it needs. * In a real world system this provider could fetch the details from the scan. */ private static class BeforeScan extends AbstractNexusObjectProvider<NXcollection> { public BeforeScan() { super("before_scan", NexusBaseClass.NX_COLLECTION); } @Override protected NXcollection createNexusObject() { NXcollection beforeScan = NexusNodeFactory.createNXcollection(); // Create cs1 collection: NXcollection cs1 = NexusNodeFactory.createNXcollection(); beforeScan.addGroupNode("cs1", cs1); cs1.setAttribute(null, "metadata_type", "scannable"); String[] cs1FieldNames = new String[] { "cs1_x", "cs1_y", "cs1_z" }; double[] cs1FieldValues = new double[] { 202.2512, 0.15, -976.472 }; for (int i = 0; i < cs1FieldNames.length; i++) { cs1.setField(cs1FieldNames[i], cs1FieldValues[i]); cs1.setAttribute(cs1FieldNames[i], "field_type", "input"); cs1.setAttribute(cs1FieldNames[i], "format", "%5.5g"); cs1.setAttribute(cs1FieldNames[i], "units", "mm"); } // Create sample stage collection NXcollection sampleStage = NexusNodeFactory.createNXcollection(); beforeScan.addGroupNode("sample_stage", sampleStage); String[] ss1FieldNames = new String[] { "ss1_X", "ss1_Y", "ss1_Z", "ss1_rot", "ss1_samplex", "ss1_sampley", "ss1_samplez" }; double[] ss1FieldValues = new double[] { -976.472, 9.9764, 25.1812, -88.2, 1365.111, -3900.095, 75.966 }; String[] units = new String[] { "mm", "mm", "mm", "deg", "um", "um", "um" }; for (int i = 0; i < ss1FieldNames.length; i++) { sampleStage.setField(ss1FieldNames[i], ss1FieldValues[i]); sampleStage.setAttribute(ss1FieldNames[i], "field_type", "input"); sampleStage.setAttribute(ss1FieldNames[i], "units", units[i]); sampleStage.setAttribute(ss1FieldNames[i], "format", "%5.5g"); if (ss1FieldNames[i].contains("sample")) { sampleStage.setAttribute(ss1FieldNames[i], "target", "/entry/before_scan/sample_stage/" + ss1FieldValues[i]); } } return beforeScan; } } private static final String FILE_NAME = "complexTestFile.nxs"; @Override protected String getFilename() { return FILE_NAME; } private SimplePositioner actualTimePositioner; private SimplePositioner beamOkPositioner; private SimplePositioner ioncIPositioner; private TestDetector testDetector; private TestSource testSource; private BeforeScan beforeScan; private TomoScanDevicePositioner tomoScanDevicePositioner; private NexusUser user; private MapBasedMetadataProvider scanData; @Override protected List<NexusEntryModification> getNexusTreeModifications() { beforeScan = new BeforeScan(); actualTimePositioner = new SimplePositioner("actualTime"); beamOkPositioner = new SimplePositioner("beakok"); ioncIPositioner = new SimplePositioner("ionc_i"); tomoScanDevicePositioner = new TomoScanDevicePositioner(); testDetector = new TestDetector(); testSource = new TestSource(); user = new NexusUser("user01"); user.setUsername("myusername"); scanData = new MapBasedMetadataProvider(); scanData.addMetadataEntry("entry_identifier", "24737"); scanData.addMetadataEntry("experiment_identifier", "nt9396-1"); scanData.addMetadataEntry("program_name", "GDA 8.36.0"); scanData.addMetadataEntry("scan_command", "scan tomoScanDevice Start: -88.200000 Stop: 91.800000 Step: 2.000000 Darks every:0 imagesPerDark:5 Flats every:0 imagesPerFlat:5 InBeamPosition:11.150000 OutOfBeamPosition:5.000000 numImages 111 actualTime ionc_i pco1_hw_hdf 0.1 beamok"); scanData.addMetadataEntry("scan_dimensions", 111); scanData.addMetadataEntry("scan_identifier", "a3d668c0-e3c4-4ed9-b127-4a202b2b6bac"); scanData.addMetadataEntry("title", "AKingUVA_7050wSSwire_InSitu_95RH_2MMgCl2_p4ul_p4h"); List<NexusEntryModification> nexusObjects = new ArrayList<>(); nexusObjects.add(beforeScan); nexusObjects.add(scanData); nexusObjects.add(actualTimePositioner); nexusObjects.add(beamOkPositioner); nexusObjects.add(ioncIPositioner); nexusObjects.add(testDetector); nexusObjects.add(testSource); nexusObjects.add(tomoScanDevicePositioner); nexusObjects.add(user); nexusObjects.add(new CustomNexusEntryModification() { @Override public void modifyEntry(NXentry entry) { entry.setAttribute("title", "target", "/entry/title"); } }); return nexusObjects; } @Override protected void configureEntryModel(NexusEntryBuilder nexusEntryModel) { nexusEntryModel.setInstrumentName("i13"); } @Override protected void addDataBuilder(NexusEntryBuilder entryModel) throws NexusException { NexusDataBuilder dataBuilder = entryModel.newData(testDetector.getName()); dataBuilder.setPrimaryDevice(testDetector); dataBuilder.addAxisDevice(tomoScanDevicePositioner, 0); dataBuilder.addAxisDevice(actualTimePositioner); dataBuilder.addAxisDevice(beamOkPositioner); dataBuilder.addAxisDevice(ioncIPositioner); // TODO, add these fields as part of the detector (primary) device // TODO also add region_origin and region_size // AxisDataDevice<NXdetector> detectorAxisDevice = new DataDevice<>(testDetector), null, 0); // detectorAxisDevice.setSourceFields("count_time", "start_time", "time_ms"); // detectorAxisDevice.set // detectorAxisDevice.setIsPrimary(true); // dataBuilder.addDataDevice(detectorAxisDevice); } protected void addApplicationDefinitions(NexusEntryBuilder nexusEntryModel) throws NexusException { TomoApplicationBuilder appDefModel = (TomoApplicationBuilder) nexusEntryModel.newApplication(NexusApplicationDefinition.NX_TOMO); appDefModel.addDefaultGroups(); appDefModel.setTitle(nexusEntryModel.getDataNode(NXentry.NX_TITLE)); appDefModel.setControl(ioncIPositioner); appDefModel.setSource(testSource); appDefModel.setDetector(testDetector); appDefModel.setSampleName("test sample"); appDefModel.setRotationAngle(tomoScanDevicePositioner); appDefModel.setXTranslation(nexusEntryModel.getDataNode("before_scan/sample_stage/ss1_samplex")); appDefModel.setYTranslation(nexusEntryModel.getDataNode("before_scan/sample_stage/ss1_sampley")); appDefModel.setZTranslation(nexusEntryModel.getDataNode("before_scan/sample_stage/ss1_samplez")); appDefModel.newData(); } @Override protected String getTestClassName() { return ComplexNexusFileBuilderTest.class.getCanonicalName(); } }