FAILURE MAP
← Case archive

FA-71716 / Seismic magnitude estimation / Open access

Regional conversion to Mw: ML low branch boundary · case 01

ML 3.5 converts to Mw 3.4.

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

ROOT CAUSE

The low-magnitude regression includes 3.5.

VERIFIED REPAIR

Use the regression only for ML < 3.5.

Unsuccessful approach: Moving the boundary to 3.4 passes ML 3.4 through unconverted.

Case contract

Case-sensitive type. ML: < 3.5 -> 0.8 ML + 0.6; 3.5..6.0 -> ML; > 6.0 None. mb: 3.5..6.2 -> 1.54 mb - 2.54, else None. Ms: <= 6.1 -> 0.67 Ms + 2.07; 6.1 < Ms <= 8.2 -> 0.99 Ms + 0.08; else None. Other types None. Round half up to 0.1 via floor(x*10 + 0.5)/10.

Why this case matters

Homogenised catalogues convert heterogeneous magnitudes to a common Mw.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(mtype, value):
    if mtype == "ML":
        if value > 6.0:
            return None
        x = 0.8 * value + 0.6 if value <= 3.5 else value
    elif mtype == "mb":
        if not (3.5 <= value <= 6.2):
            return None
        x = 1.54 * value - 2.54
    elif mtype == "Ms":
        if value > 8.2:
            return None
        x = 0.67 * value + 2.07 if value <= 6.1 else 0.99 * value + 0.08
    else:
        return None
    return math.floor(x * 10 + 0.5) / 10
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['ML 2.0', ['ML', 2.0], 2.2], ['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['ML 4.8', ['ML', 4.8], 4.8], ['ML 6.0', ['ML', 6.0], 6.0], ['ML 6.1', ['ML', 6.1], None], ['ML 6.9', ['ML', 6.9], None], ['mb 3.4', ['mb', 3.4], None]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['mb 3.4', ['mb', 3.4], None], ['mb 3.5', ['mb', 3.5], 2.9], ['mb 5.0', ['mb', 5.0], 5.2], ['mb 6.2', ['mb', 6.2], 7.0], ['mb 6.3', ['mb', 6.3], None], ['Ms 4.0', ['Ms', 4.0], 4.8]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['Ms 6.1', ['Ms', 6.1], 6.2], ['Ms 6.2', ['Ms', 6.2], 6.2], ['Ms 8.2', ['Ms', 8.2], 8.2], ['Ms 8.3', ['Ms', 8.3], None], ['Md 3.0', ['Md', 3.0], None], ['ml 4.0', ['ml', 4.0], None]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['ML 4.8', ['ML', 4.8], 4.8], ['ML 6.0', ['ML', 6.0], 6.0], ['ML 6.1', ['ML', 6.1], None], ['ML 6.9', ['ML', 6.9], None], ['mb 3.4', ['mb', 3.4], None], ['mb 3.5', ['mb', 3.5], 2.9]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['mb 3.5', ['mb', 3.5], 2.9], ['mb 5.0', ['mb', 5.0], 5.2], ['mb 6.2', ['mb', 6.2], 7.0], ['mb 6.3', ['mb', 6.3], None], ['Ms 4.0', ['Ms', 4.0], 4.8], ['Ms 6.0', ['Ms', 6.0], 6.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
ML 2.02.22.2Passed
ML 3.43.33.3Passed
ML 3.53.43.5Failed
ML 4.84.84.8Passed
ML 6.06.06.0Passed
ML 6.1NoneNonePassed
ML 6.9NoneNonePassed
mb 3.4NoneNonePassed

SHA-256 / aeaf38b3393c5f730928852669297a4ad096938f5e9fb7efb38d14444e5ef2d2

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(mtype, value):
    if mtype == "ML":
        if value > 6.0:
            return None
        x = 0.8 * value + 0.6 if value < 3.4 else value
    elif mtype == "mb":
        if not (3.5 <= value <= 6.2):
            return None
        x = 1.54 * value - 2.54
    elif mtype == "Ms":
        if value > 8.2:
            return None
        x = 0.67 * value + 2.07 if value <= 6.1 else 0.99 * value + 0.08
    else:
        return None
    return math.floor(x * 10 + 0.5) / 10
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['ML 2.0', ['ML', 2.0], 2.2], ['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['ML 4.8', ['ML', 4.8], 4.8], ['ML 6.0', ['ML', 6.0], 6.0], ['ML 6.1', ['ML', 6.1], None], ['ML 6.9', ['ML', 6.9], None], ['mb 3.4', ['mb', 3.4], None]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['mb 3.4', ['mb', 3.4], None], ['mb 3.5', ['mb', 3.5], 2.9], ['mb 5.0', ['mb', 5.0], 5.2], ['mb 6.2', ['mb', 6.2], 7.0], ['mb 6.3', ['mb', 6.3], None], ['Ms 4.0', ['Ms', 4.0], 4.8]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['Ms 6.1', ['Ms', 6.1], 6.2], ['Ms 6.2', ['Ms', 6.2], 6.2], ['Ms 8.2', ['Ms', 8.2], 8.2], ['Ms 8.3', ['Ms', 8.3], None], ['Md 3.0', ['Md', 3.0], None], ['ml 4.0', ['ml', 4.0], None]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['ML 4.8', ['ML', 4.8], 4.8], ['ML 6.0', ['ML', 6.0], 6.0], ['ML 6.1', ['ML', 6.1], None], ['ML 6.9', ['ML', 6.9], None], ['mb 3.4', ['mb', 3.4], None], ['mb 3.5', ['mb', 3.5], 2.9]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['mb 3.5', ['mb', 3.5], 2.9], ['mb 5.0', ['mb', 5.0], 5.2], ['mb 6.2', ['mb', 6.2], 7.0], ['mb 6.3', ['mb', 6.3], None], ['Ms 4.0', ['Ms', 4.0], 4.8], ['Ms 6.0', ['Ms', 6.0], 6.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
ML 2.02.22.2Passed
ML 3.43.43.3Failed
ML 3.53.53.5Passed
ML 4.84.84.8Passed
ML 6.06.06.0Passed
ML 6.1NoneNonePassed
ML 6.9NoneNonePassed
mb 3.4NoneNonePassed

SHA-256 / d65af762b5e1dfca125d16e904af3398762fdcc6f980639a114cb4a198cfc832

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(mtype, value):
    if mtype == "ML":
        if value > 6.0:
            return None
        x = 0.8 * value + 0.6 if value < 3.5 else value
    elif mtype == "mb":
        if not (3.5 <= value <= 6.2):
            return None
        x = 1.54 * value - 2.54
    elif mtype == "Ms":
        if value > 8.2:
            return None
        x = 0.67 * value + 2.07 if value <= 6.1 else 0.99 * value + 0.08
    else:
        return None
    return math.floor(x * 10 + 0.5) / 10
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['ML 2.0', ['ML', 2.0], 2.2], ['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['ML 4.8', ['ML', 4.8], 4.8], ['ML 6.0', ['ML', 6.0], 6.0], ['ML 6.1', ['ML', 6.1], None], ['ML 6.9', ['ML', 6.9], None], ['mb 3.4', ['mb', 3.4], None]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['mb 3.4', ['mb', 3.4], None], ['mb 3.5', ['mb', 3.5], 2.9], ['mb 5.0', ['mb', 5.0], 5.2], ['mb 6.2', ['mb', 6.2], 7.0], ['mb 6.3', ['mb', 6.3], None], ['Ms 4.0', ['Ms', 4.0], 4.8]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['Ms 6.1', ['Ms', 6.1], 6.2], ['Ms 6.2', ['Ms', 6.2], 6.2], ['Ms 8.2', ['Ms', 8.2], 8.2], ['Ms 8.3', ['Ms', 8.3], None], ['Md 3.0', ['Md', 3.0], None], ['ml 4.0', ['ml', 4.0], None]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['ML 4.8', ['ML', 4.8], 4.8], ['ML 6.0', ['ML', 6.0], 6.0], ['ML 6.1', ['ML', 6.1], None], ['ML 6.9', ['ML', 6.9], None], ['mb 3.4', ['mb', 3.4], None], ['mb 3.5', ['mb', 3.5], 2.9]], [['ML 3.4', ['ML', 3.4], 3.3], ['ML 3.5', ['ML', 3.5], 3.5], ['mb 3.5', ['mb', 3.5], 2.9], ['mb 5.0', ['mb', 5.0], 5.2], ['mb 6.2', ['mb', 6.2], 7.0], ['mb 6.3', ['mb', 6.3], None], ['Ms 4.0', ['Ms', 4.0], 4.8], ['Ms 6.0', ['Ms', 6.0], 6.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
ML 2.02.22.2Passed
ML 3.43.33.3Passed
ML 3.53.53.5Passed
ML 4.84.84.8Passed
ML 6.06.06.0Passed
ML 6.1NoneNonePassed
ML 6.9NoneNonePassed
mb 3.4NoneNonePassed

SHA-256 / 01a692383b0eca20e5bec670eeb2d8fd5333643fa05d1fb8da104b127035403b

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

Case digest / 1a6f176a063cf2958668f732f86e07e78d8a8dfb71d7446885d5d4fcab44121b