// // GridDirectory.java // /* This source file is part of the edu.wisc.ssec.mcidas package and is Copyright (C) 1998 - 2017 by Tom Whittaker, Tommy Jasmin, Tom Rink, Don Murray, James Kelly, Bill Hibbard, Dave Glowacki, Curtis Rueden and others. 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 */ package edu.wisc.ssec.mcidas; import java.util.Date; /** * Class for modelling a McIDAS grid header. * @see <A HREF="http://www.ssec.wisc.edu/mcidas/doc/prog_man.html"> * McIDAS Programmer's Manual</A> * * @author Don Murray */ public class GridDirectory { /** GridDirectory block size */ public static final int DIRSIZE = 64; /** Grid size (rows*columns) */ private static final int GRIDSIZE_INDEX = 0; /** number of rows */ public static final int ROWS_INDEX = 1; /** number of columns */ public static final int COLS_INDEX = 2; /** ref date */ public static final int REFDATE_INDEX = 3; /** ref time */ public static final int REFTIME_INDEX = 4; /** forecast time */ public static final int FTIME_INDEX = 5; /** param name */ public static final int PARAM_NAME_INDEX = 6; /** param scale */ public static final int PARAM_SCALE_INDEX = 7; /** param units */ public static final int PARAM_UNITS_INDEX = 8; /** level value */ public static final int LEVEL_VALUE_INDEX = 9; /** level scale */ public static final int LEVEL_SCALE_INDEX = 10; /** level unit */ public static final int LEVEL_UNITS_INDEX = 11; /** param type */ public static final int PARAM_TYPE_INDEX = 12; /** second forecast time (for time diff or average) */ public static final int SECOND_FTIME_INDEX = 13; /** second level value */ public static final int SECOND_LEVEL_VALUE_INDEX = 14; /** navigation index */ public static final int NAV_BLOCK_INDEX = 33; /** navigation length */ public static final int NAV_BLOCK_LENGTH = 8; /** grid description */ public static final int GRID_DESCR_INDEX = 52; /** grid description length*/ public static final int GRID_DESCR_LENGTH = 12; private int[] dir = new int[GridDirectory.DIRSIZE]; // single directory private String paramName; private String gridDescription; private String paramUnitName; private int forecastHour; private Date referenceTime; private Date validTime; private Date secondTime = null; private double paramScale; private double levelValue; private String levelUnitName; private double secondLevelValue; private int rows; private int columns; private int paramType; private int[] navBlock; private GRIDnav gridNav = null; /** * Construct a GridDirectory from the grid directory block. * * @param dirblock directory block from the McIDAS grid */ public GridDirectory(int[] dirblock) throws McIDASException { if (dirblock.length != DIRSIZE) throw new McIDASException("Directory is not the right size"); System.arraycopy( dirblock, 0, dir, 0, DIRSIZE); // March down the list of parameters rows = dirblock[ROWS_INDEX]; columns = dirblock[COLS_INDEX]; // date and time values int refDay = dirblock[REFDATE_INDEX]; int refHMS = dirblock[REFTIME_INDEX]; referenceTime = new Date(McIDASUtil.mcDayTimeToSecs(refDay, refHMS) * 1000); forecastHour = dirblock[FTIME_INDEX]; validTime = new Date( (McIDASUtil.mcDayTimeToSecs(refDay,refHMS)+ (forecastHour * 3600)) * 1000 ); // parameter values paramName = McIDASUtil.intBitsToString(dirblock[PARAM_NAME_INDEX]).trim(); paramScale = Math.pow(10., dirblock[PARAM_SCALE_INDEX]); paramUnitName = McIDASUtil.intBitsToString(dirblock[PARAM_UNITS_INDEX]).trim(); paramType = dirblock[PARAM_TYPE_INDEX]; // level values levelValue = dirblock[LEVEL_VALUE_INDEX] * Math.pow(10., dirblock[LEVEL_SCALE_INDEX]); // level * scale levelUnitName = McIDASUtil.intBitsToString(dirblock[LEVEL_UNITS_INDEX]).trim(); // Special case for character levels if (Math.abs(levelValue) > 10000 && levelUnitName.equals("")) { levelUnitName = McIDASUtil.intBitsToString(dirblock[LEVEL_VALUE_INDEX]).trim(); levelValue = 999; } if (paramType == 4 || paramType == 8) // level difference or average { secondLevelValue = dirblock[SECOND_LEVEL_VALUE_INDEX] * Math.pow(10., dirblock[LEVEL_SCALE_INDEX]); // 2nd * scale } if (paramType == 1 || paramType == 2) // time difference or average { secondTime = new Date( (McIDASUtil.mcDayTimeToSecs(refDay,refHMS)+ ((dirblock[SECOND_FTIME_INDEX]/10000) * 3600)) * 1000 ); // NB: second time is 10000*time in hours to make HHMMSS // so we need to divide it out } // make the nav block navBlock = new int[NAV_BLOCK_LENGTH]; System.arraycopy( dirblock, NAV_BLOCK_INDEX, navBlock, 0, NAV_BLOCK_LENGTH); // get the grid description int[] nameBits = new int[GRID_DESCR_LENGTH]; System.arraycopy( dirblock, GRID_DESCR_INDEX, nameBits, 0, nameBits.length); gridDescription = McIDASUtil.intBitsToString(nameBits).trim(); } /** * Get the raw directory block * @return array of the raw parameters in int form * @deprecated use getDirectoryBlock */ public int[] getDirBlock() { return getDirectoryBlock(); } /** * Get the raw directory block * @return array of the raw parameters in int form */ public int[] getDirectoryBlock() { return dir; } /** * Get the name of the parameter * @return parameter name */ public String getParamName() { return paramName; } /** * Get the grid description * @return grid description */ public String getGridDescription() { return gridDescription; } /** * Get the scale of the parameter values * @return parameter scale (power of 10) */ public double getParamScale() { return paramScale; } /** * Get the unit name of the parameter values * @return unit name for this parameter */ public String getParamUnitName() { return paramUnitName; } /** * Get the reference time for this parameter * @return reference time */ public Date getReferenceTime() { return referenceTime; } /** * Get the valid time for this parameter if it is a forecast * @return valid time */ public Date getValidTime() { return validTime; } /** * Get the forecast hour for this parameter if it is a forecast * @return forecast hour */ public int getForecastHour() { return forecastHour; } /** * Get the second time for this parameter if it is a time difference * @return second time (null if only one time associated with this) */ public Date getSecondTime() { return secondTime; } /** * Get the vertical level value. * @return level By McIDAS conventions, 1013. == mean sea level, * 0. == tropopause, 1001. == surface. Otherwise, * value is what is returned. */ public double getLevelValue() { return levelValue; } /** * Get the units of the vertical level. * @return unit name of the level */ public String getLevelUnitName() { return levelUnitName; } /** * Get the second vertical level value if one exists. * @return level By McIDAS conventions, 1013. == mean sea level, * 0. == tropopause, 1001. == surface. Otherwise, * value is what is returned. */ public double getSecondLevelValue() { return secondLevelValue; } /** * Get the number of rows in the grid * @return number of rows */ public int getRows() { return rows; } /** * Get the number of columns in the grid * @return number of columns */ public int getColumns() { return columns; } /** * Get the navigation parameters. * @return array of nav parameters. The first value is the grid type * and subsequent values provide the parameters for that type. * see <A HREF="http://www.ssec.wisc.edu/mcidas/doc/prog_man.html"> * McIDAS Programmer's Manual</A> for a description * @see #getNavType() */ public int[] getNavBlock() { return navBlock; } /** * Get the navigation * @return GRIDnav for this grid (may be null) */ public GRIDnav getNavigation() { if (gridNav == null) { // make the nav module try { gridNav = new GRIDnav(getDirectoryBlock()); } catch (McIDASException excp) { gridNav = null; } } return gridNav; } /** * Get the navigation type. Type is stored as first element of * the nav block. * @return nav type * <pre> * types are: * 1 = pseudo-Mercator * 2 = Polar Stereographic or Lambert Conformal * 3 = Equidistant * 4 = pseudo-Mercator (more general) * 5 = no navigation * 6 = Lambert Conformal Tangent Cone * </pre> * @see #getNavBlock() */ public int getNavType() { return navBlock[0]; } /** * Check the equality of the object in question with this. * @param o object in question */ public boolean equals(Object o) { if (!(o instanceof GridDirectory)) return false; GridDirectory that = (GridDirectory) o; return (this == that || java.util.Arrays.equals( getDirectoryBlock(), that.getDirectoryBlock())); } /** * String representation of the GridDirectory * @return human readable string */ public String toString() { StringBuffer buff = new StringBuffer(); buff.append("Grid Directory:"); buff.append("\n"); buff.append("\tParameter = "); buff.append(paramName + " [" + paramUnitName + "] ("); buff.append(gridDescription +")"); buff.append("\n"); buff.append("\trefTime: "); buff.append(referenceTime.toGMTString()); buff.append(" valid: "+validTime.toGMTString()); buff.append("\n"); buff.append("\tsecond Time: "); buff.append( (secondTime != null) ? secondTime.toGMTString() : "none"); buff.append("\n"); buff.append("\tLevel: "); buff.append(levelValue+" ["+levelUnitName+"] second: "+secondLevelValue); buff.append("\n"); buff.append("\tNav Type: "); buff.append(getNavType()); buff.append(" rows: " + rows); buff.append(" cols: " + columns); buff.append("\n"); return buff.toString(); } }