Skip to content

Commit 7f5c4e0

Browse files
authored
Merge pull request #1157 from akrherz/gh1156_spc
✨ Support New SPC CIG[1-3] Thresholds for #1156
2 parents 4ead72e + ea42af7 commit 7f5c4e0

File tree

4 files changed

+141
-13
lines changed

4 files changed

+141
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ All notable changes to this library are documented in this file.
1616
- Added crude bounds checking within `pyiem.observation` to prevent out of
1717
reasonable bounds data from going to the database.
1818
- Increased LSR jabber message generation limit to 20 (#1154).
19+
- Support Storm Prediction Center updated `CIG[1-3]` thresholds (#1156).
1920
- Update CI testing to include python=3.14
2021

2122
### Bug Fixes
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
364
2+
WUUS01 KWNS 141448
3+
PTSDY1
4+
5+
DAY 1 CONVECTIVE OUTLOOK AREAL OUTLINE
6+
NWS STORM PREDICTION CENTER NORMAN OK
7+
0848 AM CDT SAT MAR 15 2025
8+
9+
VALID TIME 141630Z - 151200Z
10+
11+
PROBABILISTIC OUTLOOK POINTS DAY 1
12+
13+
... TORNADO ...
14+
15+
0.02 28639469 29049401 30659379 31819322 33899135 35718973
16+
38088829 41138572 42768421 42878311 39808251 38538136
17+
37288044 34468068 33318102 31958168 28708378
18+
0.05 29079380 30719349 31449307 32749191 35568930 37438790
19+
38098738 38268519 37638366 36548284 35678177 33898186
20+
32788219 31098311 29018447
21+
0.10 29099311 31479208 32299184 33239110 35398904 36228809
22+
36618703 36568480 35828339 34898306 33828293 32108328
23+
30478419 29188520
24+
0.15 29798988 29999091 30139151 30899186 31779173 32349154
25+
32909117 35388819 35768717 35528597 34498470 33358446
26+
32198451 31438483 30498543 30118681 29798988
27+
0.30 32418654 31768781 31208924 31509013 32309031 33009006
28+
34178885 34658781 34468675 33838574 33078578 32418654
29+
CIG1 29238916 29139041 29289157 29519228 29799276 30919234
30+
32299184 33189114 36238809 36638710 36588490 35948348
31+
35668259 35468130 35268086 34978064 34488067 33358103
32+
29778397 29618494 29928677 29238916
33+
CIG2 32939045 34698899 35528712 35498600 34848430 33908374
34+
32768393 31418472 30488971 30559072 30979090 31539088
35+
32939045
36+
CIG3 31569018 32269033 32998999 33608935 33828870 33568796
37+
33168764 32458765 31688819 31218928 31569018
38+
&&
39+
40+
... HAIL ...
41+
42+
0.05 29019401 31009411 32889348 33789294 35229174 37198993
43+
39488770 41368568 41548500 41318423 40798393 39648423
44+
37888376 36958296 36058222 35008196 34048209 33048244
45+
31348303 29478418
46+
0.15 29059379 30729349 31469306 33419131 35518931 36748843
47+
37138793 37158719 36478622 35958534 35268409 34338344
48+
32738351 31278391 29898464 29198519
49+
0.30 35108785 34998673 34138626 32648678 31888755 31188923
50+
30139150 30859187 31619176 32319156 35108785
51+
CIG1 31029232 32269179 33829024 35198848 35398787 35358736
52+
35338682 34918571 34108530 32848554 31898520 30928462
53+
30428473 29738523 29968605 30118776 29558973 29499169
54+
30179255 31029232
55+
&&
56+
57+
... WIND ...
58+
59+
0.05 29029401 30999412 32949345 33809294 38958819 40718718
60+
42358608 43198518 44088394 44098147 42787956 41517890
61+
38757963 35538011 33968065 31808177 28648380
62+
0.15 28829212 29699285 31429213 32379160 35098949 38098734
63+
38908622 38778469 37858274 37028178 35798118 34798136
64+
33388182 31258303 29008447
65+
0.30 33458275 32208310 30528419 29578530 30308666 30218911
66+
30499079 31229152 32279139 34928930 36628647 36588481
67+
35818339 34918304 33458275
68+
0.45 34488468 34388507 34888682 35248726 35748718 36098621
69+
35918499 35368449 34488468
70+
CIG1 36468576 36258430 35808328 35308217 34818135 33378182
71+
31548361 31108406 30538462 29688533 30228628 30988709
72+
31288769 31088904 30959011 30999107 31099138 31279152
73+
32289137 33669033 35058903 36468666 36468576
74+
&&
75+
76+
CATEGORICAL OUTLOOK POINTS DAY 1
77+
78+
... CATEGORICAL ...
79+
80+
HIGH 33009006 34178885 34658781 34468675 33838574 33078578
81+
32418654 31768781 31208924 31509013 32309031 33009006
82+
MDT 31539088 32939045 34698899 35528712 35498600 34498470
83+
33358446 32198451 31388486 30488971 30559072 30979090
84+
31539088
85+
ENH 29508822 29238916 29139041 29289157 29519228 29799276
86+
31479208 32299184 33189114 36228809 36618703 36568486
87+
35828339 34918304 33458275 32208310 31588357 30478419
88+
29628485 29928677
89+
SLGT 29079380 30729349 31469306 35568930 38098738 38908622
90+
38778469 37858274 37028178 35798118 34798136 33388182
91+
31098311 29478417
92+
MRGL 43017990 42787956 41517890 38757963 35538011 33968065
93+
31958168 28888365 99999999 29119402 30999412 32889348
94+
33809294 35229174 39028815 40718718 42358608 43198518
95+
44088394 44098166
96+
TSTM 28089552 30739715 31799693 33319567 35769373 37959023
97+
40348833 42788789 45088805 46808787 47818951 47729178
98+
47099485 47859580 50299450 99999999 49881471 47041110
99+
46121014 42870839 40970645 39660530 38760481 38000478
100+
37080562 36700699 37230836 38721042 40471218 42201323
101+
43571425 44851517 45791598 46491754 46562108 46332314
102+
46412511 99999999 44847676 41857826 38637941 36137899
103+
33367993 30518160 27958338
104+
&&

src/pyiem/nws/products/spcpts.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
)
3535
DMATCH = re.compile(r"D(?P<day1>[0-9])\-?(?P<day2>[0-9])?")
3636
THRESHOLD_ORDER = (
37-
"0.02 0.05 0.10 0.15 0.25 0.30 0.35 0.40 0.45 0.60 TSTM MRGL SLGT ENH "
38-
"MDT HIGH IDRT SDRT ELEV CRIT EXTM"
37+
"0.02 0.05 0.10 0.15 0.25 0.30 0.35 0.40 0.45 0.60 0.75 0.90 "
38+
"CIG1 CIG2 CIG3 TSTM MRGL SLGT ENH MDT HIGH IDRT SDRT ELEV CRIT EXTM"
3939
).split()
4040

4141

@@ -252,21 +252,28 @@ def difference_geometries(self):
252252
for cat in self.get_categories():
253253
outlooks = list(filter(lambda x: x.category == cat, self.outlooks))
254254
for idx in range(0, len(outlooks) - 1):
255-
larger = outlooks[idx]
256-
smaller = outlooks[idx + 1]
255+
this_outlook = outlooks[idx]
256+
next_outlook = outlooks[idx + 1]
257+
# Figure out when the geometry_layers (full polygon) should be
258+
# used.
257259
if (
258-
larger.level is None
259-
or smaller.level is None
260-
or larger.threshold in ["SDRT", "IDRT"] # One Off
260+
this_outlook.level is None
261+
or next_outlook.level is None
262+
or this_outlook.threshold in ["SDRT", "IDRT"]
263+
or next_outlook.threshold == "CIG1"
261264
):
262-
larger.geometry = larger.geometry_layers
265+
this_outlook.geometry = this_outlook.geometry_layers
263266
continue
264-
larger.geometry = larger.geometry_layers.difference(
265-
smaller.geometry_layers
267+
this_outlook.geometry = (
268+
this_outlook.geometry_layers.difference(
269+
next_outlook.geometry_layers
270+
)
266271
)
267272
# Ensure multipolygon
268-
if not isinstance(larger.geometry, MultiPolygon):
269-
larger.geometry = MultiPolygon([larger.geometry])
273+
if not isinstance(this_outlook.geometry, MultiPolygon):
274+
this_outlook.geometry = MultiPolygon(
275+
[this_outlook.geometry]
276+
)
270277
# Last polygon needs duplicated
271278
if outlooks:
272279
outlooks[-1].geometry = outlooks[-1].geometry_layers
@@ -431,7 +438,8 @@ def find_outlooks(self):
431438
re.match(
432439
(
433440
r"^(D[3-8]\-?[3-8]?|EXTM|MRGL|ENH|SLGT|MDT|ELEV|"
434-
r"HIGH|CRIT|TSTM|SIGN|IDRT|SDRT|0\.[0-9][0-9]) "
441+
r"HIGH|CRIT|TSTM|SIGN|CIG[1-3]|"
442+
r"IDRT|SDRT|0\.[0-9][0-9]) "
435443
),
436444
line,
437445
)

tests/nws/products/test_spcpts.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@
1414
from pyiem.util import get_test_file, utc
1515

1616

17+
def test_gh1156_cig():
18+
"""Test the newly minted CIG thresholds."""
19+
prod = parser(
20+
get_test_file("SPCPTS/PTSDY1_gh1156.txt"),
21+
utcnow=utc(2025, 3, 15, 15),
22+
)
23+
assert not prod.warnings
24+
outlook = prod.get_outlook("TORNADO", "CIG1", 1)
25+
assert outlook.geometry_layers.area > outlook.geometry.area
26+
outlook = prod.get_outlook("TORNADO", "CIG2", 1)
27+
assert outlook.geometry_layers.area > outlook.geometry.area
28+
outlook = prod.get_outlook("TORNADO", "CIG3", 1)
29+
assert outlook.geometry_layers.area == outlook.geometry.area
30+
31+
1732
def test_d48_crosses_month():
1833
"""Test that the right month is assigned to this."""
1934
prod = parser(

0 commit comments

Comments
 (0)