/*- ******************************************************************************* * Copyright (c) 2011, 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 * * Contributors: * Matthew Gerring - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.dawnsci.nexus; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.january.dataset.ILazyWriteableDataset; import org.eclipse.january.dataset.SliceND; /** * * This class represents information about the scan which the NeXus device is running in. * * For instance, names of scannables in the axes and the rank of the scan. * * TODO mattd 2017-02-28: should this class be removed and we use ScanInformation / ScanModel instead? * * @author Matthew Gerring * */ public class NexusScanInfo { public static enum ScanRole { DETECTOR, SCANNABLE, MONITOR, METADATA } private int rank; private final Map<ScanRole, Collection<String>> deviceNames; private int[] shape; public NexusScanInfo() { this(Collections.emptyList()); } /** * * @param axisNames must be ordered correctly into indices */ public NexusScanInfo(List<String> axisNames) { super(); deviceNames = new EnumMap<>(ScanRole.class); deviceNames.put(ScanRole.SCANNABLE, axisNames); this.rank = 1; } public int getRank() { return rank; } public void setRank(int rank) { this.rank = rank; } private void setDeviceNames(ScanRole scanRole, Collection<String> names) { // private so that we can ensure the correct type of collection for the role // e.g. List for Scannables deviceNames.put(scanRole, names); } public Collection<String> getDeviceNames(ScanRole scanRole) { Collection<String> names = deviceNames.get(scanRole); return names == null ? Collections.emptyList() : names; } public void setDetectorNames(Set<String> detectorNames) { setDeviceNames(ScanRole.DETECTOR, detectorNames); } public Collection<String> getDetectorNames() { return getDeviceNames(ScanRole.DETECTOR); } public List<String> getScannableNames() { return (List<String>) getDeviceNames(ScanRole.SCANNABLE); } public void setScannableNames(List<String> axisNames) { setDeviceNames(ScanRole.SCANNABLE, axisNames); } public Set<String> getMonitorNames() { return (Set<String>) getDeviceNames(ScanRole.MONITOR); } public void setMonitorNames(Set<String> monitorNames) { setDeviceNames(ScanRole.MONITOR, monitorNames); } public Set<String> getMetadataScannableNames() { return (Set<String>) getDeviceNames(ScanRole.METADATA); } public void setMetadataScannableNames(Set<String> metadataScannableNames) { setDeviceNames(ScanRole.METADATA, metadataScannableNames); } public int[] getShape() { return shape; } public void setShape(int[] shape) { this.shape = shape; } /** * Returns the {@link ScanRole} of the device with the given name within the scan, * or <code>null</code> if none * @param name name of device * @return role or device within scan, or <code>null</code> */ public ScanRole getScanRole(String name) { for (ScanRole scanRole : deviceNames.keySet()) { Collection<String> names = deviceNames.get(scanRole); if (names != null && names.contains(name)) { return scanRole; } } return null; } public int[] createChunk(int... datashape) { return createChunk(true, datashape); } /** * Attempts to make a chunk size from the scan. * NOTE This assumes that the datashape is a resonable size currently. * If the datashape is small, the chunking can become too small to usefully * read. * * @param datashape * @return the suggested chunk array */ public int[] createChunk(boolean append, int... datashape) { // Create chunk array of correct length final int[] chunk = append ? new int[rank+datashape.length] : new int[rank]; // Initialise the array to all 1 // TODO this is slightly redundant but ensures no zeros can ever be allowed through Arrays.fill(chunk, 1); // Change end of chunk array to match datashape int index = 0; for (int i = datashape.length; i>0; i--) { chunk[chunk.length-i] = datashape[index]; index++; } return chunk; } /** * Create a location for a slice of data from the list (correctly ordered) of * scan names and thier relative indices. This information is available from the * IPosition which is sent into the device during the scan. * * @param context LazyDataset we are writing to * @param names available from the IPosition for instance * @param indices available from the IPosition for instance * @param datashape shape of data that the device is adding to the nD stack * @return */ @Deprecated public static SliceND createLocation(ILazyWriteableDataset context, Collection<String> names, Map<String,Integer> indices, int... datashape) { throw new IllegalArgumentException("Please use IScanRankService to determine the correct slice information during a scan!"); } @Override public String toString() { return "NexusScanInfo [rank=" + rank + ", axisNames=" + getScannableNames() + "]"; } }