Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions scripts/legacy_xrd/convert_legacy_xrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,18 @@
"CW": "Caleb Wasserbeck",
}

# Scan settings by step size (degrees 2-theta). Times are as reported by the
# lab (effective time per step); quick scans are routine, long ones are the
# ~2 h scans used for Rietveld refinement.
# Scan settings by step size (degrees 2-theta), with the time per step in
# seconds confirmed by Tufail Hassan (email, 2026-10-12). Quick scans are
# routine; long ones are used for Rietveld refinement.
SCAN_TYPES = {
Fraction("0.02"): ("quick", 49.0),
Fraction("0.015"): ("long", 361.24),
Fraction("0.02"): ("quick", 0.191),
Fraction("0.015"): ("long", 1.41),
}

# Column for the pattern file: the output name on the lab's registered
# diffractometer.
PATTERN_FIELD = "XRD pattern file"

# Conditions the lab reports as constant for its MAX synthesis runs.
LEGACY_CONSTANTS = {
"Atmosphere": "Ar",
Expand Down Expand Up @@ -129,7 +133,7 @@
"Two Theta Max",
"Points",
"Researcher",
"XRD Pattern",
PATTERN_FIELD,
"Source File",
"Tags",
]
Expand Down Expand Up @@ -499,7 +503,7 @@ def convert(
"Two Theta Max": _fmt_number(max(pattern.two_theta)),
"Points": str(len(pattern.two_theta)),
"Researcher": researcher,
"XRD Pattern": f"patterns/{pattern_name}",
PATTERN_FIELD: f"patterns/{pattern_name}",
"Source File": path.name,
"Tags": " ".join(parsed.tags),
}
Expand Down
20 changes: 17 additions & 3 deletions scripts/legacy_xrd/test_convert_legacy_xrd.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@

sys.path.insert(0, str(Path(__file__).parent))

from convert_legacy_xrd import FormulaError, convert, parse_filename, parse_formula # noqa: E402
from convert_legacy_xrd import ( # noqa: E402
FormulaError,
classify_scan,
convert,
parse_filename,
parse_formula,
)

RAW_LINES = [f'"{3 + i * 0.02:.16g}\t{100 + i}"\r\n' for i in range(50)]

Expand Down Expand Up @@ -98,6 +104,13 @@ def test_bad_date_is_an_error(self):
self.assertTrue(parse_filename("133024_Ti3AlC2_1500_4h_TH").problems)


class ClassifyScanTests(unittest.TestCase):
def test_lab_confirmed_times_per_step(self):
self.assertEqual(classify_scan(0.02), ("quick", 0.191))
self.assertEqual(classify_scan(0.015), ("long", 1.41))
self.assertEqual(classify_scan(0.05), ("unknown", None))


class ConvertTests(unittest.TestCase):
def test_splits_into_synthesis_and_xrd_linked_by_sample_id(self):
with tempfile.TemporaryDirectory() as tmp:
Expand All @@ -124,18 +137,19 @@ def test_splits_into_synthesis_and_xrd_linked_by_sample_id(self):
self.assertRegex(sample["Sample ID"], r"^PUDT[0-9A-Z]{10}$")
self.assertEqual({row["Sample ID"] for row in xrd}, {sample["Sample ID"]})
self.assertEqual(xrd[0]["Scan Type"], "quick")
self.assertEqual((xrd[0]["Step Size"], xrd[0]["Time per Step"]), ("0.02", "0.191"))
self.assertEqual(xrd[1]["Tags"], "rescan")
self.assertEqual((xrd[0]["Loading"], xrd[0]["Sample Preparation"]), ("top", "ground powder"))
self.assertIn("not stripped", xrd[0]["Radiation"])
self.assertEqual(sample["Precursors"], "")

pattern = (out / xrd[0]["XRD Pattern"]).read_text().splitlines()
pattern = (out / xrd[0]["XRD pattern file"]).read_text().splitlines()
self.assertEqual(pattern[0], "two_theta_deg,intensity_counts")
self.assertEqual(pattern[1], "3.0,100")
self.assertEqual(len(pattern), 51)
with zipfile.ZipFile(out / "patterns.zip") as archive:
self.assertEqual(
sorted(archive.namelist()), sorted(row["XRD Pattern"] for row in xrd)
sorted(archive.namelist()), sorted(row["XRD pattern file"] for row in xrd)
)

# It's exactly the ID the platform issues for that synthesis run.
Expand Down