FAILURE MAP
← Case archive

FA-71651 / Seismic magnitude estimation / Open access

GNSS peak ground displacement magnitude: hypocentral distance · case 01

Nearby stations of deep events give inflated magnitudes.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Epicentral distance is used instead of hypocentral.

THE FAILURE

Epicentral distance is used instead of hypocentral.

Unsuccessful approach: Adding depth linearly overstates R.

Case contract

obs are [PGD in m, epicentral km]. Per station PGD in cm, R = hypocentral distance; skip PGD < 2 cm or R > 1000 km. log10(PGD) = A + B M + C M log10 R with A=-4.434, B=1.047, C=-0.138, solved for M. Return [mean M rounded 0.01, stations used] or None.

Why this case matters

GNSS PGD magnitudes do not saturate for great earthquakes in early warning.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(obs, depth_km):
    A, B, C = -4.434, 1.047, -0.138
    ms = []
    for pgd_m, epi in obs:
        pgd_cm = pgd_m * 100.0
        r = epi
        if pgd_cm < 2.0 or r > 1000:
            continue
        ms.append((math.log10(pgd_cm) - A) / (B + C * math.log10(r)))
    if not ms:
        return None
    return [round(sum(ms) / len(ms), 2), len(ms)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['GNSS set 0', [[[0.005, 700], [0.05, 1100], [0.02, 995], [0.02, 700]], 25], [7.36, 2]], ['GNSS set 1', [[[0.005, 200], [0.005, 10], [1.2, 995], [0.005, 995], [0.02, 995]], 10], [8.88, 2]], ['GNSS set 2', [[[1.2, 200]], 10], [8.93, 1]], ['GNSS set 3', [[[1.2, 1100]], 10], None], ['GNSS set 4', [[[0.005, 995], [0.02, 200], [0.005, 1100], [1.2, 995], [1.2, 60]], 10], [8.3, 3]], ['GNSS set 5', [[[0.005, 10], [0.3, 60], [0.3, 1100], [0.3, 10]], 60], [7.48, 2]], ['GNSS set 6', [[[0.3, 10], [0.005, 200], [1.2, 1100], [0.005, 1100], [0.02, 60]], 60], [6.72, 2]], ['GNSS set 7', [[[0.005, 700], [1.2, 1100]], 25], None]], [['GNSS set 7', [[[0.005, 700], [1.2, 1100]], 25], None], ['GNSS set 8', [[[1.2, 700], [0.005, 10]], 10], [9.95, 1]], ['GNSS set 9', [[[1.2, 60], [0.3, 10], [0.05, 60]], 25], [7.19, 3]], ['GNSS set 10', [[[0.3, 700], [0.02, 1100]], 60], [9.04, 1]], ['GNSS set 11', [[[1.2, 1100], [0.02, 200], [0.02, 200], [0.005, 1100], [0.05, 10]], 25], [6.34, 3]], ['GNSS set 12', [[[0.3, 200]], 25], [8.11, 1]], ['GNSS set 13', [[[0.005, 700], [0.05, 700], [1.2, 995], [0.3, 700]], 25], [9.05, 3]], ['GNSS set 14', [[[1.2, 700], [0.02, 200], [0.02, 700]], 10], [7.89, 3]]], [['GNSS set 13', [[[0.005, 700], [0.05, 700], [1.2, 995], [0.3, 700]], 25], [9.05, 3]], ['GNSS set 14', [[[1.2, 700], [0.02, 200], [0.02, 700]], 10], [7.89, 3]], ['GNSS set 15', [[[0.005, 60]], 10], None], ['GNSS set 16', [[[1.2, 200], [0.005, 200], [0.02, 10], [0.3, 700]], 25], [7.85, 3]], ['GNSS set 17', [[[0.3, 200], [0.05, 995]], 60], [8.12, 2]], ['GNSS set 18', [[[0.02, 10], [0.3, 1100], [1.2, 200], [0.005, 700], [1.2, 995]], 10], [8.18, 3]], ['GNSS set 19', [[[0.02, 700], [0.02, 60]], 60], [6.65, 2]], ['GNSS set 20', [[[1.2, 60], [0.3, 700], [0.3, 200], [0.3, 995], [0.02, 995]], 60], [8.46, 5]]], [['GNSS set 19', [[[0.02, 700], [0.02, 60]], 60], [6.65, 2]], ['GNSS set 21', [[[1.2, 200], [0.02, 1100], [0.005, 700], [0.3, 995]], 10], [9.13, 2]], ['GNSS set 22', [[[0.05, 700], [1.2, 200], [1.2, 10], [1.2, 1100], [0.3, 1100]], 10], [8.04, 3]], ['GNSS set 23', [[[0.3, 700], [0.05, 995], [1.2, 200], [0.005, 10]], 25], [8.69, 3]], ['GNSS set 24', [[[0.02, 1100], [1.2, 200], [0.02, 1100], [0.3, 1100]], 60], [8.96, 1]], ['GNSS set 25', [[[0.005, 1100], [0.3, 60], [1.2, 10], [0.05, 700], [1.2, 60]], 25], [7.78, 4]], ['GNSS set 26', [[[0.05, 995]], 60], [8.11, 1]], ['GNSS set 27', [[[0.3, 10]], 60], [7.38, 1]]], [['GNSS set 24', [[[0.02, 1100], [1.2, 200], [0.02, 1100], [0.3, 1100]], 60], [8.96, 1]], ['GNSS set 28', [[[0.02, 1100], [0.005, 200], [0.05, 200]], 10], [7.04, 1]], ['GNSS set 29', [[[0.3, 60], [0.02, 1100], [0.3, 995], [1.2, 60]], 60], [8.42, 3]], ['GNSS set 30', [[[0.3, 200], [1.2, 10], [0.3, 1100]], 60], [8.13, 2]], ['GNSS set 31', [[[0.05, 200], [0.05, 700]], 10], [7.44, 2]], ['GNSS set 32', [[[1.2, 1100]], 10], None], ['GNSS set 33', [[[0.02, 10], [0.3, 995], [1.2, 1100], [0.02, 700]], 60], [7.5, 3]], ['noise floor station', [[[0.02, 100]], 10], [6.14, 1]]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
GNSS set 0[7.36, 2][7.36, 2]Passed
GNSS set 1[8.88, 2][8.88, 2]Passed
GNSS set 2[8.93, 1][8.93, 1]Passed
GNSS set 3NoneNonePassed
GNSS set 4[8.3, 3][8.3, 3]Passed
GNSS set 5[6.94, 2][7.48, 2]Failed
GNSS set 6[6.2, 2][6.72, 2]Failed
GNSS set 7NoneNonePassed

SHA-256 / 38e5865ceedbf7b4ce873cb3183c1d8628de24870213d2a340459519f0f43a62

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(obs, depth_km):
    A, B, C = -4.434, 1.047, -0.138
    ms = []
    for pgd_m, epi in obs:
        pgd_cm = pgd_m * 100.0
        r = epi + depth_km
        if pgd_cm < 2.0 or r > 1000:
            continue
        ms.append((math.log10(pgd_cm) - A) / (B + C * math.log10(r)))
    if not ms:
        return None
    return [round(sum(ms) / len(ms), 2), len(ms)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['GNSS set 0', [[[0.005, 700], [0.05, 1100], [0.02, 995], [0.02, 700]], 25], [7.36, 2]], ['GNSS set 1', [[[0.005, 200], [0.005, 10], [1.2, 995], [0.005, 995], [0.02, 995]], 10], [8.88, 2]], ['GNSS set 2', [[[1.2, 200]], 10], [8.93, 1]], ['GNSS set 3', [[[1.2, 1100]], 10], None], ['GNSS set 4', [[[0.005, 995], [0.02, 200], [0.005, 1100], [1.2, 995], [1.2, 60]], 10], [8.3, 3]], ['GNSS set 5', [[[0.005, 10], [0.3, 60], [0.3, 1100], [0.3, 10]], 60], [7.48, 2]], ['GNSS set 6', [[[0.3, 10], [0.005, 200], [1.2, 1100], [0.005, 1100], [0.02, 60]], 60], [6.72, 2]], ['GNSS set 7', [[[0.005, 700], [1.2, 1100]], 25], None]], [['GNSS set 7', [[[0.005, 700], [1.2, 1100]], 25], None], ['GNSS set 8', [[[1.2, 700], [0.005, 10]], 10], [9.95, 1]], ['GNSS set 9', [[[1.2, 60], [0.3, 10], [0.05, 60]], 25], [7.19, 3]], ['GNSS set 10', [[[0.3, 700], [0.02, 1100]], 60], [9.04, 1]], ['GNSS set 11', [[[1.2, 1100], [0.02, 200], [0.02, 200], [0.005, 1100], [0.05, 10]], 25], [6.34, 3]], ['GNSS set 12', [[[0.3, 200]], 25], [8.11, 1]], ['GNSS set 13', [[[0.005, 700], [0.05, 700], [1.2, 995], [0.3, 700]], 25], [9.05, 3]], ['GNSS set 14', [[[1.2, 700], [0.02, 200], [0.02, 700]], 10], [7.89, 3]]], [['GNSS set 13', [[[0.005, 700], [0.05, 700], [1.2, 995], [0.3, 700]], 25], [9.05, 3]], ['GNSS set 14', [[[1.2, 700], [0.02, 200], [0.02, 700]], 10], [7.89, 3]], ['GNSS set 15', [[[0.005, 60]], 10], None], ['GNSS set 16', [[[1.2, 200], [0.005, 200], [0.02, 10], [0.3, 700]], 25], [7.85, 3]], ['GNSS set 17', [[[0.3, 200], [0.05, 995]], 60], [8.12, 2]], ['GNSS set 18', [[[0.02, 10], [0.3, 1100], [1.2, 200], [0.005, 700], [1.2, 995]], 10], [8.18, 3]], ['GNSS set 19', [[[0.02, 700], [0.02, 60]], 60], [6.65, 2]], ['GNSS set 20', [[[1.2, 60], [0.3, 700], [0.3, 200], [0.3, 995], [0.02, 995]], 60], [8.46, 5]]], [['GNSS set 19', [[[0.02, 700], [0.02, 60]], 60], [6.65, 2]], ['GNSS set 21', [[[1.2, 200], [0.02, 1100], [0.005, 700], [0.3, 995]], 10], [9.13, 2]], ['GNSS set 22', [[[0.05, 700], [1.2, 200], [1.2, 10], [1.2, 1100], [0.3, 1100]], 10], [8.04, 3]], ['GNSS set 23', [[[0.3, 700], [0.05, 995], [1.2, 200], [0.005, 10]], 25], [8.69, 3]], ['GNSS set 24', [[[0.02, 1100], [1.2, 200], [0.02, 1100], [0.3, 1100]], 60], [8.96, 1]], ['GNSS set 25', [[[0.005, 1100], [0.3, 60], [1.2, 10], [0.05, 700], [1.2, 60]], 25], [7.78, 4]], ['GNSS set 26', [[[0.05, 995]], 60], [8.11, 1]], ['GNSS set 27', [[[0.3, 10]], 60], [7.38, 1]]], [['GNSS set 24', [[[0.02, 1100], [1.2, 200], [0.02, 1100], [0.3, 1100]], 60], [8.96, 1]], ['GNSS set 28', [[[0.02, 1100], [0.005, 200], [0.05, 200]], 10], [7.04, 1]], ['GNSS set 29', [[[0.3, 60], [0.02, 1100], [0.3, 995], [1.2, 60]], 60], [8.42, 3]], ['GNSS set 30', [[[0.3, 200], [1.2, 10], [0.3, 1100]], 60], [8.13, 2]], ['GNSS set 31', [[[0.05, 200], [0.05, 700]], 10], [7.44, 2]], ['GNSS set 32', [[[1.2, 1100]], 10], None], ['GNSS set 33', [[[0.02, 10], [0.3, 995], [1.2, 1100], [0.02, 700]], 60], [7.5, 3]], ['noise floor station', [[[0.02, 100]], 10], [6.14, 1]]]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
GNSS set 0[7.26, 1][7.36, 2]Failed
GNSS set 1None[8.88, 2]Failed
GNSS set 2[8.96, 1][8.93, 1]Failed
GNSS set 3NoneNonePassed
GNSS set 4[7.37, 2][8.3, 3]Failed
GNSS set 5[7.62, 2][7.48, 2]Failed
GNSS set 6[6.84, 2][6.72, 2]Failed
GNSS set 7NoneNonePassed

SHA-256 / 4161958e366f9adbec532cc79d3f10b539426b9e512b653220bf5cd45630a3ce

HELD IN THE MEMBER ARCHIVE

The verified repair and its recorded checks are member-only.

This mechanism has 8 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.

Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.

Member access is invitation-based. Sign in with your invited account to inspect the repair.

Sign in to the archive ↗

Verification & scope

Stipulated deterministic teaching model of a seismological magnitude procedure; constants and tables are fixed by the contract and no claim of agency or standards conformance is made. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:48:31.599552+00:00.

Case digest / 060df81f0c915f6407057e79754f96696039af66b878d769cb1ae231b91a1694