    001/*****************************************************************************
    002 * Copyright by The HDF Group.                                               *
    003 * Copyright by the Board of Trustees of the University of Illinois.         *
    004 * All rights reserved.                                                      *
    005 *                                                                           *
    006 * This file is part of the HDF Java Products distribution.                  *
    007 * The full copyright notice, including terms governing use, modification,   *
    008 * and redistribution, is contained in the files COPYING and Copyright.html. *
    009 * COPYING can be found at the root of the source code distribution tree.    *
    010 * Or, see https://support.hdfgroup.org/products/licenses.html               *
    011 * If you do not have access to either file, you may request a copy from     *
    012 * help@hdfgroup.org.                                                        *
    013 ****************************************************************************/
    014
    015package hdf.object.fits;
    016
    017import java.lang.reflect.Array;
    018import java.util.Iterator;
    019import java.util.List;
    020import java.util.Vector;
    021
    022import hdf.object.Attribute;
    023import hdf.object.Dataset;
    024import hdf.object.Datatype;
    025import hdf.object.FileFormat;
    026import hdf.object.Group;
    027import hdf.object.HObject;
    028import hdf.object.ScalarDS;
    029import nom.tam.fits.BasicHDU;
    030import nom.tam.fits.Header;
    031import nom.tam.fits.HeaderCard;
    032
    033/**
    034 * FitsDataset describes an multi-dimension array of HDF5 scalar or atomic data
    035 * types, such as byte, int, short, long, float, double and string,
    036 * and operations performed on the scalar dataset
    037 * <p>
    038 * The library predefines a modest number of datatypes. For details, read <a
    039 * href="https://support.hdfgroup.org/HDF5/doc/UG/HDF5_Users_Guide-Responsive%20HTML5/HDF5_Users_Guide/Datatypes/HDF5_Datatypes.htm">
    040 * The Datatype Interface (H5T)</a>
    041 * <p>
    042 * @version 1.1 9/4/2007
    043 * @author Peter X. Cao
    044 */
    045public class FitsDataset extends ScalarDS
    046{
    047    private static final long serialVersionUID = 3944770379558335171L;
    048
    049    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FitsDataset.class);
    050
    051    /**
    052     * The list of attributes of this data object. Members of the list are
    053     * instance of Attribute.
    054     */
    055    private List attributeList;
    056
    057    private BasicHDU nativeDataset;
    058
    059    /**
    060     * Constructs an FitsDataset object with specific netcdf variable.
    061     *
    062     * @param fileFormat the netcdf file.
    063     * @param hdu the BasicHDU.
    064     * @param dName the name for this dataset.
    065     * @param oid the unique identifier for this dataset.
    066     */
    067    public FitsDataset(FileFormat fileFormat, BasicHDU hdu, String dName, long[] oid) {
    068        super(fileFormat, dName, HObject.SEPARATOR, oid);
    069        unsignedConverted = false;
    070        nativeDataset = hdu;
    071    }
    072
    073    /*
    074     * (non-Javadoc)
    075     * @see hdf.object.DataFormat#hasAttribute()
    076     */
    077    @Override
    078    public boolean hasAttribute () { return false; }
    079
    080    /*
    081     * (non-Javadoc)
    082     * @see hdf.object.Dataset#copy(hdf.object.Group, java.lang.String, long[], java.lang.Object)
    083     */
    084    @Override
    085    public Dataset copy(Group pgroup, String dstName, long[] dims, Object buff)
    086            throws Exception {
    087        // not supported
    088        throw new UnsupportedOperationException("copy operation unsupported for FITS.");
    089    }
    090
    091    /*
    092     * (non-Javadoc)
    093     * @see hdf.object.Dataset#readBytes()
    094     */
    095    @Override
    096    public byte[] readBytes() throws Exception {
    097        // not supported
    098        throw new UnsupportedOperationException("readBytes operation unsupported for FITS.");
    099    }
    100
    101    /*
    102     * (non-Javadoc)
    103     * @see hdf.object.Dataset#read()
    104     */
    105    @Override
    106    public Object read() throws Exception {
    107        Object theData = null;
    108        Object fitsData = null;
    109
    110        if (nativeDataset == null) {
    111            return null;
    112        }
    113
    114        try {
    115            fitsData = nativeDataset.getData().getData();
    116        }
    117        catch (Exception ex) {
    118            throw new UnsupportedOperationException("This implementation only supports integer and float dataset. " +
    119                    "It may not work for other datatypes. \n"+ex);
    120        }
    121
    122        int n = get1DLength(fitsData);
    123
    124        theData = FitsDatatype.allocateArray(nativeDataset.getBitPix(), n);
    125
    126        to1Darray(fitsData, theData, 0);
    127
    128        return theData;
    129    }
    130
    131    /*
    132     * (non-Javadoc)
    133     * @see hdf.object.Dataset#write(java.lang.Object)
    134     */
    135    @Override
    136    public void write(Object buf) throws Exception {
    137        // not supported
    138        throw new UnsupportedOperationException("write operation unsupported for FITS.");
    139    }
    140
    141    /*
    142     * (non-Javadoc)
    143     * @see hdf.object.DataFormat#getMetadata()
    144     */
    145    @SuppressWarnings("rawtypes")
    146    @Override
    147    public List getMetadata() throws Exception {
    148        if (attributeList != null) {
    149            return attributeList;
    150        }
    151
    152        if (nativeDataset == null) {
    153            return null;
    154        }
    155
    156        Header header = nativeDataset.getHeader();
    157        if (header == null) {
    158            return null;
    159        }
    160
    161        attributeList = new Vector();
    162        HeaderCard hc = null;
    163        Iterator it = header.iterator();
    164        Attribute attr = null;
    165        Datatype dtype = new FitsDatatype(Datatype.CLASS_STRING, 80, 0, 0);
    166        long[] dims = {1};
    167        String value = null;
    168        while (it.hasNext()) {
    169            value = "";
    170            hc = (HeaderCard)it.next();
    171            attr = new Attribute(this, hc.getKey(), dtype, dims);
    172            String tvalue = hc.getValue();
    173            if (tvalue != null) {
    174                value += tvalue;
    175            }
    176            tvalue = hc.getComment();
    177            if (tvalue != null) {
    178                value += " / " + tvalue;
    179            }
    180            attr.setData(value);
    181            attributeList.add(attr);
    182        }
    183
    184        return attributeList;
    185    }
    186
    187    /*
    188     * (non-Javadoc)
    189     * @see hdf.object.DataFormat#writeMetadata(java.lang.Object)
    190     */
    191    @Override
    192    public void writeMetadata(Object info) throws Exception {
    193        // not supported
    194        throw new UnsupportedOperationException("writeMetadata operation unsupported for FITS.");
    195    }
    196
    197    /*
    198     * (non-Javadoc)
    199     * @see hdf.object.DataFormat#removeMetadata(java.lang.Object)
    200     */
    201    @Override
    202    public void removeMetadata(Object info) throws Exception {
    203        // not supported
    204        throw new UnsupportedOperationException("removeMetadata operation unsupported for FITS.");
    205    }
    206
    207    /*
    208     * (non-Javadoc)
    209     * @see hdf.object.DataFormat#updateMetadata(java.lang.Object)
    210     */
    211    @Override
    212    public void updateMetadata(Object info) throws Exception {
    213        // not supported
    214        throw new UnsupportedOperationException("updateMetadata operation unsupported for FITS.");
    215    }
    216
    217    /*
    218     * (non-Javadoc)
    219     * @see hdf.object.HObject#open()
    220     */
    221    @Override
    222    public long open() { return -1;}
    223
    224    /*
    225     * (non-Javadoc)
    226     * @see hdf.object.HObject#close(int)
    227     */
    228    @Override
    229    public void close(long did) {
    230        // Nothing to implement
    231    }
    232
    233    /*
    234     * (non-Javadoc)
    235     * @see hdf.object.Dataset#init()
    236     */
    237    @Override
    238    public void init() {
    239        if (nativeDataset == null) {
    240            return;
    241        }
    242
    243        if (inited) {
    244            return; // already called. Initialize only once
    245        }
    246
    247        int[] axes= null;
    248        try {
    249            axes = nativeDataset.getAxes();
    250        }
    251        catch (Exception ex) {
    252            log.debug("nativeDataset.getAxes():", ex);
    253        }
    254
    255        if (axes == null) {
    256            return;
    257        }
    258
    259
    260        rank = axes.length;
    261        if (rank == 0) {
    262            // a scalar data point
    263            rank = 1;
    264            dims = new long[1];
    265            dims[0] = 1;
    266        }
    267        else {
    268            dims = new long[rank];
    269            for (int i=0; i<rank; i++) {
    270                dims[i] = axes[i];
    271            }
    272        }
    273
    274        startDims = new long[rank];
    275        selectedDims = new long[rank];
    276        for (int i=0; i<rank; i++) {
    277            startDims[i] = 0;
    278            selectedDims[i] = 1;
    279        }
    280
    281        if (rank == 1) {
    282            selectedIndex[0] = 0;
    283            selectedDims[0] = dims[0];
    284        }
    285        else if (rank == 2) {
    286            selectedIndex[0] = 0;
    287            selectedIndex[1] = 1;
    288            selectedDims[0] = dims[0];
    289            selectedDims[1] = dims[1];
    290        }
    291        else if (rank > 2) {
    292            selectedIndex[0] = 0;
    293            selectedIndex[1] = 1;
    294            selectedIndex[2] = 2;
    295            selectedDims[0] = dims[0];
    296            selectedDims[1] = dims[1];
    297        }
    298
    299        if ((rank > 1) && isText) {
    300            selectedDims[1] = 1;
    301        }
    302
    303        inited = true;
    304    }
    305
    306    /*
    307     * (non-Javadoc)
    308     * @see hdf.object.ScalarDS#getPalette()
    309     */
    310    @Override
    311    public byte[][] getPalette()
    312    {
    313        if (palette == null) {
    314            palette = readPalette(0);
    315        }
    316
    317        return palette;
    318    }
    319
    320    /*
    321     * (non-Javadoc)
    322     * @see hdf.object.ScalarDS#readPalette(int)
    323     */
    324    @Override
    325    public byte[][] readPalette(int idx) {
    326        return null;
    327    }
    328
    329    /**
    330     * Creates a new dataset.
    331     *
    332     * @param name the name of the dataset to create.
    333     * @param pgroup the parent group of the new dataset.
    334     * @param type the datatype of the dataset.
    335     * @param dims the dimension size of the dataset.
    336     * @param maxdims the max dimension size of the dataset.
    337     * @param chunks the chunk size of the dataset.
    338     * @param gzip the level of the gzip compression.
    339     * @param data the array of data values.
    340     *
    341     * @return the new dataset if successful. Otherwise returns null.
    342     *
    343     * @throws Exception
    344     *            if there is an error
    345     */
    346    public static FitsDataset create(
    347            String name,
    348            Group pgroup,
    349            Datatype type,
    350            long[] dims,
    351            long[] maxdims,
    352            long[] chunks,
    353            int gzip,
    354            Object data) throws Exception {
    355        // not supported
    356        throw new UnsupportedOperationException("Unsupported operation for FITS.");
    357    }
    358
    359    /*
    360     * (non-Javadoc)
    361     * @see hdf.object.ScalarDS#getPaletteRefs()
    362     */
    363    @Override
    364    public byte[] getPaletteRefs() {
    365        return null;
    366    }
    367
    368    /*
    369     * (non-Javadoc)
    370     * @see hdf.object.Dataset#getDatatype()
    371     */
    372    @Override
    373    public Datatype getDatatype() {
    374        if (datatype == null) {
    375            try {
    376                datatype = new FitsDatatype(nativeDataset.getBitPix());
    377            }
    378            catch (Exception ex) {
    379                log.debug("getDatatype(): failed to create datatype: ", ex);
    380                datatype = null;
    381            }
    382        }
    383
    384        return datatype;
    385    }
    386
    387    /*
    388     * (non-Javadoc)
    389     * @see hdf.object.HObject#setName(java.lang.String)
    390     */
    391    @Override
    392    public void setName (String newName) throws Exception {
    393        // not supported
    394        throw new UnsupportedOperationException("Unsupported operation for FITS.");
    395    }
    396
    397    private int get1DLength(Object data) throws Exception {
    398
    399        if (!data.getClass().isArray()) {
    400            return 1;
    401        }
    402
    403        int len = Array.getLength(data);
    404
    405        int total = 0;
    406        for (int i = 0; i < len; i++) {
    407            total += get1DLength(Array.get(data, i));
    408        }
    409
    410        return total;
    411    }
    412
    413    /** copy multi-dimension array of fits data into 1D array */
    414    private int to1Darray(Object dataIn, Object dataOut, int offset) throws Exception {
    415        Class component = dataIn.getClass().getComponentType();
    416        if (component == null) {
    417            return offset;
    418        }
    419
    420        int size = Array.getLength(dataIn);
    421        if (!component.isArray()) {
    422            System.arraycopy(dataIn, 0, dataOut, offset, size);
    423            return offset+size;
    424        }
    425
    426        for (int i = size - 1; i >= 0; i--) {
    427            offset = to1Darray(Array.get(dataIn, i), dataOut, offset);
    428        }
    429
    430        return offset;
    431    }
    432
    433    //Implementing DataFormat
    434    public List getMetadata(int... attrPropList) throws Exception {
    435        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
    436    }
    437}