A Python toolkit for the minerals, stones, gems and other condensed-matter accretions that show up at the gemological lab bench. Eleven analytical techniques (Raman, XRF, LIBS, UV-VIS, EPR, LA-ICP-MS, SQUID magnetometry, photoluminescence, FTIR, ⁵⁷Fe Mössbauer, cathodoluminescence), a 96-entry mineral catalog, and a unified diagnostic pipeline that produces auditable identification reports (with an opt-in calibrated-confidence path and a spectral-embedding similarity search) — with a 23-step curriculum that teaches the workflow from "diamond vs simulants" through to a capstone integrated diagnosis.
An unknown green stone, identified as tsavorite via the unified diagnose() pipeline using four techniques (Raman + UV-VIS + XRF + LIBS).
checkmsg is built around a single Spectrum data primitive that every technique speaks. Seven analyzer modules turn raw spectra into structured findings. A unified diagnostic pipeline scores every catalog entry against the collected evidence and produces a DiagnosticReport with verdict, confidence, full candidate-score table, evidence list, reasoning trace, and follow-up recommendations.
flowchart TB
subgraph Input["Input — seven technique-specific spectra"]
S1["raman cm⁻¹"]
S2["xrf keV"]
S3["libs nm"]
S4["uvvis nm"]
S5["epr mT"]
S6["laicpms m/z"]
S7["squid-mh mT / squid-chi K"]
end
subgraph Analyzers["Per-technique analyzers"]
A1["raman.analyze"]
A2["xrf.identify_elements"]
A3["libs.identify"]
A4["uvvis.assign_bands"]
A5["epr.analyze"]
A6["laicpms.analyze"]
A7["squid.analyze (dc/rf)"]
end
Catalog[("MineralProfile<br/>CATALOG (96 entries)")]
Diagnose["diagnose.diagnose"]
Report[["DiagnosticReport<br/>verdict + reasoning trace"]]
S1 --> A1
S2 --> A2
S3 --> A3
S4 --> A4
S5 --> A5
S6 --> A6
S7 --> A7
A1 --> Diagnose
A2 --> Diagnose
A3 --> Diagnose
A4 --> Diagnose
A5 --> Diagnose
A6 --> Diagnose
A7 --> Diagnose
Catalog --> Diagnose
Diagnose --> Report
git clone <this-repo> && cd checkmsg
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pytest -q # 226 tests, ~62 s
.venv/bin/python examples/19_unknown_stone_capstone.py # full diagnose, prints reasoning traceA minimal Python session:
from checkmsg import minerals
from checkmsg.diagnose import diagnose
profile = minerals.get("ruby")
spectra = [
minerals.synthesize_raman(profile, noise=0.005),
minerals.synthesize_uvvis(profile),
minerals.synthesize_xrf(profile),
]
report = diagnose(spectra, frequency_GHz=9.5)
print(report.render())| Technique | Module | What it identifies | Reference data |
|---|---|---|---|
| Raman | raman.py |
Mineral / molecular structure via vibrational modes | RRUFF + catalog peak tables |
| XRF | xrf.py |
Elements (Z ≥ 11) via characteristic X-ray emission | NIST K/L line tables |
| LIBS | libs.py |
Light elements (Be / Li / B) via plasma emission | NIST Atomic Spectra Database |
| UV-VIS | uvvis.py |
Colour origin via electronic transitions | Bundled chromophore table |
| EPR | epr.py |
Unpaired electrons via spin-Hamiltonian simulation | 9 literature-cited centers |
| LA-ICP-MS | laicpms.py |
Concentrations + isotope ratios + U-Pb age | NIST SRM 612/610, IUPAC, chondrite REE |
| SQUID magnetometry | squid.py |
Bulk magnetic ordering, Curie/Néel T, saturation moment, AC χ′(ω)/χ″(ω) — distinguishes magnetite vs hematite, freshwater vs saltwater pearls, HPHT vs natural diamond | 13 magnetic minerals (Dunlop & Özdemir 1997) |
| Muon imaging (experimental) | muon/ |
3-D internal density + Z² scattering + element ID for large composite subjects | 18 materials (Tsai 1974), muonic K_α tabulation (Engfer et al. 1974) |
Each technique has a dedicated docs page at docs/techniques.md with schematic, sequence diagram, and worked example.
Twenty-three runnable example scripts under examples/ — single-technique discriminations through a capstone integrated diagnosis, plus experimental muon-tomography and SQUID-magnetometry modes. Pick a tile to dive in.
Full per-example walkthroughs in docs/curriculum.md.
docs/architecture.md— system overview, class diagram, repository map.docs/techniques.md— per-technique schematics + sequence diagrams + worked outputs.docs/catalog.md— mineral catalog reference + auto-generated confusables graph.docs/diagnose.md— diagnostic pipeline algorithm, scoring rules, worked example.docs/accuracy.md— per-module accuracy tiers, provenance, scoring-weight rationale, and how to read the confidence band.docs/curriculum.md— 23 example walkthroughs.
The catalog and reference tables are sourced from primary gemological and atomic-physics literature:
- RRUFF Project — Raman reference spectra (https://rruff.info), CC-licensed.
- NIST Atomic Spectra Database — XRF K/L line energies + LIBS atomic emission lines.
- IUPAC 2021 — natural-abundance isotope tables.
- Pearce, Perkins, Westgate, Gorton, Jackson, Neal & Chenery 1997, Geostandards Newsletter 21:115 — NIST SRM 612 / 610 preferred values.
- McDonough & Sun 1995, Chem. Geol. 120:223 — CI chondrite REE.
- Stacey & Kramers 1975, Earth Planet. Sci. Lett. 26:207 — terrestrial Pb composition.
- Steiger & Jäger 1977, Earth Planet. Sci. Lett. 36:359 — U-Pb decay constants.
- Longerich, Jackson & Günther 1996, J. Anal. At. Spectrom. 11:899 — LA-ICP-MS internal-standard quantitation equation.
- Loubser & van Wyk 1978, Rep. Prog. Phys. 41:1201 — diamond P1 EPR parameters.
- Manenkov & Prokhorov 1956, Soviet Physics JETP 1:611 — Cr³⁺ in corundum (the ruby maser system).
- Dunlop & Özdemir 1997, Rock Magnetism: Fundamentals and Frontiers (CUP) — Curie/Néel temperatures and saturation magnetisations for the SQUID signature library.
- Hunt, Moskowitz, Banerjee 1995, Rock Physics and Phase Relations (AGU Reference Shelf 3) — bulk magnetic susceptibility ranges for natural mineral assemblages.
Citations for every individual catalog entry live in src/checkmsg/minerals.py docstrings.
The example scripts and tests use synthetic spectra generated for didactic purposes. Real instrument data — with drift, polyatomic interferences, matrix-induced sensitivity changes, and physical inclusions — will degrade diagnose() accuracy. This toolkit is not certified for commercial gemological identification.
The reported confidence is a separation ratio, not a probability that the verdict is correct. See docs/accuracy.md for per-module accuracy tiers and the standing disclaimer that every diagnosis surfaces.











