/*- * Copyright 2016 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 declaration package uk.ac.diamond.scisoft.analysis.processing.operations.export; // Imports from Java import java.io.File; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; // Imports from org.eclipse.january import org.eclipse.january.IMonitor; import org.eclipse.january.dataset.IDataset; import org.eclipse.january.dataset.Maths; import org.eclipse.january.metadata.AxesMetadata; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DatasetUtils; // Imports from org.eclipse.dawnsci import org.eclipse.dawnsci.nexus.NexusFile; import org.eclipse.dawnsci.nexus.NexusException; import org.eclipse.dawnsci.hdf5.nexus.NexusFileHDF5; import org.eclipse.dawnsci.analysis.tree.TreeFactory; import org.eclipse.dawnsci.analysis.api.tree.DataNode; import org.eclipse.dawnsci.analysis.api.tree.GroupNode; import org.eclipse.dawnsci.analysis.tree.impl.DataNodeImpl; import org.eclipse.dawnsci.analysis.api.processing.OperationData; import org.eclipse.dawnsci.analysis.api.processing.OperationRank; import org.eclipse.dawnsci.analysis.api.processing.IExportOperation; import org.eclipse.dawnsci.analysis.api.processing.OperationException; import org.eclipse.dawnsci.analysis.dataset.operations.AbstractOperation; import org.eclipse.dawnsci.analysis.dataset.slicer.SliceFromSeriesMetadata; // Imports from uk.ac.diamond.scisoft import uk.ac.diamond.scisoft.analysis.io.NexusTreeUtils; //The operation file for exporting a NXcanSAS file //@author Tim Snow //Let's save this file. public class Export1DNXcanSASOperation extends AbstractOperation<Export1DNXcanSASModel, OperationData> implements IExportOperation { @Override public String getId() { return "uk.ac.diamond.scisoft.analysis.processing.operations.export.Export1DNXcanSASOperation"; } @Override public OperationRank getInputRank() { return OperationRank.ONE; } @Override public OperationRank getOutputRank() { return OperationRank.ONE; } @Override protected OperationData process(IDataset input, IMonitor monitor) throws OperationException { // Get the frame's metadata so that we know the filename etc. SliceFromSeriesMetadata sliceSeriesMetadata = getSliceSeriesMetadata(input); int frameNumber = sliceSeriesMetadata.getSliceInfo().getSliceNumber(); // Get the file's name String fileName = sliceSeriesMetadata.getFilePath(); String folderPath = fileName.substring(0, fileName.lastIndexOf(File.separator)); fileName = fileName.substring(fileName.lastIndexOf(File.separator) + 1, fileName.lastIndexOf(".")); String filePath = ""; // Create a save path if (model.getOutputDirectoryPath() != "") { filePath = model.getOutputDirectoryPath() + File.separator + fileName + "_" + String.format("%0" + String.valueOf(model.getPaddingZeros()) + "d", frameNumber) + "_NXcanSAS.nxs"; } else { filePath = folderPath + File.separator + fileName + "_" + String.format("%0" + String.valueOf(model.getPaddingZeros()) + "d", frameNumber) + "_NXcanSAS.nxs"; } // Get the data so that it's a nice array for outputting IDataset dataForOutput = input; // Get the axis data so that it's a nice array for outputting IDataset axesForOutput = (IDataset) input.getFirstMetadata(AxesMetadata.class).getAxes()[0]; axesForOutput = Maths.multiply(axesForOutput, 10); // Get the error data so that it's a nice array for outputting IDataset errorForOutput = input.getErrors(); // The SASdata class SDS classes of I & Q (I_err too!) with attributes for each SDS class e.g. I_axes = Q, Q_indicies 0. GroupNode nxData = TreeFactory.createGroupNode(0); nxData.addAttribute(TreeFactory.createAttribute("signal", "I")); nxData.addAttribute(TreeFactory.createAttribute("I_axes", "Q")); nxData.addAttribute(TreeFactory.createAttribute("Q_indices", Long.valueOf(0))); // Then we add the data DataNode sasDataNode = new DataNodeImpl(1); sasDataNode.setDataset(dataForOutput); sasDataNode.addAttribute(TreeFactory.createAttribute("units", "arbitrary")); //nxData.addDataNode("I", NexusTreeUtils.createDataNode("I", dataForOutput, "1/cm")); nxData.addDataNode("Q", NexusTreeUtils.createDataNode("Q", axesForOutput, "1/nm")); // And any error values, if present if (errorForOutput != null) { sasDataNode.addAttribute(TreeFactory.createAttribute("uncertainties", "Idev")); //nxData.addAttribute(TreeFactory.createAttribute("I/uncertainties", "Idev")); nxData.addDataNode("Idev", NexusTreeUtils.createDataNode("Idev", dataForOutput, "arbitrary")); } nxData.addDataNode("I", sasDataNode); try { // Create the file and get ready to write NexusFile nexusFileReference = new NexusFileHDF5(filePath); nexusFileReference.createAndOpenToWrite(); // Create the NXcanSAS file header NXcanSASHeader(nexusFileReference, fileName, input.getName()); // Write in the experimental data nexusFileReference.addNode("/sasentry/sasdata", nxData); // Then, finally, close the file nexusFileReference.close(); } catch (NexusException nexusFileError) { System.out.println("This error occured when attempting to open the NeXus file: " + nexusFileError.getMessage()); } // For now, let's just create a return class, fill it OperationData output = new OperationData(); output.setData(input); // And return the input data return output; } private void NXcanSASHeader (NexusFile nexusFileReference, String fileName, String fileTitle) throws NexusException { // First up, let's get the time DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date currentDate = new Date(); // So the NxcanSAS file format requires us to output Q & I minimum with Idev as well for preference. // We need a SASroot, SASentry and SASdata class structure with lowercase names (entry and data) // As a courtesy the root level has the file_name and file_time (acquisition time) given as attributes (Time format: YYYY-MM-DDTHH:MM:SS+0000 (timezone)) GroupNode nxRoot = TreeFactory.createGroupNode(0); nxRoot.addAttribute(TreeFactory.createAttribute("NX_class", "NXroot")); nxRoot.addAttribute(TreeFactory.createAttribute("canSAS_class", "SASroot")); nxRoot.addAttribute(TreeFactory.createAttribute("default", "sasentry")); nxRoot.addAttribute(TreeFactory.createAttribute("file_name", fileName)); nxRoot.addAttribute(TreeFactory.createAttribute("file_time", dateFormatter.format(currentDate))); nxRoot.addAttribute(TreeFactory.createAttribute("producer", "DAWN")); // The SASentry class contains a SASdata class with a version attribute (NXcanSAS version e.g. 1.0) GroupNode nxEntry = TreeFactory.createGroupNode(0); nxEntry.addAttribute(TreeFactory.createAttribute("NX_class", "NXentry")); nxEntry.addAttribute(TreeFactory.createAttribute("canSAS_class", "SASentry")); nxEntry.addAttribute(TreeFactory.createAttribute("default", "sasdata")); nxEntry.addAttribute(TreeFactory.createAttribute("version", "1.0")); // These next three require fields with values not attributes DataNode definitionDataNote = new DataNodeImpl(1); definitionDataNote.setDataset(DatasetFactory.createFromObject("NXcanSAS")); nxEntry.addDataNode("definition", definitionDataNote); DataNode runDataNote = new DataNodeImpl(1); runDataNote.setDataset(DatasetFactory.createFromObject(fileName)); nxEntry.addDataNode("run", runDataNote); DataNode titleDataNote = new DataNodeImpl(1); titleDataNote.setDataset(DatasetFactory.createFromObject(fileName)); nxEntry.addDataNode("title", titleDataNote); // The SASdata class SDS classes of I & Q (I_err too!) with attributes for each SDS class e.g. I_axes = Q, Q_indicies 0. GroupNode nxData = TreeFactory.createGroupNode(0); nxData.addAttribute(TreeFactory.createAttribute("NX_class", "NXdata")); nxData.addAttribute(TreeFactory.createAttribute("canSAS_class", "SASdata")); // Then write this header nexusFileReference.addNode("/", nxRoot); nexusFileReference.addNode("/sasentry", nxEntry); nexusFileReference.addNode("/sasentry/sasdata", nxData); } }