/* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /**************************************************************************** * NCSA HDF * * National Comptational Science Alliance * * University of Illinois at Urbana-Champaign * * 605 E. Springfield, Champaign IL 61820 * * * * For conditions of distribution and use, see the accompanying * * hdf/COPYING file. * * * ****************************************************************************/ package visad.data.hdf5; import visad.*; import visad.data.*; import visad.UnimplementedException; import java.rmi.*; import java.net.URL; import ncsa.hdf.hdf5lib.H5; import ncsa.hdf.hdf5lib.HDF5Constants; import ncsa.hdf.hdf5lib.HDF5CDataTypes; import ncsa.hdf.hdf5lib.exceptions.HDF5Exception; /** HDF5Form is a data form adapter for HDF5 files. */ public class HDF5Form extends Form implements FormFileInformer { public HDF5Form() { this( "HDF5 Data" ); } public HDF5Form(String name ) { super( name ); } public boolean isThisType(String name) { boolean retVal = false; try { retVal = H5.H5Fis_hdf5(name); } catch (Exception ex) {;} return retVal; } public boolean isThisType(byte[] block) { int firstByte = (new Byte(block[0]).intValue()); if (firstByte != 137) return false; String bytes2to4 = new String( block, 1, 4 ); return bytes2to4.startsWith("HDF"); } public String[] getDefaultSuffixes() { String[] suffs = { "hdf", "h5"}; return suffs; } public FormNode getForms( Data data ) { return this; } public DataImpl open( String file_path ) throws VisADException, RemoteException { HDF5FileAdapted file = null; try { file = new HDF5FileAdapted( file_path, HDF5Constants.H5F_ACC_RDONLY, HDF5Constants.H5P_DEFAULT ); } catch (HDF5Exception e) {System.err.println(e); } return getFileData( file ); } public DataImpl open( URL url ) throws VisADException { throw new UnimplementedException( "HDF5Form.open( URL )" ); } public void add( String id, Data data, boolean replace ) throws BadFormException { throw new BadFormException( "HDF5Form.add( String, Data, boolean )" ); } public void save( String filename, Data data, boolean replace ) throws BadFormException, RemoteException, VisADException { //System.out.println("\n\nHDF5Form.save called."); int fid=0, did=0, gid=0; try { fid = H5.H5Fcreate(filename, HDF5Constants.H5F_ACC_TRUNC, HDF5Constants.H5P_DEFAULT, HDF5Constants.H5P_DEFAULT); } catch (HDF5Exception e) { throw new HDF5AdapterException( "HDF5Form.save() failed: cannot create file "+filename); } catch (NoClassDefFoundError e) { throw new HDF5AdapterException( "HDF5Form.save() failed: cannot create file "+filename); } try { save(fid, data, 0, 0); } catch (BadFormException e) { throw e; } catch (RemoteException e) { throw e; } catch (VisADException e) { throw e; } catch (HDF5Exception e) { throw new HDF5AdapterException(e.toString()); } finally { try{H5.H5Fclose(fid);} catch (Exception e) {} } } /** Save only tuple and field. Tuple is mapped to HDF5 groups and Field is mapped to HDF5 dataset. Only the first range value, i.e. value[][0] is written to the output file. We don't know how to deal with compound data. */ private void save( int pid, Data data, int level, int index) throws BadFormException, RemoteException, VisADException, HDF5Exception { if (data instanceof Tuple) { int g_idx=0, new_pid=0; Data d = null; Tuple tuple = (Tuple)data; String gname = "Group"+index+"at"+level; if (level==0 ) { new_pid=pid; g_idx = -1; } else { new_pid = H5.H5Gcreate(pid, gname, -1); } int n = tuple.getDimension(); for (int i = 0; i < n; i++) { d = tuple.getComponent(i); //if (data instanceof Tuple) g_idx++; save(new_pid, d, level+1, g_idx++); } } else if (data instanceof Field) { Field field = (Field)data; RealType[] rTypes = ((FunctionType) field.getType()).getRealComponents(); Set dset = field.getDomainSet(); if (!(dset instanceof GriddedSet) || rTypes == null) return; GriddedSet domain = (GriddedSet)dset; RealType rangeType = (RealType) rTypes[0]; int sid=0, did=0, tid=0; int l = domain.getLength(); int[] ddims = domain.getLengths(); int rank = ddims.length; long[] dims = new long[rank]; for (int i=0; i<rank; i++) dims[i] = ddims[i]; sid = H5.H5Screate_simple(rank, dims, null); int number_of_range_components = 1; if (field.isFlatField()) number_of_range_components = ((FlatField)field).getRangeDimension(); else number_of_range_components = ((Unit[]) field.getDefaultRangeUnits()).length; float[] rangeValues = new float[l]; float[][] rValue = field.getFloats(false); if (number_of_range_components==1) { for (int i=0; i<l; i++) rangeValues[i] = rValue[0][i]; try { did = H5.H5Dcreate(pid, rangeType.getName(), H5.J2C(HDF5CDataTypes.JH5T_NATIVE_FLOAT), sid, HDF5Constants.H5P_DEFAULT); H5.H5Dwrite(did, H5.J2C(HDF5CDataTypes.JH5T_NATIVE_FLOAT), HDF5Constants.H5S_ALL, HDF5Constants.H5S_ALL, HDF5Constants.H5P_DEFAULT, rangeValues); } finally { H5.H5Dclose(did); H5.H5Sclose(sid); } } else // write compound data { float[][] fValue = new float[l][number_of_range_components]; for (int i=0; i<l; i++) { for (int j=0; j<number_of_range_components; j++) fValue[i][j] = rValue[j][i]; } try { tid = H5.H5Tcreate(HDF5Constants.H5T_COMPOUND,number_of_range_components*4); for (int j=0; j<number_of_range_components; j++) { rangeType = (RealType) rTypes[j]; H5.H5Tinsert(tid, rangeType.getName(), j*4, H5.J2C(HDF5CDataTypes.JH5T_NATIVE_FLOAT)); } String dname = "Compound"+index+"at"+level; did = H5.H5Dcreate(pid, dname, tid, sid, HDF5Constants.H5P_DEFAULT); H5.H5Dwrite(did, tid, sid, HDF5Constants.H5S_ALL, HDF5Constants.H5P_DEFAULT,fValue); } finally { H5.H5Tclose(tid); H5.H5Dclose(did); H5.H5Sclose(sid); } } } else if (data instanceof Text) { Text text = (Text) data; String text_value = text.getValue(); TextType tt = (TextType)text.getType(); String text_name = tt.getName(); int max_length=text_value.length(); long[] dims_str = {1}; int dataspace = H5.H5Screate_simple(1, dims_str, null); int datatype = H5.H5Tcopy(H5.J2C(HDF5CDataTypes.JH5T_C_S1)); H5.H5Tset_size(datatype,max_length); H5.H5Tset_strpad(datatype,HDF5Constants.H5T_STR_NULLPAD); int dataset = H5.H5Dcreate(pid, text_name, datatype, dataspace, HDF5Constants.H5P_DEFAULT); byte [][] bnotes = new byte[1][max_length]; bnotes[0] = text_value.getBytes(); H5.H5Dwrite(dataset, datatype, HDF5Constants.H5S_ALL, HDF5Constants.H5S_ALL, HDF5Constants.H5P_DEFAULT, bnotes); H5.H5Dclose(dataset); bnotes = null; } } public MathType getMathType( HDF5FileAdapted file ) throws VisADException, RemoteException { MathType mathType = null; HDF5DataAdaptable data = null; int n_structs = file.getObjectCount(); if ( n_structs <= 0 ) { throw new HDF5AdapterException("no data object in file: "+file.getName()); } MathType[] types = new MathType[ n_structs ]; for ( int i = 0; i < n_structs; i++ ) { Object obj = file.getDataObject(i); if ( obj instanceof HDF5GroupAdapted ) { data = (HDF5GroupAdapted)obj; } else if ( obj instanceof HDF5DatasetAdapted ) { data = (HDF5DatasetAdapted)obj; } mathType = data.getMathType(); types[i] = mathType; } TupleType t_type = new TupleType( types ); return (MathType) t_type; } public DataImpl getFileData( HDF5FileAdapted file ) throws VisADException, RemoteException { //System.out.println("HDF5Form.getFileData() called"); DataImpl data = null; HDF5DataAdaptable h5Data = null; int n_structs = file.getObjectCount(); if ( n_structs <= 0 ) { throw new HDF5AdapterException("no data object in file: "+file.getName()); } HDF5DataAdaptable[] datas = new HDF5DataAdaptable[ n_structs ]; // only deal with Groups and datasets int ndatas=0; for ( int i = 0; i < n_structs; i++ ) { Object obj = file.getDataObject(i); if ( obj instanceof HDF5GroupAdapted ) { datas[ndatas++] = (HDF5GroupAdapted)obj; } else if ( obj instanceof HDF5DatasetAdapted ) { datas[ndatas++] = (HDF5DatasetAdapted)obj; } } return assembleStructs( datas ); } private DataImpl assembleStructs( HDF5DataAdaptable[] h_datas ) throws VisADException, RemoteException { //System.out.println("HDF5Form.assembleStructs() called"); DataImpl fileData = null; int n_structs = h_datas.length; if ( n_structs == 1 ) return getVisADDataObject( h_datas[0] ); boolean types_equal = true; MathType first_type = null; MathType[] types = new MathType[ n_structs ]; DataImpl[] datas = new DataImpl[ n_structs ]; datas[0] = getVisADDataObject( h_datas[0] ); types[0] = datas[0].getType(); first_type = types[0]; for ( int i = 1; i < n_structs; i++ ) { datas[i] = getVisADDataObject( h_datas[i] ); types[i] = datas[i].getType(); types_equal = types[i].equals(first_type); } if ( types_equal ) { RealType struct_id = RealType.getRealType("struct_id"); Integer1DSet domain = new Integer1DSet(struct_id, n_structs); FunctionType fType = new FunctionType((MathType) struct_id, first_type); FieldImpl field = new FieldImpl(fType, domain); for ( int i = 0; i < n_structs; i++ ) field.setSample(i, datas[i]); fileData = field; } else { TupleType t_type = new TupleType( types ); fileData = new Tuple( t_type, datas, false ); } return fileData; } public DataImpl getVisADDataObject( HDF5DataAdaptable h_data ) throws VisADException, RemoteException { return h_data.getAdaptedData(); } }