/** * GranitePrint -- print a portion of a Granite file * and generate some simple stats; min/max/average * * Arguments: xfdlfile - input data set * bounds - optional subblock specification * * rdb 01/26/12 -- derived from SubFile.java * */ import java.io.*; import java.nio.*; import edu.unh.sdb.common.*; import edu.unh.sdb.datasource.*; import java.io.*; import java.nio.*; import java.util.*; public class GranitePrint { //----------------- class variables ----------------------------- static String inName = null; static String baseName = null; static int[] boundsArgs = null; static RecordDescriptor rd = null; static double[] min = null; static double[] max = null; static double[] sum = null; //-- formatting variables static int maxLineLength = 100; static String foldStart = " "; static String sliceLine = " ------------------------------ "; //------------------------ main ------------------------------------- public static void main(String arg[]) throws FileNotFoundException, IOException { readArgs( arg ); DataSource ds = DataSource.create( "input", inName ); ds.activate(); int nAttr = ds.getNumAttributes(); min = new double[ nAttr ]; max = new double[ nAttr ]; sum = new double[ nAttr ]; for ( int i = 0; i < nAttr; i++ ) { min[ i ] = Double.MAX_VALUE; max[ i ] = Double.MIN_VALUE; sum[ i ] = 0; } DataBlock db = getData( ds ); //System.err.println( " out bounds " + db.getBounds() ); printBlock( db ); // print to stderr some simple stats StringBuffer line = new StringBuffer(); Formatter fmt = new Formatter( line ); System.err.printf( "%4s\t%12s%12s%12s", "Attr", "min", "max", "avg\n" ); for ( int i = 0; i < nAttr; i++ ) { fmt.format( "%4d\t%12.4f\t%12.4f\t%12.4f", i, min[ i ], max[ i ], ( sum[ i ] / db.volume() )); System.err.println( line ); } } //------------------- getData ------------------------------- /** * get the subblock of data desired */ private static DataBlock getData( DataSource inDS ) { int dim = inDS.dim(); ISBounds dsb = inDS.getBounds(); if ( boundsArgs != null ) { int[] lb = new int[ dim ]; int[] ub = new int[ dim ]; if ( boundsArgs.length == dim ) { for ( int i = 0; i < dim; i++ ) { lb[ i ] = 0; ub[ i ] = boundsArgs[ i ] - 1; } dsb = new ISBounds( lb, ub ); } else if ( boundsArgs.length == 2 * dim ) { for ( int i = 0; i < dim; i++ ) { lb[ i ] = boundsArgs[ i ]; ub[ i ] = boundsArgs[ i + 3 ]; } dsb = new ISBounds( lb, ub ); } else { System.err.println( "Error in bounds args: must have " + dim + " bounds or " + (2*dim) + " bounds. " + boundsArgs.length + " found. Using NO subbounds." ); } } DataBlock db = inDS.subblock( dsb ); return db; } //-------------- printBlock ------------------------------------ /** * This code will won't work so nicely for dim > 3 */ private static void printBlock( DataBlock block ) throws IOException { ISBounds bnds = block.getBounds(); ISIterator isi = new ISIterator( bnds ); RecordDescriptor rd = block.getRecordDescriptor(); int[] types = rd.getStorageTypes(); StringBuffer line = new StringBuffer( ); int lastSlice = -1; int thisSlice = 0; int lastCol = bnds.getUpper( bnds.dim() - 1 ); for( isi.init(); isi.valid(); isi.next() ) { if ( isi.dim() > 2 ) thisSlice = isi.getCoord( isi.dim() - 3 ); // if at start of a slice, output a separator if ( thisSlice != lastSlice ) { line.append( sliceLine + " Slice: " + thisSlice + sliceLine ); printLine( line ); line.setLength( 0 ); lastSlice = thisSlice; } if ( line.length() == 0 ) line.append( ((IndexSpaceID) isi).toString() + ": " ); Datum d = block.datum( isi ); StringBuffer s = datumToString( d, types ); if ( s.length() >= maxLineLength - line.length() ) { printLine( line ); line.setLength( 0 ); line.append( foldStart ); } line.append( s ); // if at end of row, output the line if ( isi.getCoord( isi.dim() - 1 ) == lastCol ) { printLine( line ); line.setLength( 0 ); } } printLine( line ); } //----------------- printLine( StringBuffer ) ------------------- private static void printLine( StringBuffer line ) { System.out.println( line ); } //----------------- datumToString -------------------------------- private static StringBuffer datumToString( Datum d, int[] types ) { StringBuffer str = new StringBuffer(); StringBuffer num = new StringBuffer(); Formatter fmt = new Formatter( num ); double val = 0.0; str.append( '[' ); for ( int i = 0; i < types.length; i++ ) { switch ( types[ i ] ) { case 0: // Undefined str.append( '?' ); break; case 1: // boolean byte bool = d.getByte( i ); if ( bool == 0 ) str.append( "false" ); else str.append( "true" ); break; case 2: // byte case 3: // unsigned byte case 4: // char byte b = d.getByte( i ); val = b; str.append( b ); break; case 5: // short case 6: // unsigned short short s = d.getShort( i ); val = s; str.append( s ); break; case 7: // int int n = d.getInt( i ); val = n; str.append( n ); break; case 8: // float // try to reduce typical output size; use formatted output // that defaults to 3 decimal points -- put test to see if // the output looks like 0 for a non-zero number; if so, // use default output format. float f = d.getFloat( i ); val = f; fmt.format( "%6.3f", f ); if ( num.toString().matches( " *-?0\\.0+$" ) // look like 0.0? && ( f > 0.0001 || f < -0.0001 )) // but isn't str.append( f ); else str.append( num ); break; case 9: // double // try to reduce typical output size; use formatted output // that defaults to 3 decimal points -- put test to see if // the output looks like 0 for a non-zero number; if so, // use default output format. double dbl = d.getDouble( i ); val = dbl; fmt.format( "%6.3e", dbl ); if ( num.toString().matches( " *-?0\\.0+$" ) // look like 0.0? && ( dbl > 0.0001 || dbl < -0.0001 )) // but isn't str.append( dbl ); else str.append( num ); break; case 10: // long str.append( "**LONG**" ); break; case 11: // record str.append( "**RECORD**" ); break; default: str.append( "**ERROR**" ); break; } if ( val < min[ i ] ) min[ i ] = val; if ( val > max[ i ] ) max[ i ] = val; sum[ i ] += val; str.append( ", " ); } str.setCharAt( str.length() - 2, ']' ); return str; } //---------------------- openDataSource ---------------------------- // a little utility function to read the descriptor file. // private static DataSource openDataSource( String dsName, String fileName ) { DataSource ds = null; try { ds = DataSource.create( dsName, inName ); } catch ( Exception ex ) { System.err.println( "Open error: " + ex.getMessage() ); System.exit( -1 ); } return ds; } //--------------- usage ----------------------------------- static void usage() { PrintStream out = System.out; // should pass in output stream out.println( "Usage: java GranitePrint infdl [ -l n ] [ bounds ]\n" + " infdl - xfdl file describing the input DataSource\n" + " -l n - output line length; defaults to 100\n" + " -l can precede infdl, and must precede bnds\n" + " bounds subblock of the DataSource as block input.\n" + " bnds must be either n ints or 2n ints where\n" + " n is the dim of DataSource. if n values\n" + " specified, they define SIZES of bounds \n" + " with 0,0,0 as origin of subblock\n" + " if not specified, prints the entire file" ); } //-------------- readArgs -------------------------------- // static void readArgs( String[] args ) { if ( args.length == 0 ) { usage(); System.exit( 0 ); } ArrayList intArgs = new ArrayList(); for ( int iarg = 0; iarg < args.length; iarg++ ) { String sarg = args[ iarg ]; if ( sarg.equals( "-l" )) maxLineLength = getArg( args, ++iarg, 100 ); else if ( inName == null ) // check for file name inName = args[ iarg ]; else // read bounds arguments intArgs.add( getArg( args, iarg, 0 )); } if ( intArgs.size() > 0 ) { boundsArgs = new int[ intArgs.size() ]; for ( int i = 0; i < intArgs.size(); i++ ) boundsArgs[i] = ((Integer)intArgs.get( i )).intValue(); } } //---------------------- getArg( String[], int, int ) ----------------- /** * This is a utility method for accessing one of the command line * string arguments and converting it to an int. It accepts the * entire array of arguments in String form, an integer indicating * which is to be converted to an int and a default value to be * returned if this argument was not on the command line, or if * the specified String is not a valid integer representation. */ public static int getArg( String[ ] args, int which, int defaultVal ) { try { return Integer.parseInt( args[ which ] ); } catch ( ArrayIndexOutOfBoundsException oob ) { } catch ( NumberFormatException nfe ) { System.err.println( "Error: improper command line argument " + which + " = " + args[ which ] + ". It should be an integer; using default value: " + defaultVal ); } return defaultVal; } }