Skip to content

Commit 7ff8542

Browse files
authored
Merge pull request #11 from bcdev/TB_Noaa_Buoy
Tb noaa buoy
2 parents 49063ae + bd0c60f commit 7ff8542

32 files changed

+3667
-773
lines changed

cems/src/main/bin/matchup_console.bat

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
3+
. ${PM_EXE_DIR}/${MMS_ENV_NAME}
4+
5+
start_date=$1
6+
end_date=$2
7+
interval=$3
8+
config_dir=$4
9+
use_case_config=$5
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class SerialMatchup:
2+
3+
def run_matchup(self):
4+
print("here we go")
5+
6+
7+
if __name__ == "__main__":
8+
serialRunner = SerialMatchup()
9+
serialRunner.run_matchup()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.bc.fiduceo.reader.insitu.ndbc;
2+
3+
class CwRecord {
4+
5+
int utc;
6+
short windDir;
7+
float windSpeed;
8+
short gustDir;
9+
float gustSpeed;
10+
short gustTime;
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.bc.fiduceo.reader.insitu.ndbc;
2+
3+
enum MeasurementType {
4+
CONSTANT_WIND,
5+
STANDARD_METEOROLOGICAL
6+
}
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package com.bc.fiduceo.reader.insitu.ndbc;
2+
3+
import com.bc.fiduceo.core.Dimension;
4+
import com.bc.fiduceo.core.Interval;
5+
import com.bc.fiduceo.core.NodeType;
6+
import com.bc.fiduceo.geometry.Polygon;
7+
import com.bc.fiduceo.location.PixelLocator;
8+
import com.bc.fiduceo.reader.AcquisitionInfo;
9+
import com.bc.fiduceo.reader.time.TimeLocator;
10+
import com.bc.fiduceo.reader.time.TimeLocator_MillisSince1970;
11+
import com.bc.fiduceo.util.NetCDFUtils;
12+
import com.bc.fiduceo.util.TimeUtils;
13+
import com.bc.fiduceo.util.VariableProxy;
14+
import org.esa.snap.core.util.StringUtils;
15+
import ucar.ma2.Array;
16+
import ucar.ma2.ArrayInt;
17+
import ucar.ma2.DataType;
18+
import ucar.ma2.InvalidRangeException;
19+
import ucar.nc2.Attribute;
20+
import ucar.nc2.Variable;
21+
22+
import java.io.BufferedReader;
23+
import java.io.File;
24+
import java.io.FileReader;
25+
import java.io.IOException;
26+
import java.util.ArrayList;
27+
import java.util.Calendar;
28+
import java.util.Date;
29+
import java.util.List;
30+
31+
import static com.bc.fiduceo.util.NetCDFUtils.*;
32+
33+
class NdbcCWReader extends NdbcReader {
34+
35+
private static final String GTIME = "GTIME";
36+
private static final String REG_EX_CW = "\\w{5}c\\d{4}.txt";
37+
38+
private static final String GDR = "GDR";
39+
40+
private static StationDatabase stationDatabase;
41+
42+
private ArrayList<CwRecord> records;
43+
private TimeLocator timeLocator;
44+
45+
@Override
46+
public void open(File file) throws IOException {
47+
ensureStationDatabase();
48+
loadStation(file, stationDatabase);
49+
parseFile(file);
50+
}
51+
52+
private void parseFile(File file) throws IOException {
53+
records = new ArrayList<>();
54+
try (final FileReader fileReader = new FileReader(file)) {
55+
final Calendar calendar = TimeUtils.getUTCCalendar();
56+
final BufferedReader bufferedReader = new BufferedReader(fileReader);
57+
String line;
58+
while ((line = bufferedReader.readLine()) != null) {
59+
if (line.startsWith("#")) {
60+
// skip comment lines tb 2023-02-27
61+
continue;
62+
}
63+
64+
final CwRecord cwRecord = parseLine(line, calendar);
65+
records.add(cwRecord);
66+
}
67+
}
68+
}
69+
70+
@Override
71+
public void close() throws IOException {
72+
if (records != null) {
73+
records.clear();
74+
records = null;
75+
}
76+
77+
timeLocator = null;
78+
station = null;
79+
}
80+
81+
@Override
82+
public AcquisitionInfo read() throws IOException {
83+
final AcquisitionInfo acquisitionInfo = new AcquisitionInfo();
84+
85+
int minTime = Integer.MAX_VALUE;
86+
int maxTime = Integer.MIN_VALUE;
87+
for (final CwRecord record : records) {
88+
if (record.utc < minTime) {
89+
minTime = record.utc;
90+
}
91+
if (record.utc > maxTime) {
92+
maxTime = record.utc;
93+
}
94+
}
95+
96+
acquisitionInfo.setSensingStart(new Date(minTime * 1000L));
97+
acquisitionInfo.setSensingStop(new Date(maxTime * 1000L));
98+
99+
acquisitionInfo.setNodeType(NodeType.UNDEFINED);
100+
101+
return acquisitionInfo;
102+
}
103+
104+
@Override
105+
public String getRegEx() {
106+
return REG_EX_CW;
107+
}
108+
109+
@Override
110+
public PixelLocator getPixelLocator() throws IOException {
111+
throw new RuntimeException("not implemented"); // intentional tb 2023-02-27
112+
}
113+
114+
@Override
115+
public PixelLocator getSubScenePixelLocator(Polygon sceneGeometry) throws IOException {
116+
throw new RuntimeException("not implemented"); // intentional tb 2023-02-27
117+
}
118+
119+
@Override
120+
public TimeLocator getTimeLocator() throws IOException {
121+
if (timeLocator == null) {
122+
createTimeLocator();
123+
}
124+
125+
return timeLocator;
126+
}
127+
128+
private void createTimeLocator() {
129+
long[] timeArray = new long[records.size()];
130+
131+
int i = 0;
132+
for (final CwRecord record : records) {
133+
timeArray[i] = record.utc * 1000L;
134+
i++;
135+
}
136+
137+
timeLocator = new TimeLocator_MillisSince1970(timeArray);
138+
}
139+
140+
@Override
141+
public Array readRaw(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
142+
final CwRecord record = records.get(centerY);
143+
144+
switch (variableName) {
145+
case STATION_ID:
146+
final Array resultArray = Array.factory(DataType.STRING, new int[]{1, 1});
147+
resultArray.setObject(0, station.getId());
148+
return resultArray;
149+
case STATION_TYPE:
150+
final StationType type = station.getType();
151+
return createResultArray(toByte(type), -1, DataType.BYTE, interval);
152+
case MEASUREMENT_TYPE:
153+
final MeasurementType measurementType = station.getMeasurementType();
154+
return createResultArray(toByte(measurementType), -1, DataType.BYTE, interval);
155+
case LONGITUDE:
156+
return createResultArray(station.getLon(), Float.NaN, DataType.FLOAT, interval);
157+
case LATITUDE:
158+
return createResultArray(station.getLat(), Float.NaN, DataType.FLOAT, interval);
159+
case ANEMOMETER_HEIGHT:
160+
return createResultArray(station.getAnemometerHeight(), Float.NaN, DataType.FLOAT, interval);
161+
case TIME:
162+
return createResultArray(record.utc, NetCDFUtils.getDefaultFillValue(int.class), DataType.INT, interval);
163+
case WDIR:
164+
return createResultArray(record.windDir, 999, DataType.SHORT, interval);
165+
case WSPD:
166+
return createResultArray(record.windSpeed, 99.f, DataType.FLOAT, interval);
167+
case GST:
168+
return createResultArray(record.gustSpeed, 99.f, DataType.FLOAT, interval);
169+
case GDR:
170+
return createResultArray(record.gustDir, 999, DataType.SHORT, interval);
171+
case GTIME:
172+
return createResultArray(record.gustTime, 9999, DataType.SHORT, interval);
173+
}
174+
175+
return null;
176+
}
177+
178+
@Override
179+
public Array readScaled(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
180+
return readRaw(centerX, centerY, interval, variableName); // nothing to scale here tb 2023-02-28
181+
}
182+
183+
@Override
184+
public ArrayInt.D2 readAcquisitionTime(int x, int y, Interval interval) throws IOException, InvalidRangeException {
185+
final Array timeArray = readRaw(x, y, interval, TIME);
186+
187+
return (ArrayInt.D2) timeArray;
188+
}
189+
190+
@Override
191+
public List<Variable> getVariables() throws InvalidRangeException, IOException {
192+
final ArrayList<Variable> variables = new ArrayList<>();
193+
194+
List<Attribute> attributes = new ArrayList<>();
195+
196+
createBasicStationVariables(variables, attributes);
197+
198+
// measurement record variables ----------------------------------
199+
createMeasurementTimeVariable(variables);
200+
createWindDirectionVariable(variables);
201+
createWindSpeedVariable(variables);
202+
203+
attributes = new ArrayList<>();
204+
attributes.add(new Attribute(CF_UNITS_NAME, "degT"));
205+
attributes.add(new Attribute(CF_FILL_VALUE_NAME, 999));
206+
attributes.add(new Attribute(CF_STANDARD_NAME, "wind_gust_from_direction"));
207+
attributes.add(new Attribute(CF_LONG_NAME, "Direction, in degrees clockwise from true North, of the GST, reported at the last hourly 10-minute segment."));
208+
variables.add(new VariableProxy(GDR, DataType.SHORT, attributes));
209+
210+
createGustSpeedVariable(variables, "Maximum 5-second peak gust during the measurement hour, reported at the last hourly 10-minute segment.");
211+
212+
attributes = new ArrayList<>();
213+
attributes.add(new Attribute(CF_UNITS_NAME, "hhmm"));
214+
attributes.add(new Attribute(CF_FILL_VALUE_NAME, 9999));
215+
attributes.add(new Attribute(CF_LONG_NAME, "The minute of the hour that the GSP occurred, reported at the last hourly 10-minute segment."));
216+
variables.add(new VariableProxy(GTIME, DataType.SHORT, attributes));
217+
218+
return variables;
219+
}
220+
221+
@Override
222+
public Dimension getProductSize() throws IOException {
223+
return new Dimension("product_size", 1, records.size());
224+
}
225+
226+
private void ensureStationDatabase() throws IOException {
227+
if (stationDatabase == null) {
228+
stationDatabase = parseStationDatabase("buoy_locations_cw.txt");
229+
}
230+
}
231+
232+
CwRecord parseLine(String line, Calendar calendar) {
233+
final CwRecord cwRecord = new CwRecord();
234+
235+
line = line.replaceAll(" +", " "); // some fields are separated by two or more blanks (sigh) tb 2023-02-27
236+
final String[] tokens = StringUtils.split(line, new char[]{' '}, true);
237+
238+
calendar.setTimeInMillis(0);
239+
calendar.set(Calendar.YEAR, Integer.parseInt(tokens[0]));
240+
calendar.set(Calendar.MONTH, Integer.parseInt(tokens[1]) - 1); // calendar wants month zero-based tb 2023-02-27
241+
calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(tokens[2]));
242+
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(tokens[3]));
243+
calendar.set(Calendar.MINUTE, Integer.parseInt(tokens[4]));
244+
cwRecord.utc = (int) (calendar.getTimeInMillis() * 0.001);
245+
246+
cwRecord.windDir = Short.parseShort(tokens[5]);
247+
cwRecord.windSpeed = Float.parseFloat(tokens[6]);
248+
cwRecord.gustDir = Short.parseShort(tokens[7]);
249+
cwRecord.gustSpeed = Float.parseFloat(tokens[8]);
250+
cwRecord.gustTime = Short.parseShort(tokens[9]);
251+
252+
return cwRecord;
253+
}
254+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.bc.fiduceo.reader.insitu.ndbc;
2+
3+
import com.bc.fiduceo.reader.DataType;
4+
import com.bc.fiduceo.reader.Reader;
5+
import com.bc.fiduceo.reader.ReaderContext;
6+
import com.bc.fiduceo.reader.ReaderPlugin;
7+
8+
public class NdbcCWReaderPlugin implements ReaderPlugin {
9+
10+
private final String[] SUPPORTED_KEYS = {"ndbc-cw-ob", "ndbc-cw-cb", "ndbc-cw-lb", "ndbc-cw-os", "ndbc-cw-cs", "ndbc-cw-ls"};
11+
12+
@Override
13+
public Reader createReader(ReaderContext readerContext) {
14+
return new NdbcCWReader();
15+
}
16+
17+
@Override
18+
public String[] getSupportedSensorKeys() {
19+
return SUPPORTED_KEYS;
20+
}
21+
22+
@Override
23+
public DataType getDataType() {
24+
return DataType.INSITU;
25+
}
26+
}

0 commit comments

Comments
 (0)