Skip to content

Commit a5ead0b

Browse files
authored
Merge pull request #1508 from cbs228/bugfix/legacy-noaa-rap-models
grib: fix NullPointerException for legacy NOAA RAP models
2 parents 3f0b68c + c8020f6 commit a5ead0b

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed

grib/src/main/java/ucar/nc2/grib/grib2/table/Grib2Tables.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,10 @@ private TimeIntervalAndUnits getForecastTimeInterval(Grib2Pds.PdsInterval pdsInt
607607
range += ti.timeIncrement;
608608
}
609609
}
610+
if (timeUnitIntv < 0) {
611+
range = 0;
612+
timeUnitIntv = 1; /* hours */
613+
}
610614
return new TimeIntervalAndUnits(timeUnitIntv, range);
611615
}
612616

376 Bytes
Binary file not shown.
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package ucar.nc2.grib.grib2;
2+
3+
import org.junit.Before;
4+
import org.junit.Test;
5+
import java.io.IOException;
6+
import org.junit.runner.RunWith;
7+
import org.junit.runners.JUnit4;
8+
9+
import ucar.nc2.grib.coord.TimeCoordIntvDateValue;
10+
import ucar.nc2.grib.grib2.table.Grib2Tables;
11+
import static org.junit.Assert.assertEquals;
12+
import static org.junit.Assert.assertTrue;
13+
14+
@RunWith(JUnit4.class)
15+
public class TestPds8 {
16+
@Before
17+
public void openTestFile() throws IOException {
18+
String testfile = "../grib/src/test/data/index/example_pds_8_quirks.grib2.gbx9";
19+
20+
Grib2Index gi = new Grib2Index();
21+
boolean success = gi.readIndex(testfile, -1);
22+
assertTrue(success);
23+
assertEquals(gi.getRecords().size(), 2);
24+
quirky = gi.getRecords().get(0);
25+
normal = gi.getRecords().get(1);
26+
}
27+
28+
@Test
29+
public void testForQuirkyRecord() {
30+
Grib2Pds normal_pds = normal.getPDS();
31+
Grib2Pds quirky_pds = quirky.getPDS();
32+
33+
assertEquals(normal_pds.getRawLength(), 58);
34+
assertEquals(quirky_pds.getRawLength(), 58);
35+
36+
// byte 41 is numberOfTimeRange, which is generally 1 for
37+
// this type of GRIB2 record. For the quirk, it is zero.
38+
assertEquals(normal_pds.getOctet(42), 1);
39+
assertEquals(quirky_pds.getOctet(42), 0);
40+
}
41+
42+
@Test
43+
public void testPds8ReadBasic() {
44+
Grib2Pds pds8 = quirky.getPDS();
45+
assertEquals(pds8.getTemplateNumber(), 8);
46+
assertEquals(pds8.getParameterCategory(), 1);
47+
assertEquals(pds8.getParameterNumber(), 29);
48+
assertEquals(pds8.getGenProcessType(), 2);
49+
assertEquals(pds8.getGenProcessId(), 105);
50+
assertEquals(pds8.getBackProcessId(), 0);
51+
assertEquals(pds8.getTimeUnit(), 1);
52+
assertEquals(pds8.getForecastTime(), 0);
53+
}
54+
55+
@Test
56+
public void testPds8CanGetNormalTime() {
57+
Grib2Tables tbl = Grib2Tables.factory(normal);
58+
TimeCoordIntvDateValue tc = tbl.getForecastTimeInterval(normal);
59+
// start and end times are the same
60+
assertEquals(tc.getStart().getMillis(), tc.getEnd().getMillis());
61+
assertEquals(tc.getStart().getMillis(), 1500508800000L);
62+
}
63+
64+
@Test
65+
public void testPds8CanStillGetQuirkyTime() {
66+
Grib2Tables tbl = Grib2Tables.factory(quirky);
67+
TimeCoordIntvDateValue tc = tbl.getForecastTimeInterval(quirky);
68+
// start and end times are the same
69+
assertEquals(tc.getStart().getMillis(), tc.getEnd().getMillis());
70+
assertEquals(tc.getStart().getMillis(), 1500508800000L);
71+
}
72+
73+
/*
74+
* ====================== SECTION_4 ( length=58, padding=0 ) ======================
75+
* 1-4 section4Length = 58
76+
* 5 numberOfSection = 4
77+
* 6-7 NV = 0
78+
* 8-9 productDefinitionTemplateNumber = 8 [Average, accumulation, extreme values or other statistically processed
79+
* values at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval
80+
* (grib2/tables/2/4.0.table) ]
81+
* 10 parameterCategory = 1 [Moisture (grib2/tables/2/4.1.0.table) ]
82+
* 11 parameterNumber = 8 [Total precipitation (kg m-2) (grib2/tables/2/4.2.0.1.table) ]
83+
* 12 typeOfGeneratingProcess = 2 [Forecast (grib2/tables/2/4.3.table) ]
84+
* 13 backgroundProcess = 0
85+
* 14 generatingProcessIdentifier = 105
86+
* 15-16 hoursAfterDataCutoff = 0
87+
* 17 minutesAfterDataCutoff = 0
88+
* 18 indicatorOfUnitOfTimeRange = 1 [Hour (grib2/tables/2/4.4.table) ]
89+
* 19-22 forecastTime = 0
90+
* 23 typeOfFirstFixedSurface = 1 [Ground or water surface (grib2/tables/2/4.5.table ,
91+
* grib2/tables/local/kwbc/1/4.5.table) ]
92+
* 24 scaleFactorOfFirstFixedSurface = 0
93+
* 25-28 scaledValueOfFirstFixedSurface = 0
94+
* 29 typeOfSecondFixedSurface = 255 [Missing (grib2/tables/2/4.5.table , grib2/tables/local/kwbc/1/4.5.table) ]
95+
* 30 scaleFactorOfSecondFixedSurface = 0
96+
* 31-34 scaledValueOfSecondFixedSurface = 0
97+
* 35-36 yearOfEndOfOverallTimeInterval = 2017
98+
* 37 monthOfEndOfOverallTimeInterval = 7
99+
* 38 dayOfEndOfOverallTimeInterval = 20
100+
* 39 hourOfEndOfOverallTimeInterval = 0
101+
* 40 minuteOfEndOfOverallTimeInterval = 0
102+
* 41 secondOfEndOfOverallTimeInterval = 0
103+
* 42 numberOfTimeRange = 1
104+
* 43-46 numberOfMissingInStatisticalProcess = 0
105+
* 47 typeOfStatisticalProcessing = 1 [Accumulation (grib2/tables/2/4.10.table) ]
106+
* 48 typeOfTimeIncrement = 2 [Successive times processed have same start time of forecast, forecast time is
107+
* incremented (grib2/tables/2/4.11.table) ]
108+
* 49 indicatorOfUnitForTimeRange = 1 [Hour (grib2/tables/2/4.4.table) ]
109+
* 50-53 lengthOfTimeRange = 0
110+
* 54 indicatorOfUnitForTimeIncrement = 255 [Missing (grib2/tables/2/4.4.table) ]
111+
* 55-58 timeIncrement = 0
112+
*/
113+
private Grib2Record quirky;
114+
115+
/*
116+
* ====================== SECTION_4 ( length=58, padding=0 ) ======================
117+
* 1-4 section4Length = 58
118+
* 5 numberOfSection = 4
119+
* 6-7 NV = 0
120+
* 8-9 productDefinitionTemplateNumber = 8 [Average, accumulation, extreme values or other statistically processed
121+
* values at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval
122+
* (grib2/tables/2/4.0.table) ]
123+
* 10 parameterCategory = 1 [Moisture (grib2/tables/2/4.1.0.table) ]
124+
* 11 parameterNumber = 8 [Total precipitation (kg m-2) (grib2/tables/2/4.2.0.1.table) ]
125+
* 12 typeOfGeneratingProcess = 2 [Forecast (grib2/tables/2/4.3.table) ]
126+
* 13 backgroundProcess = 0
127+
* 14 generatingProcessIdentifier = 105
128+
* 15-16 hoursAfterDataCutoff = 0
129+
* 17 minutesAfterDataCutoff = 0
130+
* 18 indicatorOfUnitOfTimeRange = 1 [Hour (grib2/tables/2/4.4.table) ]
131+
* 19-22 forecastTime = 0
132+
* 23 typeOfFirstFixedSurface = 1 [Ground or water surface (grib2/tables/2/4.5.table ,
133+
* grib2/tables/local/kwbc/1/4.5.table) ]
134+
* 24 scaleFactorOfFirstFixedSurface = 0
135+
* 25-28 scaledValueOfFirstFixedSurface = 0
136+
* 29 typeOfSecondFixedSurface = 255 [Missing (grib2/tables/2/4.5.table , grib2/tables/local/kwbc/1/4.5.table) ]
137+
* 30 scaleFactorOfSecondFixedSurface = 0
138+
* 31-34 scaledValueOfSecondFixedSurface = 0
139+
* 35-36 yearOfEndOfOverallTimeInterval = 2017
140+
* 37 monthOfEndOfOverallTimeInterval = 7
141+
* 38 dayOfEndOfOverallTimeInterval = 20
142+
* 39 hourOfEndOfOverallTimeInterval = 0
143+
* 40 minuteOfEndOfOverallTimeInterval = 0
144+
* 41 secondOfEndOfOverallTimeInterval = 0
145+
* 42 numberOfTimeRange = 1
146+
* 43-46 numberOfMissingInStatisticalProcess = 0
147+
* 47 typeOfStatisticalProcessing = 1 [Accumulation (grib2/tables/2/4.10.table) ]
148+
* 48 typeOfTimeIncrement = 2 [Successive times processed have same start time of forecast, forecast time is
149+
* incremented (grib2/tables/2/4.11.table) ]
150+
* 49 indicatorOfUnitForTimeRange = 1 [Hour (grib2/tables/2/4.4.table) ]
151+
* 50-53 lengthOfTimeRange = 0
152+
* 54 indicatorOfUnitForTimeIncrement = 255 [Missing (grib2/tables/2/4.4.table) ]
153+
* 55-58 timeIncrement = 0
154+
*/
155+
private Grib2Record normal;
156+
}
157+
158+
/*
159+
* # steps to reproduce test data
160+
*
161+
* baseurl='www.ncei.noaa.gov/oa/prod-model/rapid-refresh/access/historical/analysis'
162+
* curl -O "https://${baseurl}/201707/20170720/rap_130_20170720_0000_000.grb2"
163+
*
164+
* codes_split_file -1 rap_130_20170720_0000_000.grb2
165+
*
166+
* # quirky
167+
* grib_dump -O -p section_4 \
168+
* -w section4Length=58,numberOfTimeRange=0 \
169+
* rap_130_20170720_0000_000.grb2_199
170+
*
171+
* # normal
172+
* grib_dump -O -p section_4 \
173+
* -w section4Length=58,numberOfTimeRange=1 \
174+
* rap_130_20170720_0000_000.grb2_212
175+
*
176+
* cat \
177+
* rap_130_20170720_0000_000.grb2_199 \
178+
* rap_130_20170720_0000_000.grb2_212 \
179+
* >example_pds_8_quirks.grib2
180+
*
181+
* # index
182+
* java -jar netcdfAll-5.10.0-SNAPSHOT.jar \
183+
* example_pds_8_quirks.grib2
184+
*
185+
* # generates example_pds_8_quirks.grib2.gbx9
186+
*/

0 commit comments

Comments
 (0)