Automated earthquake monitoring, processing, and alerting system for the Oklahoma Geological Survey (OGS). This system processes seismic events from SeisComp3 in real-time, catalogs them, generates alerts, and distributes data via multiple channels including Twitter, Bluesky, SMS, Slack, and the USGS Product Distribution Layer (PDL).
Production Deployment Structure:
~/test/ # Python scripts
~/bin/ # Shell scripts & utilities
~/seiscomp3/ # SeisComp3 installation
System Launch (via crontab):
# Start main listener at system boot
@reboot cd /home/sysop/test; python seiscomp_processing.py &
# Monitor and restart processes every 2 minutes
*/2 * * * * /usr/bin/bash /home/sysop/bin/cron_restart_listen.bash >/dev/null 2>&1
*/2 * * * * /usr/bin/bash /home/sysop/bin/cron_restart_twitter.bash >/dev/null 2>&1
*/2 * * * * /usr/bin/bash /home/sysop/bin/cron_restart_pdl_listen.bash >/dev/null 2>&1SeisComp3 Event Queue (MySQL)
↓
seiscomp_processing.py (main listener)
↓
event_processor.py (validation & filtering)
↓
update.sh (format conversion)
↓
┌─────┬──────┬──────────┐
↓ ↓ ↓ ↓
PDL Twitter Slack Database
(via triggerpdl.py) (via changes.py) (direct insert)
The heart of the system - listens for all seismic events
- Connects to SeisComp3
- Subscribes to EVENT message group from SeisComp3
- When new/updated event received:
- Creates directory structure:
/home/sysop/test/xml/YYYY/MM/ - Executes
scxmldumpto extract event XML from MySQL - Passes XML to
event_processor.pyfor validation - 20-second delay allows magnitude updates before processing
- Creates directory structure:
- Restart: Every 2 minutes via
cron_restart_listen.bash - Log file:
seiscomp_test.log(rotates at 5MB, 14 backups) - Process: Runs as single Python process, one event at a time
Filters events and determines if they should be cataloged
Cataloging Decision Logic:
IF analyst classified event (earthquake, quarry blast, or outside interest):
→ CATALOG (Reviewed status)
ELSE IF all criteria met:
→ Magnitude ≥1.5
→ Associated phases ≥10
→ Mismatch score ≤0.81
→ Depth ≤40km (40,000m)
→ CATALOG (Preliminary status)
ELSE:
→ SKIP
Actions on Valid Event:
- Insert into PostgreSQL database
earthquake_quake.quakestable - Geolocation lookup using reverse geocoder (lat/lon → county/state)
- Geographic filtering:
- Multiple quarry zones defined (OK panhandle, Poteau, Ardmore areas)
- Uses matplotlib polygon point-in-polygon test
- Quarry blasts classified vs. natural earthquakes
- SMS alerts for M>4.0 events (via Twilio)
- Slack notifications with event details
- Calls
update.shto format and distribute
Database Insertion (if valid):
event_id: SeisComp3 event ID- Origin time, latitude, longitude, depth
- Magnitude & type, source (OGS/USGS)
- County/state from reverse geocoding
- Error estimates for all parameters
- PostGIS geometry point
Special Handling:
- USGS magnitude comments parsed and prioritized
- High-magnitude events (>4.0) receive special alerts
- Non-existing events deleted from database
- Event updates replace previous entries
Converts SeisComp XML to ANSS QuakeML and distributes
Called by event_processor.py for each valid event:
- Extract:
scxmldumpqueries SeisComp3 MySQL with event ID - Transform: XSLT conversion SeisComp→QuakeML (0.11→1.2)
- Precision:
roundhundredths.pystandardizes decimal places - Distribute:
- Writes:
/home/sysop/output/{EVENT_ID}_update.xml - Copies:
/home/sysop/outgoing_quakeml/{EVENT_ID}_update.xml
- Writes:
- Creates: Timestamps and metadata in QuakeML headers
These processes independently monitor directories and handle distribution:
Monitors and posts earthquake alerts to Twitter/Bluesky
- Watches:
/home/sysop/textfiles/directory - Operation:
- Runs continuously, checks every 240 seconds
- Detects new/updated event text files
- For M>4.0 events:
- Waits 90 seconds between checks (up to 3× for magnitude updates)
- Extracts current magnitude from event XML
- Posts to Twitter via
twitter_update_tweepy.py - Posts to Bluesky via
bluesky_post.py
- Tracks processed events in
change.pkl
- Startup: Via
start_changes.bash - Monitoring:
cron_restart_twitter.bash(every 2 min) - Dependencies: tweepy, atproto
Monitors and sends QuakeML to USGS Product Distribution Layer
- Watches:
/home/sysop/outgoing_quakeml/directory - Operation:
- Runs continuously, checks every 10 seconds
- On event first detection:
- SCPs to PDL:
sysop@10.27.192.63:/home/sysop/pdl/quakeml/ - Marks in
triggerpdl.pklhistory
- SCPs to PDL:
- On updates (file >120s old):
- SCPs updated file to PDL
- Deletes local copy after successful send
- Uses pickle file to track all historical events (no re-sends)
- Startup: Via
start_pdl_listen.bash - Monitoring:
cron_restart_pdl_listen.bash(every 2 min) - File age calculation: Checks modification time in seconds
twitter_update_tweepy.py: Posts messages to Twitter using Tweepy OAuthbluesky_post.py: Posts to Bluesky social network using atproto
manual_magnitude.py: Updates magnitude values in existing QuakeML filesroundhundredths.py: Standardizes decimal precision in QuakeML XMLdelete.sh: Database cleanup utilities
grab_restapi.py: Fetches earthquake data from OGS REST API, downloads shapefiles (1-day, 7-day, 30-day)grab_restapi_complete.py: Complete API grabber with more parametersrequest_capstool.py: Request CAPS tool earthquake data
heliplots.py: Generates focal mechanism (beach ball) plots for earthquakes- Uses ObsPy to fetch waveform data from FDSN servers
- Reads picks and polarities from event XML
- Generates focal sphere radiation pattern plots (currently set for Oklahoma network)
heliplots_shakes.py: Variant with shake map integration
ogs_logger.py: Logging utility (rotating file handler, 5MB max, 14 backups)cron_cleantimetable.bash: Kills orphanedload_timetableprocesses
Each listener has a corresponding start script that:
-
Sets SeisComp3 environment variables
-
Sets Python path to include SeisComp3 libraries
-
Redirects output to log file
-
Runs process in background
-
start_listen.bash: Startsseiscomp_processing.py→listen.log -
start_changes.bash: Startschanges.py→twitter_changes.log -
start_pdl_listen.bash: Startstriggerpdl.py→listen_pdl_trigger.log
All processes monitored via grep and restarted if dead:
cron_restart_listen.bash: Checksseiscomp_processing.py, restarts viastart_listen.bashcron_restart_twitter.bash: Checkschanges.py, restarts viastart_changes.bashcron_restart_pdl_listen.bash: Checkstriggerpdl.py, restarts viastart_pdl_listen.bash
Each runs every 2 minutes via crontab for high availability.
- SeisComp3 (3.x) with MySQL database backend
- PostgreSQL with PostGIS extension (earthquake catalog)
- MySQL (SeisComp3 data storage)
obspy # Earthquake data processing
psycopg2 # PostgreSQL connection
twilio # SMS alerts
reverse-geocoder # Location name lookup (lat/lon → county/state)
matplotlib # Geographic polygon operations
tweepy # Twitter API
atproto # Bluesky API
numpy # Numerical operations (heliplots)
pytz # Timezone handling
- Twilio: SMS alerts (Account SID & Auth Token required)
- Twitter: OAuth credentials (Consumer Key/Secret, Access Key/Secret)
- Bluesky: Account & password
- USGS PDL: SCP access to PDL server
- FDSN Servers: Waveform data for heliplots (IRIS, etc.)
- SeisComp3 messaging (CORBA, TCP 18002)
- MySQL access (localhost:3306)
- PostgreSQL access (remote: sdeprod.ogs.nor.ou.edu)
- SSH/SCP to PDL server (10.27.192.63)
- Internet access for API calls and external distribution
/home/sysop/
├── seiscomp3/ # SeisComp3 installation
├── test/ # Python scripts location
│ ├── seiscomp_processing.py
│ ├── event_processor.py
│ ├── ogs_logger.py
│ └── xml/ # Staged XML (YYYY/MM structure)
├── bin/ # Shell scripts location
│ ├── start_*.bash
│ ├── cron_restart_*.bash
│ ├── update.sh
│ └── xsl/ # XSLT transforms for QuakeML conversion
├── output/ # Converted QuakeML files (temporary)
├── outgoing_quakeml/ # Distribution queue for PDL
├── textfiles/ # Alert text files (monitored by changes.py)
├── highmag/ # High-magnitude alerts (M>4.0)
└── pdl/ # Local PDL mirror (if applicable)
1. SeisComp3 detects M3.5 event (auto-located)
2. seiscomp_processing.py receives message
- Dumps: /home/sysop/test/xml/2025/10/ogs2025abcd.xml
- Waits: 20 seconds for updates
- Calls: event_processor.py
3. event_processor.py validates
- Mag: 3.5 ✓ (≥1.5)
- Phases: 12 ✓ (≥10)
- Mismatch: 0.45 ✓ (≤0.81)
- Depth: 8km ✓ (≤40km)
- Status: Preliminary (automated)
- Inserts into DB
- Calls: update.sh ogs2025abcd
4. update.sh creates QuakeML
- Writes: /home/sysop/output/ogs2025abcd_update.xml
- Copies: /home/sysop/outgoing_quakeml/ogs2025abcd_update.xml
5. changes.py (if magnitude noted)
- Creates: /home/sysop/textfiles/ogs2025abcd.txt
- Posts to Twitter/Bluesky (M>4.0 only)
6. triggerpdl.py
- Detects new file
- SCPs to PDL server
- Deletes local copy
1. M4.2 event detected and located automatically
2. Analyst classifies as "earthquake" in SeisComp3
3. seiscomp_processing.py detects update
4. event_processor.py validates
- Event type: earthquake ✓
- Status: Reviewed
- High-mag alert: "WARNING! M4 UTC: ..."
- SMS sent to configured numbers
- Slack notification
5-6. Same QuakeML conversion and distribution
-- Main earthquake catalog
CREATE TABLE earthquake_quake.quakes (
event_id VARCHAR PRIMARY KEY,
origintime TIMESTAMP,
latitude FLOAT,
longitude FLOAT,
depth FLOAT,
err_lon FLOAT,
err_lat FLOAT,
err_depth FLOAT,
err_origintime FLOAT,
county VARCHAR,
state VARCHAR,
prefmag FLOAT,
pmag_type VARCHAR,
pmag_src VARCHAR, -- 'OGS' or 'USGS'
status VARCHAR, -- 'Preliminary' or 'Reviewed'
reafile TEXT, -- Path to XML
shape GEOMETRY -- PostGIS point
);ps aux | grep seiscomp_processing.py
ps aux | grep changes.py
ps aux | grep triggerpdl.pytail -f /home/sysop/test/seiscomp_test.log # Main listener
tail -f /home/sysop/test/listen.log # Details
tail -f /home/sysop/test/twitter_changes.log # Social media
tail -f /home/sysop/test/listen_pdl_trigger.log # PDL distribution- Process dies: Check logs, restart via
cron_restart_*.bash - No database inserts: Verify PostgreSQL connection, check credentials
- Alerts not posting: Check Twitter/Bluesky/Twilio credentials and API quotas
- PDL not receiving: Verify SSH/SCP access to PDL server
- All times stored in UTC; local time conversion happens during alert generation
- Quarry blast filtering uses geographic polygon zones (hardcoded for Oklahoma)
- High-magnitude events (>4.0) trigger additional verification delays
- Process monitoring ensures 24/7 uptime (restart every 2 minutes if down)
- XML files retained in timestamped directory for archival/debugging
- USGS magnitude comments parsed to override local magnitude when available
- Original: Bill Greenwood (SeisComp3 integration)
- Modifications: Jake Walter (alert integration, database work)
- Current: Oklahoma Geological Survey