Change nomenclature from 'storm report' to 'storm event'
This commit is contained in:
parent
38911cb694
commit
71d0d49ca7
8 changed files with 89 additions and 89 deletions
|
@ -8,7 +8,7 @@ in conjunction with the
|
|||
[NCEI Storm Events Database](https://www.ncei.noaa.gov/pub/data/swdi/stormevents/csvfiles/)
|
||||
to archive only NEXRAD Level II data for which storms were recorded
|
||||
by the National Weather Service. Using the start and end times and
|
||||
coordinates of a given storm report, this tool is able to query and
|
||||
coordinates of a given storm event, this tool is able to query and
|
||||
filter objects in the
|
||||
[NEXRAD Level II Amazon bucket](https://registry.opendata.aws/noaa-nexrad/),
|
||||
allowing one to only archive volume scans for which storms were noted,
|
||||
|
|
|
@ -4,7 +4,7 @@ import argparse
|
|||
|
||||
from nexrad.db import Database
|
||||
from nexrad.s3 import S3Bucket
|
||||
from nexrad.storm import StormReport
|
||||
from nexrad.storm import StormEvent
|
||||
from nexrad.archive import Archive
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
|
@ -15,11 +15,11 @@ parser.add_argument('--quiet', action='store_true', help='Suppress output')
|
|||
parser.add_argument('--dry-run', action='store_true', help='Do not actually archive data')
|
||||
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument('--exclude', action='append', type=str, help='Exclude types of reports from ingest')
|
||||
group.add_argument('--type', action='append', type=str, help='Specify only given types of reports to ingest')
|
||||
group.add_argument('--exclude', action='append', type=str, help='Exclude types of events from ingest')
|
||||
group.add_argument('--type', action='append', type=str, help='Specify only given types of events to ingest')
|
||||
|
||||
parser.add_argument('db', help='SQLite3 NEXRAD radar site database')
|
||||
parser.add_argument('csv-report-details', nargs='+', help='Compressed storm report details CSV file')
|
||||
parser.add_argument('csv-event-details', nargs='+', help='Compressed storm event details CSV file')
|
||||
parser.add_argument('archive-dir', help='Target archive directory')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
@ -36,32 +36,32 @@ if args.exclude is not None:
|
|||
if args.type is not None:
|
||||
types = {s: True for s in args.type}
|
||||
|
||||
for path in getattr(args, 'csv-report-details'):
|
||||
for report in StormReport.each_from_csv_file(path):
|
||||
if args.exclude is not None and report.event_type in exclude:
|
||||
for path in getattr(args, 'csv-event-details'):
|
||||
for event in StormEvent.each_from_csv_file(path):
|
||||
if args.exclude is not None and event.event_type in exclude:
|
||||
continue
|
||||
|
||||
if args.type is not None and report.event_type not in types:
|
||||
if args.type is not None and event.event_type not in types:
|
||||
continue
|
||||
|
||||
if report.coord_start is None or report.coord_end is None:
|
||||
if event.coord_start is None or event.coord_end is None:
|
||||
continue
|
||||
|
||||
if not report.is_radar_significant():
|
||||
if not event.is_radar_significant():
|
||||
continue
|
||||
|
||||
radars = report.nearby_radars(db)
|
||||
radars = event.nearby_radars(db)
|
||||
|
||||
for key in bucket.each_matching_key(radars, report.timestamp_start, report.timestamp_end):
|
||||
for key in bucket.each_matching_key(radars, event.timestamp_start, event.timestamp_end):
|
||||
if archive.is_downloaded(key):
|
||||
if not args.quiet:
|
||||
print(f"event {report.id} key {key} type {report.event_type} already archived")
|
||||
print(f"event {event.id} key {key} type {event.event_type} already archived")
|
||||
else:
|
||||
if not args.quiet:
|
||||
if args.dry_run:
|
||||
print(f"event {report.id} key {key} type {report.event_type} would archive")
|
||||
print(f"event {event.id} key {key} type {event.event_type} would archive")
|
||||
else:
|
||||
print(f"event {report.id} key {key} type {report.event_type} archiving")
|
||||
print(f"event {event.id} key {key} type {event.event_type} archiving")
|
||||
|
||||
if not args.dry_run:
|
||||
archive.download(key)
|
||||
|
|
33
bin/nexrad-archive-event-ingest
Executable file
33
bin/nexrad-archive-event-ingest
Executable file
|
@ -0,0 +1,33 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
from nexrad.db import Database
|
||||
from nexrad.storm import StormEvent
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Ingest events from StormEvent_details_*.csv.gz files'
|
||||
)
|
||||
|
||||
parser.add_argument('--quiet', action='store_true', help='Suppress output')
|
||||
parser.add_argument('--dry-run', action='store_true', help='Do not actually ingest events')
|
||||
parser.add_argument('db', help='SQLite3 NEXRAD radar site database')
|
||||
parser.add_argument('csv-event-details', nargs='+', help='Compressed storm event details CSV file')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
db = Database.connect(args.db)
|
||||
|
||||
if not args.dry_run:
|
||||
db.execute('begin transaction')
|
||||
|
||||
for path in getattr(args, 'csv-event-details'):
|
||||
for event in StormEvent.each_from_csv_file(path):
|
||||
if not args.dry_run:
|
||||
db.add(event)
|
||||
|
||||
if not args.quiet:
|
||||
print(f"Finished ingesting file {path}")
|
||||
|
||||
if not args.dry_run:
|
||||
db.commit()
|
|
@ -1,33 +0,0 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
from nexrad.db import Database
|
||||
from nexrad.storm import StormReport
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Ingest reports from StormEvent_details_*.csv.gz files'
|
||||
)
|
||||
|
||||
parser.add_argument('--quiet', action='store_true', help='Suppress output')
|
||||
parser.add_argument('--dry-run', action='store_true', help='Do not actually ingest reports')
|
||||
parser.add_argument('db', help='SQLite3 NEXRAD radar site database')
|
||||
parser.add_argument('csv-report-details', nargs='+', help='Compressed storm report details CSV file')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
db = Database.connect(args.db)
|
||||
|
||||
if not args.dry_run:
|
||||
db.execute('begin transaction')
|
||||
|
||||
for path in getattr(args, 'csv-report-details'):
|
||||
for report in StormReport.each_from_csv_file(path):
|
||||
if not args.dry_run:
|
||||
db.add(report)
|
||||
|
||||
if not args.quiet:
|
||||
print(f"Finished ingesting file {path}")
|
||||
|
||||
if not args.dry_run:
|
||||
db.commit()
|
|
@ -16,7 +16,7 @@ select
|
|||
AddGeometryColumn('nexrad_radar', 'coord', 4326, 'POINT', 'XY'),
|
||||
CreateSpatialIndex('nexrad_radar', 'coord');
|
||||
|
||||
create table nexrad_storm_report (
|
||||
create table nexrad_storm_event (
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
episode_id INTEGER,
|
||||
timestamp_start TIMESTAMP NOT NULL,
|
||||
|
@ -29,18 +29,18 @@ create table nexrad_storm_report (
|
|||
tornado_f_rating TEXT
|
||||
);
|
||||
|
||||
create index nexrad_storm_report_episode_id_idx on nexrad_storm_report (episode_id);
|
||||
create index nexrad_storm_report_event_type_idx on nexrad_storm_report (event_type);
|
||||
create index nexrad_storm_report_wfo_idx on nexrad_storm_report (wfo);
|
||||
create index nexrad_storm_report_timestamp_start_idx on nexrad_storm_report (timestamp_start);
|
||||
create index nexrad_storm_report_timestamp_end_idx on nexrad_storm_report (timestamp_end);
|
||||
create index nexrad_storm_event_episode_id_idx on nexrad_storm_event (episode_id);
|
||||
create index nexrad_storm_event_event_type_idx on nexrad_storm_event (event_type);
|
||||
create index nexrad_storm_event_wfo_idx on nexrad_storm_event (wfo);
|
||||
create index nexrad_storm_event_timestamp_start_idx on nexrad_storm_event (timestamp_start);
|
||||
create index nexrad_storm_event_timestamp_end_idx on nexrad_storm_event (timestamp_end);
|
||||
|
||||
select
|
||||
AddGeometryColumn('nexrad_storm_report', 'coord_start', 4326, 'POINT', 'XY', 0),
|
||||
CreateSpatialIndex('nexrad_storm_report', 'coord_start');
|
||||
AddGeometryColumn('nexrad_storm_event', 'coord_start', 4326, 'POINT', 'XY', 0),
|
||||
CreateSpatialIndex('nexrad_storm_event', 'coord_start');
|
||||
|
||||
select
|
||||
AddGeometryColumn('nexrad_storm_report', 'coord_end', 4326, 'POINT', 'XY', 0),
|
||||
CreateSpatialIndex('nexrad_storm_report', 'coord_end');
|
||||
AddGeometryColumn('nexrad_storm_event', 'coord_end', 4326, 'POINT', 'XY', 0),
|
||||
CreateSpatialIndex('nexrad_storm_event', 'coord_end');
|
||||
|
||||
commit;
|
||||
|
|
|
@ -94,15 +94,15 @@ class ArchiveProduct():
|
|||
|
||||
def is_reported(self, db: Database):
|
||||
sql = """select count((
|
||||
select ST_Distance(MakeLine(report.coord_start, report.coord_end),
|
||||
select ST_Distance(MakeLine(event.coord_start, event.coord_end),
|
||||
radar.coord,
|
||||
true) as distance
|
||||
from
|
||||
nexrad_storm_report as report,
|
||||
nexrad_storm_event as event,
|
||||
nexrad_radar as radar
|
||||
where
|
||||
distance <= :radius
|
||||
and :timestamp between report.timestamp_start and report.timestamp_end
|
||||
and :timestamp between event.timestamp_start and event.timestamp_end
|
||||
and radar.call = :call)) as num
|
||||
"""
|
||||
|
||||
|
|
|
@ -80,14 +80,14 @@ def coord_from_str(text_lon: str, text_lat: str):
|
|||
|
||||
return Coord(float(text_lon), float(text_lat))
|
||||
|
||||
class StormReport(DatabaseTable):
|
||||
class StormEvent(DatabaseTable):
|
||||
__slots__ = (
|
||||
'id', 'timestamp_start', 'timestamp_end', 'episode_id',
|
||||
'state', 'event_type', 'wfo', 'locale_start', 'locale_end',
|
||||
'tornado_f_rating', 'coord_start', 'coord_end'
|
||||
)
|
||||
|
||||
__table__ = 'nexrad_storm_report'
|
||||
__table__ = 'nexrad_storm_event'
|
||||
__key__ = 'id'
|
||||
|
||||
__columns__ = (
|
||||
|
@ -133,32 +133,32 @@ class StormReport(DatabaseTable):
|
|||
|
||||
@staticmethod
|
||||
def from_csv_row(row: dict):
|
||||
report = StormReport()
|
||||
event = StormEvent()
|
||||
|
||||
tz = timezone_from_str(row['CZ_TIMEZONE'])
|
||||
|
||||
report.timestamp_start = timestamp_from_parts(tz, row['BEGIN_YEARMONTH'], row['BEGIN_DAY'], row['BEGIN_TIME'])
|
||||
report.timestamp_end = timestamp_from_parts(tz, row['END_YEARMONTH'], row['END_DAY'], row['END_TIME'])
|
||||
report.state = row['STATE']
|
||||
report.event_type = row['EVENT_TYPE']
|
||||
report.wfo = row['WFO']
|
||||
report.locale_start = row['BEGIN_LOCATION']
|
||||
report.locale_end = row['END_LOCATION']
|
||||
report.tornado_f_rating = row['TOR_F_SCALE']
|
||||
report.coord_start = coord_from_str(row['BEGIN_LON'], row['BEGIN_LAT'])
|
||||
report.coord_end = coord_from_str(row['END_LON'], row['END_LAT'])
|
||||
event.timestamp_start = timestamp_from_parts(tz, row['BEGIN_YEARMONTH'], row['BEGIN_DAY'], row['BEGIN_TIME'])
|
||||
event.timestamp_end = timestamp_from_parts(tz, row['END_YEARMONTH'], row['END_DAY'], row['END_TIME'])
|
||||
event.state = row['STATE']
|
||||
event.event_type = row['EVENT_TYPE']
|
||||
event.wfo = row['WFO']
|
||||
event.locale_start = row['BEGIN_LOCATION']
|
||||
event.locale_end = row['END_LOCATION']
|
||||
event.tornado_f_rating = row['TOR_F_SCALE']
|
||||
event.coord_start = coord_from_str(row['BEGIN_LON'], row['BEGIN_LAT'])
|
||||
event.coord_end = coord_from_str(row['END_LON'], row['END_LAT'])
|
||||
|
||||
try:
|
||||
report.episode_id = int(row['EPISODE_ID'])
|
||||
event.episode_id = int(row['EPISODE_ID'])
|
||||
except ValueError:
|
||||
report.episode_id = None
|
||||
event.episode_id = None
|
||||
|
||||
try:
|
||||
report.id = int(row['EVENT_ID'])
|
||||
event.id = int(row['EVENT_ID'])
|
||||
except ValueError:
|
||||
report.id = None
|
||||
event.id = None
|
||||
|
||||
return report
|
||||
return event
|
||||
|
||||
@staticmethod
|
||||
def each_from_csv_file(file: str):
|
||||
|
@ -167,7 +167,7 @@ class StormReport(DatabaseTable):
|
|||
|
||||
for row in reader:
|
||||
try:
|
||||
yield StormReport.from_csv_row(row)
|
||||
yield StormEvent.from_csv_row(row)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -176,7 +176,7 @@ class StormReport(DatabaseTable):
|
|||
coord: Coord=None,
|
||||
radius: float=RADAR_RANGE,
|
||||
timestamp: datetime.datetime=None):
|
||||
columns = StormReport.__format_columns_select__(StormReport)
|
||||
columns = StormEvent.__format_columns_select__(StormEvent)
|
||||
clauses = list()
|
||||
values = dict()
|
||||
|
||||
|
@ -205,12 +205,12 @@ class StormReport(DatabaseTable):
|
|||
'timestamp': str(timestamp)
|
||||
})
|
||||
|
||||
sql = "select " + ", ".join(columns) + " from nexrad_storm_report"
|
||||
sql = "select " + ", ".join(columns) + " from nexrad_storm_event"
|
||||
|
||||
if len(clauses) > 0:
|
||||
sql += " where " + " and ".join(clauses)
|
||||
|
||||
st = db.query_sql(StormReport, sql, values)
|
||||
st = db.query_sql(StormEvent, sql, values)
|
||||
|
||||
while True:
|
||||
obj = st.fetchone()
|
||||
|
|
6
run.sh
6
run.sh
|
@ -1,11 +1,11 @@
|
|||
#! /bin/sh
|
||||
|
||||
reports_csv_gz="$(realpath "$1")"
|
||||
events_csv_gz="$(realpath "$1")"
|
||||
dest="$(realpath "$2")"
|
||||
|
||||
shift 2
|
||||
|
||||
docker run --rm -it \
|
||||
--volume "$reports_csv_gz:/tmp/reports.csv.gz" \
|
||||
--volume "$events_csv_gz:/tmp/events.csv.gz" \
|
||||
--volume "$dest:/dest" \
|
||||
nexrad-archive:latest /tmp/reports.csv.gz /dest "$@"
|
||||
nexrad-archive:latest /tmp/events.csv.gz /dest "$@"
|
||||
|
|
Loading…
Add table
Reference in a new issue