/* * Copyright (c) 2012 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 uk.ac.diamond.scisoft.analysis.io; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.io.Serializable; import java.util.HashMap; import javax.vecmath.Vector3d; import org.eclipse.dawnsci.analysis.api.diffraction.DetectorProperties; import org.eclipse.dawnsci.analysis.api.diffraction.DiffractionCrystalEnvironment; import org.eclipse.dawnsci.analysis.api.io.ScanFileHolderException; import org.eclipse.january.dataset.ILazyDataset; /** * Class to load Rigaku images. Class returns a DataHolder that is called from the ScanFileHolder class. */ public class RAxisImageLoader extends AbstractFileLoader implements Serializable { private HashMap<String, Serializable> metadataMap = new HashMap<String, Serializable>(); private HashMap<String, Serializable> GDAMetadata = new HashMap<String, Serializable>(); private boolean keepBitWidth = false; private static final String DATA_NAME = "RAxis Image"; /** * @return true if loader keeps bit width of pixels */ public boolean isKeepBitWidth() { return keepBitWidth; } /** * set loader to keep bit width of pixels * * @param keepBitWidth */ public void setKeepBitWidth(boolean keepBitWidth) { this.keepBitWidth = keepBitWidth; } public RAxisImageLoader() { } /** * @param FileName */ public RAxisImageLoader(String FileName) { this(FileName, false); } /** * @param FileName * @param keepBitWidth * true if loader keeps bit width of pixels */ public RAxisImageLoader(String FileName, boolean keepBitWidth) { setFile(FileName); this.keepBitWidth = keepBitWidth; } @Override public void clearMetadata() { metadata = null; metadataMap.clear(); GDAMetadata.clear(); } @Override public DataHolder loadFile() throws ScanFileHolderException { DataHolder output = new DataHolder(); // opens the file and reads the header information RandomAccessFile raf = null; try { raf = new RandomAccessFile(fileName, "r"); } catch (FileNotFoundException fnf) { throw new ScanFileHolderException("File not found", fnf); } catch (Exception e) { try { if (raf != null) raf.close(); } catch (IOException ex) { ex.printStackTrace(); } throw new ScanFileHolderException("There was a problem loading or reading metadata", e); } processingMetadata(raf); int[] shape = { toInt("nSlow"), toInt("nFast")}; double st = toDouble("phistart"); double[] origin = createGDAMetadata(shape[1], shape[0], st); createMetadata(origin, shape[1], shape[0], st); try { ILazyDataset data; if (loadLazily) { data = createLazyDataset(DEF_IMAGE_NAME, DATA_NAME, -1, shape, new RAxisImageLoader(fileName)); } else { data = Utils.createDataset(raf, shape, keepBitWidth); data.setName(DEF_IMAGE_NAME); } output.addDataset(DATA_NAME, data); if (loadMetadata) { data.setMetadata(getMetadata()); output.setMetadata(data.getMetadata()); } } catch (Exception e) { throw new ScanFileHolderException("There was a problem reading the RAxis image", e); } finally { try { raf.close(); } catch (IOException e) { throw new ScanFileHolderException("Problem closing RAxis file", e); } } return output; } /** * processing all Metadata between { and } tags at the top of the file, put it into a key-value pair map if they are * in "key=value" format. remove ; from line ending * * @param raf * @throws ScanFileHolderException */ private void processingMetadata(RandomAccessFile raf) throws ScanFileHolderException { // handling metadata in the file header try { byte[] b = new byte[10]; raf.readFully(b); metadataMap.put("Device", new String(b).trim()); // this is a really crude way of figuring out if the binary files // is from a RAxis IP if (!new String(b).trim().contains("RAXIS")) throw new ScanFileHolderException("This image does not appear to be an RAxis image"); b = new byte[10]; raf.readFully(b); metadataMap.put("Version", new String(b).trim()); b = new byte[20]; raf.readFully(b); metadataMap.put("Crystal", new String(b).trim()); b = new byte[12]; raf.readFully(b); metadataMap.put("Crystal system", new String(b).trim()); raf.skipBytes(24); // this is supposed to be a b c al be ga b = new byte[12]; raf.readFully(b); metadataMap.put("SpaceGroup", new String(b).trim()); metadataMap.put("mosaic1", raf.readFloat()); b = new byte[80]; raf.readFully(b); metadataMap.put("memo", new String(b).trim()); b = new byte[84]; raf.readFully(b); metadataMap.put("reserve1", new String(b).trim()); b = new byte[12]; raf.readFully(b); metadataMap.put("date", new String(b).trim()); b = new byte[20]; raf.readFully(b); metadataMap.put("operatorname", new String(b).trim()); b = new byte[4]; raf.readFully(b); metadataMap.put("target", new String(b).trim()); // ('wavelength',4,'!f'), metadataMap.put("wavelength", raf.readFloat()); // ('monotype',20,'s'), b = new byte[20]; raf.readFully(b); metadataMap.put("monotype", new String(b).trim()); // ('mono2theta',4,'!f'), metadataMap.put("mono2theta", raf.readFloat()); // ('collimator',20,'s'), b = new byte[20]; raf.readFully(b); metadataMap.put("collimator", new String(b).trim()); // ('filter',4,'s'), b = new byte[4]; raf.readFully(b); metadataMap.put("filter", new String(b).trim()); // ('distance',4,'!f'), metadataMap.put("distance", raf.readFloat()); // ('Kv',4,'!f'), metadataMap.put("Kv", raf.readFloat()); // ('mA',4,'!f'), metadataMap.put("mA", raf.readFloat()); // ('focus',12,'s'), b = new byte[12]; raf.readFully(b); metadataMap.put("focus", new String(b).trim()); // ('Xmemo',80,'s'), b = new byte[80]; raf.readFully(b); metadataMap.put("Xmemo", new String(b).trim()); // ('cyl',4,'!i'), metadataMap.put("cyl", raf.readInt()); // (None,60), raf.skipBytes(60); // ('Spindle',4,'s'), # Crystal mount axis closest to spindle axis b = new byte[4]; raf.readFully(b); metadataMap.put("Spindle", new String(b).trim()); // ('Xray_axis',4,'s'), # Crystal mount axis closest to beam axis b = new byte[4]; raf.readFully(b); metadataMap.put("Xray_axis", new String(b).trim()); // ('phidatum',4,'!f'), metadataMap.put("phidatum", raf.readFloat()); // ('phistart',4,'!f'), metadataMap.put("phistart", raf.readFloat()); // ('phiend',4,'!f'), metadataMap.put("phiend", raf.readFloat()); // ('noscillations',4,'!i'), metadataMap.put("noscillations", raf.readInt()); // ('minutes',4,'!f'), # Exposure time in minutes? metadataMap.put("minutes", raf.readFloat()); // ('beampixels_x',4,'!f'), metadataMap.put("beampixels_x", raf.readFloat()); // ('beampixels_y',4,'!f'), # Direct beam position in pixels metadataMap.put("beampixels_y", raf.readFloat()); // ('omega',4,'!f'), metadataMap.put("omega", raf.readFloat()); // ('chi',4,'!f'), metadataMap.put("chi", raf.readFloat()); // ('twotheta',4,'!f'), metadataMap.put("twotheta", raf.readFloat()); // ('Mu',4,'!f'), # Spindle inclination angle? metadataMap.put("Mu", raf.readFloat()); // ('ScanTemplate',204,'s'), # This space is now used for storing the scan // # templates information b = new byte[204]; raf.readFully(b); metadataMap.put("ScanTemplate", new String(b).trim()); // ('nFast',4,'!i'), metadataMap.put("nFast", raf.readInt()); // ('nSlow',4,'!i'), # Number of fast, slow pixels metadataMap.put("nSlow", raf.readInt()); // ('sizeFast',4,'!f'), metadataMap.put("sizeFast", raf.readFloat()); // ('sizeSlow',4,'!f'), # Size of fast, slow direction in mm metadataMap.put("sizeSlow", raf.readFloat()); // ('record_length',4,'!i'), # Record length in bytes metadataMap.put("record_length", raf.readInt()); // ('number_records',4,'!i'), # number of records metadataMap.put("number_records", raf.readInt()); // ('Read_start',4,'!i'), # For partial reads, 1st read line metadataMap.put("Read_start", raf.readInt()); // ('IP_num',4,'!i'), # Which imaging plate 1, 2 ? metadataMap.put("IP_num", raf.readInt()); // ('Ratio',4,'!f'), # Output ratio for high value pixels metadataMap.put("Ratio", raf.readFloat()); // ('Fading_start',4,'!f'), # Fading time to start of read metadataMap.put("Fading_start", raf.readFloat()); // ('Fading_end',4,'!f'), # Fading time to end of read metadataMap.put("Fading_end", raf.readFloat()); // ('computer',10,'s'), # Type of computer "IRIS", "VAX", "SUN", etc b = new byte[10]; raf.readFully(b); metadataMap.put("computer", new String(b).trim()); // ('plate_type',10,'s'), # Type of IP b = new byte[10]; raf.readFully(b); metadataMap.put("plate_type", new String(b).trim()); // ('Dr',4,'!i'), metadataMap.put("Dr", raf.readInt()); // ('Dx',4,'!i'), metadataMap.put("Dx", raf.readInt()); // ('Dz',4,'!i'), # IP scanning codes?? metadataMap.put("Dz", raf.readInt()); // ('PixShiftOdd',4,'!f'), # Pixel shift to odd lines metadataMap.put("PixShiftOdd", raf.readFloat()); // ('IntRatioOdd',4,'!f'), # Intensity ratio to odd lines metadataMap.put("IntRatioOdd", raf.readFloat()); // ('MagicNum',4,'!i'), # Magic number to indicate next values are legit metadataMap.put("MagicNum'", raf.readInt()); // ('NumGonAxes',4,'!i'), # Number of goniometer axes metadataMap.put("NumGonAxes'", raf.readInt()); // ('a5x3fGonVecs',60,'!fffffffffffffff'),# Goniometer axis vectors float[] fa = { raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), }; metadataMap.put("a5x3fGonVecs", fa); // ('a5fGonStart',20,'!fffff'),# Start angles for each of 5 axes float[] fb = { raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat() }; metadataMap.put("a5x3fGonStart", fb); // ('a5fGonEnd',20,'!fffff'), # End angles for each of 5 axes float[] fc = { raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat() }; metadataMap.put("a5fGonEnd", fc); // ('a5fGonOffset',20,'!fffff'),# Offset values for each of 5 axes float[] fd = { raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat(), raf.readFloat() }; metadataMap.put("a5fGonOffset", fd); // ('ScanAxisNum',4,'!i'), # Which axis is the scan axis? metadataMap.put("ScanAxisNum", raf.readInt()); // ('AxesNames',40,'s'), # Names of the axes (space or comma separated?)''' b = new byte[10]; raf.readFully(b); metadataMap.put("ScanAxisNum", new String(b).trim()); raf.skipBytes((int) (toInt("record_length") - raf.getFilePointer())); } catch (IOException e) { throw new ScanFileHolderException("There was a problem parsing the RAxis header information", e); } } private int toInt(String key) { return (Integer) metadataMap.get(key); } private double toDouble(String key) { return ((Float) metadataMap.get(key)).doubleValue(); } private double[] createGDAMetadata(int nx, int ny, double st) throws ScanFileHolderException { try { // NXGeometery:NXtranslation double x = nx - (nx - toDouble("beampixels_x")) * toDouble("sizeFast"); double y = ny - (ny - toDouble("beampixels_y")) * toDouble("sizeSlow"); double[] detectorOrigin = { x, y, toDouble("distance") }; GDAMetadata.put("NXdetector:NXgeometry:NXtranslation", detectorOrigin); GDAMetadata.put("NXdetector:NXgeometry:NXtranslation@units", "milli*meter"); // NXGeometery:NXOrientation double[] directionCosine = { 1, 0, 0, 0, 1, 0 }; // to form identity matrix as no header data GDAMetadata.put("NXdetector:NXgeometry:NXorientation", directionCosine); // NXGeometery:XShape (shape from origin (+x, +y, +z,0, 0, 0) > x,y,0,0,0,0) double[] detectorShape = { nx * toDouble("sizeFast"), ny * toDouble("sizeSlow"), 0, 0, 0, 0 }; GDAMetadata.put("NXdetector:NXgeometry:NXshape", detectorShape); GDAMetadata.put("NXdetector:NXgeometry:NXshape@units", "milli*metre"); // NXGeometery:NXFloat double[] pixelSize = { toDouble("sizeFast"), toDouble("sizeSlow") }; GDAMetadata.put("NXdetector:x_pixel_size", pixelSize[0]); GDAMetadata.put("NXdetector:x_pixel_size@units", "milli*metre"); GDAMetadata.put("NXdetector:y_pixel_size", pixelSize[1]); GDAMetadata.put("NXdetector:y_pixel_size@units", "milli*metre"); // "NXmonochromator:wavelength" GDAMetadata.put("NXmonochromator:wavelength", toDouble("wavelength")); GDAMetadata.put("NXmonochromator:wavelength@units", "Angstrom"); // oscillation range GDAMetadata.put("NXsample:rotation_start", st); GDAMetadata.put("NXsample:rotation_start@units", "degree"); GDAMetadata.put("NXsample:rotation_range", toDouble("phiend") - st); GDAMetadata.put("NXsample:rotation_range@units", "degree"); // Exposure time GDAMetadata.put("NXsample:exposure_time", toDouble("minutes") * 60); GDAMetadata.put("NXsample:exposure_time@units", "seconds"); return detectorOrigin; } catch (Exception e) { throw new ScanFileHolderException("There was a problem creating the GDA metatdata", e); } } private void createMetadata(double[] detectorOrigin, int nx, int ny, double st) { DetectorProperties detProps = new DetectorProperties(new Vector3d(detectorOrigin), ny, nx, toDouble("sizeSlow"), toDouble("sizeFast"), null); DiffractionCrystalEnvironment diffEnv = new DiffractionCrystalEnvironment(toDouble("wavelength"), st, toDouble("phiend"), toDouble("minutes") * 60); metadata = new DiffractionMetadata(fileName, detProps, diffEnv); HashMap<String, Serializable> md = new HashMap<String, Serializable>(); md.putAll(metadataMap); md.putAll(GDAMetadata); metadata.setMetadata(md); metadata.addDataInfo(DATA_NAME, ny, nx); } }