Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Earthquake data analysis, seismogram processing, and seismic research
.claude/skills/brycewang-stanford-seismology-data-guide/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 46% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 66% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 462% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 15% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 63% | 0% |
A skill for processing seismic data, analyzing earthquake catalogs, and working with seismograms using standard tools in observational seismology. Covers data retrieval from global networks, waveform processing with ObsPy, magnitude estimation, focal mechanism analysis, and seismic hazard assessment.
| Data Center | Abbreviation | Coverage | Access | |-------------|-------------|----------|--------| | IRIS Data Management Center | IRIS DMC | Global broadband | FDSN Web Services | | European Integrated Data Archive | EIDA | European networks | FDSN Web Services | | USGS Earthquake Hazards Program | USGS EHP | Global catalog | API + ComCat | | International Seismological Centre | ISC | Global bulletin | ISC web services | | NIED F-net | F-net | Japan broadband | NIED website |
pythonfrom obspy.clients.fdsn import Client from obspy import UTCDateTime client = Client("IRIS") # Fetch earthquake catalog for a region and time window catalog = client.get_events( starttime=UTCDateTime("2024-01-01"), endtime=UTCDateTime("2024-12-31"), minmagnitude=5.0, maxmagnitude=9.0, minlatitude=30.0, maxlatitude=45.0, minlongitude=125.0, maxlongitude=150.0, orderby="magnitude", ) print(f"Found {len(catalog)} events") for event in catalog[:5]: origin = event.preferred_origin() mag = event.preferred_magnitude() print(f" M{mag.mag:.1f} {origin.time} " f"({origin.latitude:.2f}, {origin.longitude:.2f}) " f"depth={origin.depth/1000:.1f} km")
pythonfrom obspy import UTCDateTime from obspy.clients.fdsn import Client client = Client("IRIS") # Download waveform data for a specific event t = UTCDateTime("2024-01-01T07:10:00") st = client.get_waveforms( network="IU", station="ANMO", location="00", channel="BHZ", starttime=t, endtime=t + 600, # 10 minutes of data ) # Standard preprocessing pipeline st.detrend("demean") # Remove mean st.detrend("linear") # Remove linear trend st.taper(max_percentage=0.05, type="cosine") # Taper edges st.filter("bandpass", freqmin=0.01, freqmax=5.0, corners=4) # Remove instrument response to get ground velocity (m/s) inv = client.get_stations( network="IU", station="ANMO", location="00", channel="BHZ", starttime=t, endtime=t + 600, level="response", ) st.remove_response(inventory=inv, output="VEL", pre_filt=[0.005, 0.01, 8, 10])
pythonimport numpy as np from scipy.signal import welch def compute_psd(trace, nperseg=256): """ Compute power spectral density of a seismic trace. Returns frequencies (Hz) and PSD (dB relative to 1 (m/s)^2/Hz). """ freqs, psd = welch( trace.data, fs=trace.stats.sampling_rate, nperseg=nperseg, noverlap=nperseg // 2, ) psd_db = 10 * np.log10(psd + 1e-30) return freqs, psd_db
pythonfrom obspy.signal.trigger import recursive_sta_lta, trigger_onset def pick_arrivals(trace, sta_seconds=1.0, lta_seconds=30.0, threshold_on=3.5, threshold_off=1.0): """ STA/LTA trigger for P-wave arrival detection. sta_seconds: short-term average window lta_seconds: long-term average window Returns list of (on_sample, off_sample) trigger windows. """ df = trace.stats.sampling_rate cft = recursive_sta_lta( trace.data, int(sta_seconds * df), int(lta_seconds * df), ) triggers = trigger_onset(cft, threshold_on, threshold_off) return triggers, cft
Determining earthquake hypocenter from arrival times:
python# Simplified grid search earthquake location def grid_search_locate(stations, arrival_times, velocity_model, lat_range, lon_range, depth_range, grid_spacing): """ Brute-force grid search for earthquake location. Minimizes sum of squared travel-time residuals. """ best_misfit = float("inf") best_location = None for lat in np.arange(*lat_range, grid_spacing): for lon in np.arange(*lon_range, grid_spacing): for depth in np.arange(*depth_range, grid_spacing): residuals = [] for sta, obs_time in zip(stations, arrival_times): dist = geodetic_distance(lat, lon, sta.lat, sta.lon) pred_time = velocity_model.get_travel_time(dist, depth) residuals.append((obs_time - pred_time) ** 2) misfit = sum(residuals) if misfit < best_misfit: best_misfit = misfit best_location = (lat, lon, depth) return best_location, best_misfit
| Scale | Symbol | Measurement | Range | |-------|--------|------------|-------| | Local (Richter) | ML | Max amplitude on Wood-Anderson | < 6.5 | | Body wave | mb | P-wave amplitude at 1 Hz | 4-7 | | Surface wave | Ms | Rayleigh wave at 20s period | 5-8.5 | | Moment | Mw | Seismic moment from waveform | All sizes |
Moment magnitude is the standard for modern seismology:
pythondef moment_magnitude(seismic_moment_nm: float) -> float: """ Compute moment magnitude from seismic moment (in Newton-meters). Mw = (2/3) * log10(M0) - 6.07 (Hanks and Kanamori, 1979) """ return (2.0 / 3.0) * np.log10(seismic_moment_nm) - 6.07
Beach ball diagrams represent earthquake source geometry. The fault plane solution requires at least 8-10 well-distributed first-motion polarities (up/down) or full waveform moment tensor inversion.
Tools for focal mechanism determination:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 12,322 | 12,131 | -2% | 1 | 1 | 0% | 2,345 | 3,827 | +63% | 0 | 0 | — |
case-02 | pass→pass | 5,512 | 3,790 | -31% | 1 | 1 | 0% | 840 | 2,602 | +210% | 0 | 0 | — |
case-03 | pass→pass | 9,613 | 7,714 | -20% | 1 | 1 | 0% | 1,593 | 3,318 | +108% | 0 | 0 | — |
case-04 | fail→pass | 24,738 | 6,212 | -75% | 1 | 1 | 0% | 2,166 | 3,161 | +46% | 0 | 0 | — |
case-05 | pass→pass | 6,516 | 4,235 | -35% | 1 | 1 | 0% | 1,074 | 2,603 | +142% | 0 | 0 | — |
case-06 | pass→pass | 5,091 | 3,001 | -41% | 1 | 1 | 0% | 654 | 2,435 | +272% | 0 | 0 | — |
case-07 | fail→fail | 18,194 | 19,446 | +7% | 1 | 1 | 0% | 3,352 | 4,949 | +48% | 0 | 0 | — |
case-08 | fail→pass | 10,493 | 6,537 | -38% | 1 | 1 | 0% | 1,893 | 3,144 | +66% | 0 | 0 | — |
case-09 | pass→pass | 13,130 | 9,417 | -28% | 1 | 1 | 0% | 2,393 | 3,531 | +48% | 0 | 0 | — |
case-10 | fail→fail | 11,995 | 10,627 | -11% | 1 | 1 | 0% | 2,187 | 3,829 | +75% | 0 | 0 | — |
case-11 | pass→pass | 10,210 | 8,014 | -22% | 1 | 1 | 0% | 1,763 | 3,453 | +96% | 0 | 0 | — |
case-12 | pass→pass | 6,980 | 6,567 | -6% | 1 | 1 | 0% | 984 | 2,902 | +195% | 0 | 0 | — |
case-13 | pass→pass | 2,844 | 4,396 | +55% | 1 | 1 | 0% | 430 | 2,590 | +502% | 0 | 0 | — |
case-14 | fail→pass | 2,574 | 1,827 | -29% | 1 | 1 | 0% | 397 | 2,231 | +462% | 0 | 0 | — |
case-15 | pass→pass | 5,628 | 1,980 | -65% | 1 | 1 | 0% | 844 | 2,237 | +165% | 0 | 0 | — |
case-16 | pass→pass | 16,777 | 6,256 | -63% | 1 | 1 | 0% | 3,385 | 3,095 | -9% | 0 | 0 | — |
case-17 | fail→pass | 13,480 | 1,790 | -87% | 1 | 1 | 0% | 1,945 | 2,240 | +15% | 0 | 0 | — |
case-18 | pass→pass | 11,641 | 3,380 | -71% | 1 | 1 | 0% | 1,631 | 2,406 | +48% | 0 | 0 | — |
case-19 | pass→pass | 7,243 | 4,486 | -38% | 1 | 1 | 0% | 978 | 2,520 | +158% | 0 | 0 | — |
case-20 | pass→pass | 8,167 | 4,514 | -45% | 1 | 1 | 0% | 1,312 | 2,576 | +96% | 0 | 0 | — |
case-21 | pass→pass | 16,923 | 13,937 | -18% | 1 | 1 | 0% | 2,564 | 4,019 | +57% | 0 | 0 | — |
case-22 | fail→fail | 15,082 | 27,823 | +84% | 1 | 1 | 0% | 3,136 | 7,743 | +147% | 0 | 0 | — |
case-23 | fail→fail | 33,409 | 44,084 | +32% | 1 | 1 | 0% | 5,641 | 10,182 | +80% | 0 | 0 | — |
case-24 | fail→fail | 22,087 | 29,400 | +33% | 1 | 1 | 0% | 3,712 | 6,781 | +83% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +17 percentage points is the difference between those two pass rates over the 24 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.