/*- * Copyright 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 */ package org.eclipse.dawnsci.nexus; import static org.junit.Assert.assertNotNull; import java.util.HashMap; import java.util.Map; import org.eclipse.dawnsci.analysis.api.tree.DataNode; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.IDataset; import org.junit.Before; public class ComplexNexusFileTest extends AbstractNexusFileTestBase { private static final String FILE_NAME = "complex.nxs"; private Map<String, Object> testData; private NXroot root; @Override @Before public void setUp() throws Exception { super.setUp(); setupTestData(); } private void setupTestData() { final int size = 10; final int[] shape = { size }; testData = new HashMap<String, Object>(); testData.put("cs1_x", 202.2512); testData.put("cs1_y", 0.15); testData.put("cs1_z", -976.472); testData.put("ss1_X", 11.5); testData.put("ss1_Y", 9.9764); testData.put("ss1_Z", 25.1812); testData.put("ss1_rot", -88.2); testData.put("ss1_samplex", 1365.111); // rounded testData.put("ss1_sampley", -3900.095); // rounded testData.put("ss1_samplez", 75.966); // rounded testData.put("actualTime", createDoubleDataset( 1.39112723398E9, 1.391127234478E9, 1.391127234673E9, 1.391127234871E9, 1.391127235068E9, 1.391127248978E9, 1.391127249481E9, 1.391127249751E9, 1.391127249953E9, 1.391127250154E9)); testData.put("beamok", DatasetFactory.ones(shape, Dataset.FLOAT64)); testData.put("ionc_i", createDoubleDataset( 8.374020580781096, 8.370683990350841, 8.370854377232897, 8.373055360469023, 8.375409630828424, 8.363466060032364, 8.361367064643199, 8.360248862560692, 8.358109255244436, 8.358963327124483)); testData.put("count_time", createFilledDataset(0.1, size)); testData.put("data", createDetectorDataDataset()); testData.put("region_origin", DatasetFactory.zeros(new int[] { 1, 2 }, Dataset.FLOAT32)); testData.put("region_size", create2DIntDataset(new int[][] { { 2560, 2160 } })); testData.put("start_time", createDoubleDataset( 8.779, 9.277, 9.473, 9.670, 9.867, 23.777, 24.282, 24.532, 24.748, 24.950)); testData.put("time_ms", createLongDataset( // note: this dataset has type unsigned 32-bit integer in the source nexus file 3852797190l, 3852797688l, 3852797884l, 3852798081l, 3852798278l, 3852712188l, 3852812693l, 3852812943l, 3852813159l, 3852813361l)); testData.put("current", createDoubleDataset(-1.0)); testData.put("energy", createDoubleDataset(-1.0)); testData.put("sourceName", "DLS"); testData.put("sourceProbe", "X-ray"); testData.put("sourceType", "Synchotron X-Ray Source"); testData.put("imageNumber", DatasetFactory.createRange(9.0, Dataset.FLOAT64)); testData.put("image_key", createDoubleDataset(2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0)); testData.put("tomoScanDevice.ss1_X", createDoubleDataset(11.150060000000002, 11.15, 11.15, 11.15, 11.15, 5.00002, 5.0, 5.0, 5.0, 5.0)); testData.put("tomoScanDevice.ss1_rot", createFilledDataset(-88.2, 10)); testData.put("tomography_shutter", createDoubleDataset(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0)); } private IDataset getTestData(String name) { Object data = testData.get(name); if (data instanceof IDataset) { return (IDataset) data; } else if (data != null) { return DatasetFactory.createFromObject(data); } throw new IllegalArgumentException("No such dataset: " + name); } private static IDataset createDoubleDataset(double... values) { return DatasetFactory.createFromObject(values); } private static IDataset createIntegerDataset(int... values) { return DatasetFactory.createFromObject(values); } private static IDataset createLongDataset(long... values) { return DatasetFactory.createFromObject(values); } private static Dataset createFilledDataset(final double value, final int size) { DoubleDataset dataset = DatasetFactory.zeros(DoubleDataset.class, size); dataset.fill(value); return dataset; } private static Dataset create2DIntDataset(final int[][] values) { return DatasetFactory.createFromObject(values); } private static Dataset create2DFloatDataset(final float[][] values) { return DatasetFactory.createFromObject(values); } private IDataset createDetectorDataDataset() { final int[] shape = new int[] { 10, 10, 10 }; final int totalSize = 1000; // in this test case, same 2d 10x10 data is used in each of the 10 'pages' (third dimension) final short[][] data = new short[][] { { 0, 94, 97, 98, 97, 122, 98, 95, 95, 100 }, { 0, 96, 95, 104, 100, 121, 103, 95, 96, 94, 90 }, { 0, 88, 89, 102, 99, 93, 99, 95, 97, 92, 93 }, { 0, 96, 91, 98, 100, 93, 100, 96, 97, 96 }, { 0, 92, 91, 99, 95, 95, 95, 97, 99, 96, 96 }, { 0, 29261, 29994, 30354, 30325, 30621, 30357, 30148, 30915, 30818 }, { 0, 29775, 29996, 30644, 30213, 30879, 29915, 30666, 30786, 30990 }, { 0, 29792, 29606, 30125, 30327, 30651, 30095, 30387, 30457, 30804 }, { 0, 29659, 30340, 30736, 29566, 30741, 30312, 30655, 30458, 31115 }, { 0, 29750, 30138, 29977, 30468, 30942, 29739, 30694, 30401, 31084 }}; short[] flatArray = new short[totalSize]; int pageOffset = 0; for (int page = 0; page < 10; page++) { int rowOffset = pageOffset; for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { flatArray[rowOffset + j] = data[i][j]; } rowOffset += 10; } pageOffset += 100; } return DatasetFactory.createFromObject(flatArray, shape); } private DataNode getDataNode(final String path) { return (DataNode) root.findNodeLink(path).getDestination(); } private NXcollection createCS1Collection() { NXcollection cs1Collection = NexusNodeFactory.createNXcollection(); final String[] csFieldNames = new String[] { "cs1_x", "cs1_y", "cs1_z" }; for (String fieldName : csFieldNames) { IDataset value = getTestData(fieldName); cs1Collection.setDataset(fieldName, value); cs1Collection.setAttribute(fieldName, "field_type", "input"); cs1Collection.setAttribute(fieldName, "format", "%5.5g"); cs1Collection.setAttribute(fieldName, "units", "mm"); } return cs1Collection; } private NXcollection createSampleStageCollection() { NXcollection sampleStageCollection = NexusNodeFactory.createNXcollection(); String[] sampleStageFields = new String[] { "ss1_X", "ss1_Y", "ss1_Z", "ss1_rot", "ss1_samplex", "ss1_sampley", "ss1_samplez" }; for (String fieldName : sampleStageFields) { IDataset value = getTestData(fieldName); sampleStageCollection.setField(fieldName, value); sampleStageCollection.setAttribute(fieldName, "field_type", "input"); sampleStageCollection.setAttribute(fieldName, "format", "%5.5g"); String units; if (fieldName.contains("sample")) { units = "um"; sampleStageCollection.setAttribute(fieldName, "target", "entry1/before_scan/sample_stage/" + fieldName); } else if (fieldName.equals("ss1_rot")) { units = "deg"; } else { units = "mm"; } sampleStageCollection.setAttribute(fieldName, "units", units); } return sampleStageCollection; } private NXinstrument createInstrument() { NXinstrument instrument = NexusNodeFactory.createNXinstrument(); // actualTime : NXpositioner NXpositioner actualTimePositioner = NexusNodeFactory.createNXpositioner(); instrument.setPositioner("actualTime", actualTimePositioner); actualTimePositioner.setDataset("actualTime", getTestData("actualTime")); actualTimePositioner.setAttribute("actualTime", "local_name", "actualTime.actualTime"); actualTimePositioner.setAttribute("actualTime", "target", "/entry1/instrument/actualTime/actualTime"); // beamok : NXpositioner NXpositioner beamokPositioner = NexusNodeFactory.createNXpositioner(); instrument.setPositioner("beamok", beamokPositioner); beamokPositioner.setDataset("beamok", getTestData("beamok")); beamokPositioner.setAttribute("beamok", "local_name", "beamok.beamok"); beamokPositioner.setAttribute("beamok", "target", "/entry1/instrument/beamok/beamok"); // icon_i : NXpositioner NXpositioner ioncIPositioner = NexusNodeFactory.createNXpositioner(); instrument.setPositioner("ionc_i", ioncIPositioner); // use a range for the dataset (not the actual data from the example file) ioncIPositioner.setDataset("ionc_i", getTestData("ionc_i")); ioncIPositioner.setAttribute("ionc_i", "local_name", "ionc_i.ionc_i"); ioncIPositioner.setAttribute("ionc_i", "target", "/entry1/instrument/ionc_i/ionc_i"); instrument.setName(DatasetFactory.createFromObject("i13")); // pc01_hw_hdf: NXdetector NXdetector pco1HwHdfDectector = NexusNodeFactory.createNXdetector(); instrument.setDetector("pco1_hw_hdf", pco1HwHdfDectector); pco1HwHdfDectector.setDataset("count_time", getTestData("count_time")); pco1HwHdfDectector.setAttribute("count_time", "local_name", "pc01_hw_hdf.count_time"); pco1HwHdfDectector.setAttribute("count_time", "target", "/entry1/instrument/pco1_hw_hdf"); pco1HwHdfDectector.setData(getTestData("data")); pco1HwHdfDectector.setAttribute("data", "target", "/entry1/instrument/pco1_hw_hdf/data"); pco1HwHdfDectector.setDataset("region_origin", getTestData("region_origin")); pco1HwHdfDectector.setAttribute("region_origin", "target", "/entry1/instrument/pco1_hw_hdf/region_origin"); pco1HwHdfDectector.setDataset("region_size", getTestData("region_size")); pco1HwHdfDectector.setAttribute("region_size", "target", "/entry1/instrument/pco1_hw_hdf/region_size"); pco1HwHdfDectector.setDataset("start_time", getTestData("start_time")); pco1HwHdfDectector.setAttribute("start_time", "start", "2014-01-31T00:13:45"); pco1HwHdfDectector.setAttribute("start_time", "units", "s"); pco1HwHdfDectector.setAttribute("start_time", "target", "/entry1/instrument/pco1_hw_hdf/start_time"); pco1HwHdfDectector.setDataset("time_ms", getTestData("time_ms")); pco1HwHdfDectector.setAttribute("time_ms", "units", "ms"); pco1HwHdfDectector.setAttribute("time_ms", "target", "/entry1/instrument/pco1_hw_hdf/time_ms"); // source : NXsource NXsource source = NexusNodeFactory.createNXsource(); instrument.setSource(source); source.setDataset("current", getTestData("current")); source.setAttribute("current", "units", "mA"); source.setDataset("energy", getTestData("energy")); source.setAttribute("energy", "units", "GeV"); source.setName(getTestData("sourceName")); source.setProbe(getTestData("sourceProbe")); source.setType(getTestData("sourceType")); // tomoScanDevice : NXpositioner NXpositioner tomoScanDevice = NexusNodeFactory.createNXpositioner(); instrument.setPositioner("tomoScanDevice", tomoScanDevice); tomoScanDevice.setDataset("imageNumber", getTestData("imageNumber")); tomoScanDevice.setAttribute("imageNumber", "axis", "1"); tomoScanDevice.setAttribute("imageNumber", "local_name", "tomoScanDevice.imageNumber"); tomoScanDevice.setAttribute("imageNumber", "target", "/entry1/instrument/tomoScanDevice/imageNumber"); tomoScanDevice.setDataset("image_key", getTestData("image_key")); tomoScanDevice.setAttribute("image_key", "axis", "1"); tomoScanDevice.setAttribute("image_key", "local_name", "tomoScanDevice.image_key"); tomoScanDevice.setAttribute("image_key", "target", "/entry1/instrument/tomoScanDevice/image_key"); tomoScanDevice.setDataset("ss1_X", getTestData("tomoScanDevice.ss1_X")); tomoScanDevice.setAttribute("ss1_X", "axis", "1"); tomoScanDevice.setAttribute("ss1_X", "local_name", "tomoScanDevice.ss1_X"); tomoScanDevice.setAttribute("ss1_X", "target", "/entry1/instrument/tomoScanDevice/ss1_X"); tomoScanDevice.setDataset("ss1_rot", getTestData("tomoScanDevice.ss1_rot")); tomoScanDevice.setAttribute("ss1_rot", "axis", "1"); tomoScanDevice.setAttribute("ss1_rot", "label", "1"); tomoScanDevice.setAttribute("ss1_rot", "local_name", "tomoScanDevice.ss1_rot"); tomoScanDevice.setAttribute("ss1_rot", "primary", "1"); tomoScanDevice.setAttribute("ss1_rot", "target", "/entry1/instrument/tomoScanDevice/ss1_rot"); tomoScanDevice.setDataset("tomography_shutter", getTestData("tomography_shutter")); tomoScanDevice.setAttribute("tomography_shutter", "axis", "1"); tomoScanDevice.setAttribute("tomography_shutter", "local_name", "tomoScanDevice.tomography_shutter"); tomoScanDevice.setAttribute("tomography_shutter", "target", "/entry1/instrument/tomoScanDevice/tomography_shutter"); return instrument; } private NXdata createPco1HwHdfData() { NXdata data = NexusNodeFactory.createNXdata(); data.addDataNode("actualTime", getDataNode("/entry1/instrument/actualTime/actualTime")); data.addDataNode("beamok", getDataNode("/entry1/instrument/beamok/beamok")); data.addDataNode("count_time", getDataNode("/entry1/instrument/pco1_hw_hdf/count_time")); data.addDataNode("data", getDataNode("/entry1/instrument/pco1_hw_hdf/data")); data.addDataNode("imageNumber", getDataNode("/entry1/instrument/tomoScanDevice/imageNumber")); data.addDataNode("image_key", getDataNode("/entry1/instrument/tomoScanDevice/image_key")); data.addDataNode("ionc_i", getDataNode("/entry1/instrument/ionc_i/ionc_i")); data.addDataNode("region_origin", getDataNode("/entry1/instrument/pco1_hw_hdf/region_origin")); data.addDataNode("region_size", getDataNode("/entry1/instrument/pco1_hw_hdf/region_size")); data.addDataNode("ss1_X", getDataNode("/entry1/instrument/tomoScanDevice/ss1_X")); data.addDataNode("ss1_rot", getDataNode("/entry1/instrument/tomoScanDevice/ss1_rot")); data.addDataNode("start_time", getDataNode("/entry1/instrument/pco1_hw_hdf/start_time")); data.addDataNode("time_ms", getDataNode("/entry1/instrument/pco1_hw_hdf/time_ms")); data.addDataNode("tomography_shutter", getDataNode("/entry1/instrument/tomoScanDevice/tomography_shutter")); return data; } private NXsubentry createTomoEntry() { NXsubentry tomoEntry = NexusNodeFactory.createNXsubentry(); // control : NXmonitor NXmonitor controlMonitor = NexusNodeFactory.createNXmonitor(); tomoEntry.setMonitor("control", controlMonitor); controlMonitor.addDataNode("data", getDataNode("entry1/instrument/ionc_i/ionc_i")); // data : NXdata NXdata dataGroupNode = NexusNodeFactory.createNXdata(); tomoEntry.setData(dataGroupNode); dataGroupNode.addDataNode("data", getDataNode("/entry1/instrument/pco1_hw_hdf/data")); dataGroupNode.addDataNode("rotation_angle", getDataNode("/entry1/instrument/tomoScanDevice/ss1_rot")); tomoEntry.setDefinition(DatasetFactory.createFromObject("definition")); // instrument : NXinstrument NXinstrument instrument = NexusNodeFactory.createNXinstrument(); tomoEntry.setInstrument(instrument); // detector : NXdetector NXdetector detector = NexusNodeFactory.createNXdetector(); instrument.setDetector(detector); // tomo_entry/instrument/detector/data has the same data as tomo_entry/data/data detector.addDataNode("data", dataGroupNode.getDataNode("data")); // note some of these links in the original file are strange detector.addDataNode("distance", getDataNode("/entry1/scan_identifier")); detector.addDataNode("image_key", getDataNode("/entry1/instrument/tomoScanDevice/image_key")); detector.addDataNode("x_pixel_size", getDataNode("/entry1/scan_identifier")); detector.addDataNode("y_pixel_size", getDataNode("/entry1/scan_identifier")); // source : NXsource - hardlink to /entry1/instument/source NXsource source = (NXsource) root.findNodeLink("/entry1/instrument/source").getDestination(); instrument.addGroupNode("source", source); // sample : NXsample NXsample sample = NexusNodeFactory.createNXsample(); tomoEntry.setSample(sample); sample.addDataNode("rotation_angle", getDataNode("/entry1/instrument/tomoScanDevice/ss1_rot")); sample.addDataNode("x_translation", getDataNode("/entry1/before_scan/sample_stage/ss1_samplex")); sample.addDataNode("y_translation", getDataNode("/entry1/before_scan/sample_stage/ss1_sampley")); sample.addDataNode("z_translation", getDataNode("/entry1/before_scan/sample_stage/ss1_samplez")); tomoEntry.addDataNode("title", getDataNode("/entry1/title")); return tomoEntry; } @Override protected NXroot createNXroot() { root = NexusNodeFactory.createNXroot(); // create the single entry object of the nexus file NXentry entry1 = NexusNodeFactory.createNXentry(); root.setEntry("entry1", entry1); // TODO, should we set any attributes on the root, or are they only set when a file is loaded? assertNotNull(root.getEntry("entry1")); NXcollection beforeScanCollection = NexusNodeFactory.createNXcollection(); entry1.setCollection("before_scan", beforeScanCollection); NXcollection cs1Collection = createCS1Collection(); beforeScanCollection.addGroupNode("cs1", cs1Collection); NXcollection sampleStage = createSampleStageCollection(); beforeScanCollection.addGroupNode("sample_stage", sampleStage); entry1.setEntry_identifier(DatasetFactory.createFromObject("24737")); entry1.setExperiment_identifier(DatasetFactory.createFromObject("mt9396-1")); NXinstrument instrument = createInstrument(); entry1.setInstrument(instrument); NXdata pco1HwHdfData = createPco1HwHdfData(); entry1.setData("pco1_hw_hdf", pco1HwHdfData); entry1.setProgram_name(DatasetFactory.createFromObject("GDA 8.36.0")); entry1.setField("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"); entry1.setField("scan_dimensions", 111); entry1.setField("scan_identifier", "a3d668c0-e3c4-4ed9-b127-4a202b2b6bac"); entry1.setAttribute("scan_identifier", "target", "/entry1/scan_identifier"); entry1.setField("title", "AKingUVA_705wSSwire_InSitu_95RH_2MMgCI2_p4ul_p4h"); entry1.setAttribute("title", "target", "/entry1/title"); NXsubentry tomoEntry = createTomoEntry(); entry1.setSubentry("tomo_entry", tomoEntry); NXuser user = NexusNodeFactory.createNXuser(); entry1.setUser(user); user.setField("username", "ssg37927"); return root; } @Override protected String getFilename() { return FILE_NAME; } }