package nl.wldelft.timeseriesparsers; import nl.wldelft.util.TextUtils; import nl.wldelft.util.coverage.PointGeometry; import nl.wldelft.util.geodatum.GeoDatum; import nl.wldelft.util.io.LineReader; import nl.wldelft.util.io.TextParser; import nl.wldelft.util.timeseries.DefaultTimeSeriesHeader; import nl.wldelft.util.timeseries.TimeSeriesContentHandler; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * TimeSeries reader for MetOffice WW3 Timeseries * <p> * A detailed description can be found in JIRA issue FEWS-11699 *<pre> * Met Office WAVEWATCH III wave model hindcast data * Location: 52.876 N 0.334 E * YYYY MM DD HH MN Wsm Wdir * 2003 12 01 00 00 4.83 103.17 * 2003 12 01 01 00 5.10 101.31 * 2003 12 01 02 00 4.84 97.12 * 2003 12 01 03 00 4.47 100.30 * 2003 12 01 04 00 4.34 97.94 * * Current assumption are: * Location is always specified in North and East coordinates. * Parameters are always Wsm (windspeed) and Wdir (winddirection) specified in this order. * Time notation is always: YYYY MM DD HH MN * * *</pre> */ public class MetOfficeWW3TimeSeriesParser implements TextParser<TimeSeriesContentHandler> { private LineReader reader = null; private TimeSeriesContentHandler contentHandler = null; private final static char COLUMN_SEPARATOR_CHAR = ' '; private final static int PARAM_COLUMN_INDEX = 5; @Override public void parse(LineReader reader, String virtualFileName, TimeSeriesContentHandler contentHandler) throws IOException { this.contentHandler = contentHandler; this.reader = reader; // First line is descriptive. We can skip it. reader.readLine(); //Second line contains the location in lat long notation separated by spaces. String[] locationIdsLine = reader.readLine(COLUMN_SEPARATOR_CHAR); if (locationIdsLine == null || locationIdsLine.length != 5) { throw new IOException("Locations are not specified correctly\n" + reader.getFileAndLineNumber()); } // Location: 52.876 N 0.334 E GeoDatum geoDate = contentHandler.getDefaultGeoDatum(); double y = TextUtils.tryParseDouble(locationIdsLine[1], Double.NaN); if (Double.isNaN(y)) throw new IOException("Number expected for y coordinate;" + locationIdsLine[1]); double x = TextUtils.tryParseDouble(locationIdsLine[3], Double.NaN); if (Double.isNaN(x)) throw new IOException("Number expected for x coordinate;" + locationIdsLine[3]); PointGeometry location = new PointGeometry(geoDate.createXYZ(x, y, 0d)); String[] dateFormatAndParams = reader.readLine(COLUMN_SEPARATOR_CHAR); List<DefaultTimeSeriesHeader> headerList = new ArrayList(); // first 5 entries are date format. The rest are parameters int numberOfParams = dateFormatAndParams.length - PARAM_COLUMN_INDEX; for (int i = 0; i < numberOfParams; i++) { DefaultTimeSeriesHeader header = new DefaultTimeSeriesHeader(); header.setGeometry(location); header.setParameterId(dateFormatAndParams[PARAM_COLUMN_INDEX + i]); contentHandler.createTimeSeriesHeaderAlias(i, header); headerList.add(header); } parseValues(headerList); } private void parseValues(List<DefaultTimeSeriesHeader>headers) throws IOException { char decimalSeparator = '.'; for (String[] buffer = new String[5 + headers.size()]; this.reader.readLine(COLUMN_SEPARATOR_CHAR, buffer) != -1;) { // YYYY MM DD HH MN // 2003 12 01 00 00 4.83 103.17 int paramIndex = 0; for (DefaultTimeSeriesHeader header: headers) { String value = buffer[PARAM_COLUMN_INDEX + paramIndex]; this.contentHandler.setTimeSeriesHeader(header); //noinspection StringConcatenationMissingWhitespace this.contentHandler.setTime(this.contentHandler.getDefaultTimeZone(), "yyyyMMddHHmm", buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]); this.contentHandler.setValue(decimalSeparator, value); this.contentHandler.applyCurrentFields(); paramIndex++; } } } }