FAILURE MAP
← Case archive

FA-71436 / Seismic magnitude estimation / Open access

Teleseismic body-wave magnitude: calibration interpolation · case 01

Between table nodes the correction runs backward.

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

ROOT CAUSE

The interpolation fraction is measured from the upper node.

VERIFIED REPAIR

Weight by (delta - d0)/(d1 - d0).

Unsuccessful approach: Dividing by d1 instead of the interval width shrinks the fraction.

Case contract

P amplitude in micrometres, period in s, epicentral distance in degrees. Valid only for 20 <= delta <= 100 and 0 < period <= 3.0 (else None). Q(delta) is linearly interpolated from [(20,6.0),(30,6.5),(40,6.8),(60,6.9),(80,7.0),(100,7.4)]. mb = log10(A/T) + Q, rounded 0.01.

Why this case matters

mb is the first teleseismic magnitude available for global events.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(amp_um, period_s, delta_deg):
    table = [(20, 6.0), (30, 6.5), (40, 6.8), (60, 6.9), (80, 7.0), (100, 7.4)]
    if not (20 <= delta_deg <= 100):
        return None
    if period_s <= 0 or period_s > 3.0:
        return None
    q = None
    for (d0, q0), (d1, q1) in zip(table, table[1:]):
        if d0 <= delta_deg <= d1:
            q = q0 + (q1 - q0) * (d1 - delta_deg) / (d1 - d0)
            break
    return round(math.log10(amp_um / period_s) + q, 2)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['0.05 um 0.5 s at 15 deg', [0.05, 0.5, 15], None], ['0.05 um 0.5 s at 20 deg', [0.05, 0.5, 20], 5.0], ['0.05 um 0.5 s at 25 deg', [0.05, 0.5, 25], 5.25], ['0.05 um 0.5 s at 45 deg', [0.05, 0.5, 45], 5.83], ['0.05 um 0.5 s at 70 deg', [0.05, 0.5, 70], 5.95], ['0.05 um 0.5 s at 99 deg', [0.05, 0.5, 99], 6.38], ['0.05 um 0.5 s at 100 deg', [0.05, 0.5, 100], 6.4], ['0.05 um 0.5 s at 101 deg', [0.05, 0.5, 101], None]], [['0.05 um 0.5 s at 100 deg', [0.05, 0.5, 100], 6.4], ['0.05 um 0.5 s at 101 deg', [0.05, 0.5, 101], None], ['0.05 um 1.0 s at 15 deg', [0.05, 1.0, 15], None], ['0.05 um 1.0 s at 20 deg', [0.05, 1.0, 20], 4.7], ['0.05 um 1.0 s at 25 deg', [0.05, 1.0, 25], 4.95], ['0.05 um 1.0 s at 45 deg', [0.05, 1.0, 45], 5.52], ['0.05 um 1.0 s at 70 deg', [0.05, 1.0, 70], 5.65], ['0.05 um 1.0 s at 99 deg', [0.05, 1.0, 99], 6.08]], [['0.05 um 1.0 s at 99 deg', [0.05, 1.0, 99], 6.08], ['0.05 um 1.0 s at 100 deg', [0.05, 1.0, 100], 6.1], ['0.05 um 1.0 s at 101 deg', [0.05, 1.0, 101], None], ['0.05 um 2.0 s at 15 deg', [0.05, 2.0, 15], None], ['0.05 um 2.0 s at 20 deg', [0.05, 2.0, 20], 4.4], ['0.05 um 2.0 s at 25 deg', [0.05, 2.0, 25], 4.65], ['0.05 um 2.0 s at 45 deg', [0.05, 2.0, 45], 5.22], ['0.05 um 2.0 s at 70 deg', [0.05, 2.0, 70], 5.35]], [['0.05 um 2.0 s at 45 deg', [0.05, 2.0, 45], 5.22], ['0.05 um 2.0 s at 99 deg', [0.05, 2.0, 99], 5.78], ['0.05 um 2.0 s at 100 deg', [0.05, 2.0, 100], 5.8], ['0.05 um 2.0 s at 101 deg', [0.05, 2.0, 101], None], ['0.05 um 3.0 s at 15 deg', [0.05, 3.0, 15], None], ['0.05 um 3.0 s at 20 deg', [0.05, 3.0, 20], 4.22], ['0.05 um 3.0 s at 25 deg', [0.05, 3.0, 25], 4.47], ['0.05 um 3.0 s at 45 deg', [0.05, 3.0, 45], 5.05]], [['0.05 um 3.0 s at 20 deg', [0.05, 3.0, 20], 4.22], ['0.05 um 3.0 s at 70 deg', [0.05, 3.0, 70], 5.17], ['0.05 um 3.0 s at 99 deg', [0.05, 3.0, 99], 5.6], ['0.05 um 3.0 s at 100 deg', [0.05, 3.0, 100], 5.62], ['0.05 um 3.0 s at 101 deg', [0.05, 3.0, 101], None], ['0.05 um 3.5 s at 15 deg', [0.05, 3.5, 15], None], ['0.05 um 3.5 s at 20 deg', [0.05, 3.5, 20], None], ['0.4 um 0.5 s at 45 deg', [0.4, 0.5, 45], 6.73]]]
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
0.05 um 0.5 s at 15 degNoneNonePassed
0.05 um 0.5 s at 20 deg5.55.0Failed
0.05 um 0.5 s at 25 deg5.255.25Passed
0.05 um 0.5 s at 45 deg5.885.83Failed
0.05 um 0.5 s at 70 deg5.955.95Passed
0.05 um 0.5 s at 99 deg6.026.38Failed
0.05 um 0.5 s at 100 deg6.06.4Failed
0.05 um 0.5 s at 101 degNoneNonePassed

SHA-256 / 7824aaa4a92e1e8844bfd1bbfa953a238665608e7f8a240c129a68f631cded6c

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(amp_um, period_s, delta_deg):
    table = [(20, 6.0), (30, 6.5), (40, 6.8), (60, 6.9), (80, 7.0), (100, 7.4)]
    if not (20 <= delta_deg <= 100):
        return None
    if period_s <= 0 or period_s > 3.0:
        return None
    q = None
    for (d0, q0), (d1, q1) in zip(table, table[1:]):
        if d0 <= delta_deg <= d1:
            q = q0 + (q1 - q0) * (delta_deg - d0) / d1
            break
    return round(math.log10(amp_um / period_s) + q, 2)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['0.05 um 0.5 s at 15 deg', [0.05, 0.5, 15], None], ['0.05 um 0.5 s at 20 deg', [0.05, 0.5, 20], 5.0], ['0.05 um 0.5 s at 25 deg', [0.05, 0.5, 25], 5.25], ['0.05 um 0.5 s at 45 deg', [0.05, 0.5, 45], 5.83], ['0.05 um 0.5 s at 70 deg', [0.05, 0.5, 70], 5.95], ['0.05 um 0.5 s at 99 deg', [0.05, 0.5, 99], 6.38], ['0.05 um 0.5 s at 100 deg', [0.05, 0.5, 100], 6.4], ['0.05 um 0.5 s at 101 deg', [0.05, 0.5, 101], None]], [['0.05 um 0.5 s at 100 deg', [0.05, 0.5, 100], 6.4], ['0.05 um 0.5 s at 101 deg', [0.05, 0.5, 101], None], ['0.05 um 1.0 s at 15 deg', [0.05, 1.0, 15], None], ['0.05 um 1.0 s at 20 deg', [0.05, 1.0, 20], 4.7], ['0.05 um 1.0 s at 25 deg', [0.05, 1.0, 25], 4.95], ['0.05 um 1.0 s at 45 deg', [0.05, 1.0, 45], 5.52], ['0.05 um 1.0 s at 70 deg', [0.05, 1.0, 70], 5.65], ['0.05 um 1.0 s at 99 deg', [0.05, 1.0, 99], 6.08]], [['0.05 um 1.0 s at 99 deg', [0.05, 1.0, 99], 6.08], ['0.05 um 1.0 s at 100 deg', [0.05, 1.0, 100], 6.1], ['0.05 um 1.0 s at 101 deg', [0.05, 1.0, 101], None], ['0.05 um 2.0 s at 15 deg', [0.05, 2.0, 15], None], ['0.05 um 2.0 s at 20 deg', [0.05, 2.0, 20], 4.4], ['0.05 um 2.0 s at 25 deg', [0.05, 2.0, 25], 4.65], ['0.05 um 2.0 s at 45 deg', [0.05, 2.0, 45], 5.22], ['0.05 um 2.0 s at 70 deg', [0.05, 2.0, 70], 5.35]], [['0.05 um 2.0 s at 45 deg', [0.05, 2.0, 45], 5.22], ['0.05 um 2.0 s at 99 deg', [0.05, 2.0, 99], 5.78], ['0.05 um 2.0 s at 100 deg', [0.05, 2.0, 100], 5.8], ['0.05 um 2.0 s at 101 deg', [0.05, 2.0, 101], None], ['0.05 um 3.0 s at 15 deg', [0.05, 3.0, 15], None], ['0.05 um 3.0 s at 20 deg', [0.05, 3.0, 20], 4.22], ['0.05 um 3.0 s at 25 deg', [0.05, 3.0, 25], 4.47], ['0.05 um 3.0 s at 45 deg', [0.05, 3.0, 45], 5.05]], [['0.05 um 3.0 s at 20 deg', [0.05, 3.0, 20], 4.22], ['0.05 um 3.0 s at 70 deg', [0.05, 3.0, 70], 5.17], ['0.05 um 3.0 s at 99 deg', [0.05, 3.0, 99], 5.6], ['0.05 um 3.0 s at 100 deg', [0.05, 3.0, 100], 5.62], ['0.05 um 3.0 s at 101 deg', [0.05, 3.0, 101], None], ['0.05 um 3.5 s at 15 deg', [0.05, 3.5, 15], None], ['0.05 um 3.5 s at 20 deg', [0.05, 3.5, 20], None], ['0.4 um 0.5 s at 45 deg', [0.4, 0.5, 45], 6.73]]]
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
0.05 um 0.5 s at 15 degNoneNonePassed
0.05 um 0.5 s at 20 deg5.05.0Passed
0.05 um 0.5 s at 25 deg5.085.25Failed
0.05 um 0.5 s at 45 deg5.815.83Failed
0.05 um 0.5 s at 70 deg5.915.95Failed
0.05 um 0.5 s at 99 deg6.086.38Failed
0.05 um 0.5 s at 100 deg6.086.4Failed
0.05 um 0.5 s at 101 degNoneNonePassed

SHA-256 / 06cc844b4bb430d21661353f4bf2cf59cf00a38145d9c2b6072f43a67e6df2fe

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(amp_um, period_s, delta_deg):
    table = [(20, 6.0), (30, 6.5), (40, 6.8), (60, 6.9), (80, 7.0), (100, 7.4)]
    if not (20 <= delta_deg <= 100):
        return None
    if period_s <= 0 or period_s > 3.0:
        return None
    q = None
    for (d0, q0), (d1, q1) in zip(table, table[1:]):
        if d0 <= delta_deg <= d1:
            q = q0 + (q1 - q0) * (delta_deg - d0) / (d1 - d0)
            break
    return round(math.log10(amp_um / period_s) + q, 2)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['0.05 um 0.5 s at 15 deg', [0.05, 0.5, 15], None], ['0.05 um 0.5 s at 20 deg', [0.05, 0.5, 20], 5.0], ['0.05 um 0.5 s at 25 deg', [0.05, 0.5, 25], 5.25], ['0.05 um 0.5 s at 45 deg', [0.05, 0.5, 45], 5.83], ['0.05 um 0.5 s at 70 deg', [0.05, 0.5, 70], 5.95], ['0.05 um 0.5 s at 99 deg', [0.05, 0.5, 99], 6.38], ['0.05 um 0.5 s at 100 deg', [0.05, 0.5, 100], 6.4], ['0.05 um 0.5 s at 101 deg', [0.05, 0.5, 101], None]], [['0.05 um 0.5 s at 100 deg', [0.05, 0.5, 100], 6.4], ['0.05 um 0.5 s at 101 deg', [0.05, 0.5, 101], None], ['0.05 um 1.0 s at 15 deg', [0.05, 1.0, 15], None], ['0.05 um 1.0 s at 20 deg', [0.05, 1.0, 20], 4.7], ['0.05 um 1.0 s at 25 deg', [0.05, 1.0, 25], 4.95], ['0.05 um 1.0 s at 45 deg', [0.05, 1.0, 45], 5.52], ['0.05 um 1.0 s at 70 deg', [0.05, 1.0, 70], 5.65], ['0.05 um 1.0 s at 99 deg', [0.05, 1.0, 99], 6.08]], [['0.05 um 1.0 s at 99 deg', [0.05, 1.0, 99], 6.08], ['0.05 um 1.0 s at 100 deg', [0.05, 1.0, 100], 6.1], ['0.05 um 1.0 s at 101 deg', [0.05, 1.0, 101], None], ['0.05 um 2.0 s at 15 deg', [0.05, 2.0, 15], None], ['0.05 um 2.0 s at 20 deg', [0.05, 2.0, 20], 4.4], ['0.05 um 2.0 s at 25 deg', [0.05, 2.0, 25], 4.65], ['0.05 um 2.0 s at 45 deg', [0.05, 2.0, 45], 5.22], ['0.05 um 2.0 s at 70 deg', [0.05, 2.0, 70], 5.35]], [['0.05 um 2.0 s at 45 deg', [0.05, 2.0, 45], 5.22], ['0.05 um 2.0 s at 99 deg', [0.05, 2.0, 99], 5.78], ['0.05 um 2.0 s at 100 deg', [0.05, 2.0, 100], 5.8], ['0.05 um 2.0 s at 101 deg', [0.05, 2.0, 101], None], ['0.05 um 3.0 s at 15 deg', [0.05, 3.0, 15], None], ['0.05 um 3.0 s at 20 deg', [0.05, 3.0, 20], 4.22], ['0.05 um 3.0 s at 25 deg', [0.05, 3.0, 25], 4.47], ['0.05 um 3.0 s at 45 deg', [0.05, 3.0, 45], 5.05]], [['0.05 um 3.0 s at 20 deg', [0.05, 3.0, 20], 4.22], ['0.05 um 3.0 s at 70 deg', [0.05, 3.0, 70], 5.17], ['0.05 um 3.0 s at 99 deg', [0.05, 3.0, 99], 5.6], ['0.05 um 3.0 s at 100 deg', [0.05, 3.0, 100], 5.62], ['0.05 um 3.0 s at 101 deg', [0.05, 3.0, 101], None], ['0.05 um 3.5 s at 15 deg', [0.05, 3.5, 15], None], ['0.05 um 3.5 s at 20 deg', [0.05, 3.5, 20], None], ['0.4 um 0.5 s at 45 deg', [0.4, 0.5, 45], 6.73]]]
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
0.05 um 0.5 s at 15 degNoneNonePassed
0.05 um 0.5 s at 20 deg5.05.0Passed
0.05 um 0.5 s at 25 deg5.255.25Passed
0.05 um 0.5 s at 45 deg5.835.83Passed
0.05 um 0.5 s at 70 deg5.955.95Passed
0.05 um 0.5 s at 99 deg6.386.38Passed
0.05 um 0.5 s at 100 deg6.46.4Passed
0.05 um 0.5 s at 101 degNoneNonePassed

SHA-256 / 104ae40f4c1f04dc7138c3e4e235d563f895530f6fa1ba1c1fc2ba47edd0ab85

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:29.668783+00:00.

Case digest / 9b9e36d8f066649ee26a35421704fc9a6134b6f7d0140d0e17ccf8a84075d958