/*
* Copyright 1998-2015 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.iosp.gempak;
import ucar.unidata.io.RandomAccessFile;
import ucar.unidata.util.Format;
import ucar.unidata.util.StringUtil2;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* Read a Gempak sounding file
*
* @author IDV Development Team
*/
public class GempakSoundingFileReader extends AbstractGempakStationFileReader {
/**
* Surface Text identifier
*/
public static final String SNDT = "SNDT";
/**
* date key identifier
*/
public static final String DATE = "DATE";
/**
* time key identifier
*/
public static final String TIME = "TIME";
/**
* PRES vertical coordinate
*/
public static final int PRES_COORD = 1;
/**
* THTA vertical coordinate
*/
public static final int THTA_COORD = 2;
/**
* HGHT vertical coordinate
*/
public static final int HGHT_COORD = 3;
/**
* standard surface file id
*/
public static final String MERGED = "merged";
/**
* climate surface file id
*/
public static final String UNMERGED = "unmerged";
/**
* vertical coordinate
*/
private int ivert = -1;
/**
* list of unmerged parts
*/
private List<String> unmergedParts;
/**
* array of manadatory parameters
*/
private final String[] mandpp = {"PRES", "TEMP", "DWPT", "DRCT", "SPED", "HGHT"};
/**
* array of significant temperature parameters
*/
private final String[] sigtpp = {"PRES", "TEMP", "DWPT"};
/**
* array of significant wind parameters
*/
private final String[] sigwpp = {"HGHT", "DRCT", "SPED"};
/**
* array of tropopause parameters
*/
private final String[] troppp = {"PRES", "TEMP", "DWPT", "DRCT", "SPED"};
/**
* array of maximum wind parameters
*/
private final String[] maxwpp = {"PRES", "DRCT", "SPED"};
/**
* array of groups below 100 mb
*/
private final String[] belowGroups = {"TTAA", "TRPA", "MXWA", "PPAA", "TTBB", "PPBB"};
/**
* array of groups above 100 mb
*/
private final String[] aboveGroups = {"TTCC", "TRPC", "MXWC", "PPCC", "TTDD", "PPDD"};
/**
* list of valid params for each group
*/
private final String[][] parmLists = {mandpp, troppp, maxwpp, maxwpp, sigtpp, sigwpp};
/**
* Default ctor
*/
GempakSoundingFileReader() {
}
/**
* Initialize the file, read in all the metadata (ala DM_OPEN)
*
* @param raf RandomAccessFile to read.
* @param fullCheck if true, check entire structure
* @return A GempakSoundingFileReader
* @throws IOException problem reading file
*/
public static GempakSoundingFileReader getInstance(RandomAccessFile raf, boolean fullCheck) throws IOException {
GempakSoundingFileReader gsfr = new GempakSoundingFileReader();
gsfr.init(raf, fullCheck);
return gsfr;
}
/**
* Initialize this reader. Read all the metadata
*
* @return true if successful
* @throws IOException problem reading the data
*/
protected boolean init() throws IOException {
return init(true);
}
/**
* Initialize this reader. Get the Grid specific info
*
* @param fullCheck check to make sure there are grids we can handle
* @return true if successful
* @throws IOException problem reading the data
*/
protected boolean init(boolean fullCheck) throws IOException {
if (!super.init(fullCheck)) {
return false;
}
// Modeled after SN_OFIL
if (dmLabel.kftype != MFSN) {
logError("not a sounding data file ");
return false;
}
DMPart part = getPart(SNDT);
if (part != null) { // merged file
subType = MERGED;
String vertName = part.params.get(0).kprmnm;
switch (vertName) {
case "PRES":
ivert = PRES_COORD;
break;
case "THTA":
ivert = THTA_COORD;
break;
case "HGHT":
case "MHGT":
case "DHGT":
ivert = HGHT_COORD;
break;
default:
logError("unknown vertical coordinate in merged file");
return false;
}
} else {
unmergedParts = SN_CKUA();
boolean haveUnMerged = !unmergedParts.isEmpty();
if (!haveUnMerged) {
logError("unknown sounding file type - not merged/unmerged");
return false;
} else {
ivert = PRES_COORD;
subType = UNMERGED;
}
}
if (!readStationsAndTimes(true)) {
logError("Unable to read stations and times");
return false;
}
return true;
}
/**
* Get the vertical coordinate
*
* @return the vertical coordinate (PRES_COORD, THTA_COORD, HGHT_COORD)
*/
public int getVerticalCoordinate() {
return ivert;
}
/**
* Get the list of merged parts in this file
*
* @return a list of the unmerged parts (only SNDT)
*/
public List<String> getMergedParts() {
List<String> list = new ArrayList<>(1);
list.add(SNDT);
return list;
}
/**
* Get the list of unmerged parts in this file
*
* @return a list of the unmerged parts
*/
public List<String> getUnmergedParts() {
return new ArrayList<>(unmergedParts);
}
/**
* Make the file subtype
*/
protected void makeFileSubType() {
} // already set in init()
/**
* Print the list of dates in the file
*
* @param row ob row
* @param col ob column
*/
public void printOb(int row, int col) {
GempakStation station = getStations().get(col - 1);
String time = getDateString(row - 1);
StringBuilder builder = new StringBuilder("\n");
builder.append(makeHeader(station, time));
builder.append("\n");
boolean merge = getFileSubType().equals(MERGED);
List<String> parts;
if (merge) {
parts = new ArrayList<>();
parts.add(SNDT);
} else {
parts = unmergedParts;
}
for (String part : parts) {
RData rd;
try {
rd = DM_RDTR(row, col, part);
} catch (IOException ioe) {
ioe.printStackTrace();
rd = null;
}
if (rd == null) {
continue;
}
if (!merge) {
builder.append(" ");
builder.append(part);
builder.append(" ");
builder.append(time.substring(time.indexOf("/") + 1));
}
builder.append("\n");
if (!merge) {
builder.append("\t");
}
List<GempakParameter> params = getParameters(part);
for (GempakParameter parm : params) {
builder.append(StringUtil2.padLeft(parm.getName(), 7));
builder.append("\t");
}
builder.append("\n");
if (!merge) {
builder.append("\t");
}
float[] data = rd.data;
int numParams = params.size();
int numLevels = data.length / numParams;
for (int j = 0; j < numLevels; j++) {
for (int i = 0; i < numParams; i++) {
builder.append(
StringUtil2.padLeft(
Format.formatDouble(
data[j * numParams + i], 7, 1), 7));
builder.append("\t");
}
builder.append("\n");
if (!merge) {
builder.append("\t");
}
}
builder.append("\n");
}
builder.append("\n");
System.out.println(builder.toString());
}
/**
* Make the header for the text report
*
* @param stn the station
* @param date the date
* @return the header
*/
private String makeHeader(GempakStation stn, String date) {
StringBuilder builder = new StringBuilder();
builder.append("STID = ");
builder.append(StringUtil2.padRight((stn.getSTID().trim()
+ stn.getSTD2().trim()), 8));
builder.append("\t");
builder.append("STNM = ");
builder.append(Format.i(stn.getSTNM(), 6));
builder.append("\t");
builder.append("TIME = ");
builder.append(date);
builder.append("\n");
builder.append("SLAT = ");
builder.append(Format.d(stn.getLatitude(), 5));
builder.append("\t");
builder.append("SLON = ");
builder.append(Format.d(stn.getLongitude(), 5));
builder.append("\t");
builder.append("SELV = ");
builder.append(Format.d(stn.getAltitude(), 5));
builder.append("\n");
return builder.toString();
}
/**
* This subroutine checks the parts in a sounding data set for the
* unmerged data types.
*
* @return list of part names
*/
private List<String> SN_CKUA() {
List<String> types = new ArrayList<>();
boolean above = false;
boolean done = false;
String partToCheck;
while (!done) {
// check for mandatory groups
for (int group = 0; group < belowGroups.length; group++) {
if (above) {
partToCheck = aboveGroups[group];
} else {
partToCheck = belowGroups[group];
}
if (checkForValidGroup(partToCheck, parmLists[group])) {
types.add(partToCheck);
}
}
if (!above) {
above = true;
} else {
done = true;
}
}
return types;
}
/**
* Check for valid groups
*
* @param partToCheck the part name
* @param params the parameters that are supposed to be there
* @return true if the part is there and has the right params
*/
private boolean checkForValidGroup(String partToCheck, String[] params) {
DMPart part = getPart(partToCheck);
if (part == null) {
return false;
}
int i = 0;
for (DMParam parm : part.params) {
if (!(parm.kprmnm.equals(params[i++]))) {
return false;
}
}
return true;
}
/**
* Run the program
*
* @param args [0] filename (required),
* [1] variable name (X for default),
* [2] X to not list grids
* @throws IOException problem reading the file
*/
public static void main(String[] args) throws IOException {
if (args.length == 0) {
System.out.println("need to supply a GEMPAK sounding file name");
System.exit(1);
}
try {
GempakParameters.addParameters(
"resources/nj22/tables/gempak/params.tbl");
} catch (Exception e) {
System.out.println("unable to init param tables");
}
GempakSoundingFileReader gsfr = getInstance(getFile(args[0]), true);
System.out.println("Type = " + gsfr.getFileType());
gsfr.printFileLabel();
gsfr.printKeys();
gsfr.printHeaders();
gsfr.printParts();
gsfr.printDates();
gsfr.printStations(false);
int row = 1;
int col = 1;
if (args.length > 1) {
row = Integer.parseInt(args[1]);
}
if (args.length > 2) {
try {
col = Integer.parseInt(args[2]);
} catch (Exception npe) {
col = gsfr.findStationIndex(args[2]);
if (col == -1) {
System.out.println("couldn't find station " + args[2]);
System.exit(1);
}
System.out.println("found station at column " + col);
}
}
gsfr.printOb(row, col);
}
}