diff --git a/scripts/legacy_xrd/convert_legacy_xrd.py b/scripts/legacy_xrd/convert_legacy_xrd.py index b87014a..afd3f94 100644 --- a/scripts/legacy_xrd/convert_legacy_xrd.py +++ b/scripts/legacy_xrd/convert_legacy_xrd.py @@ -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", @@ -129,7 +133,7 @@ "Two Theta Max", "Points", "Researcher", - "XRD Pattern", + PATTERN_FIELD, "Source File", "Tags", ] @@ -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), } diff --git a/scripts/legacy_xrd/test_convert_legacy_xrd.py b/scripts/legacy_xrd/test_convert_legacy_xrd.py index 59c4316..529c210 100644 --- a/scripts/legacy_xrd/test_convert_legacy_xrd.py +++ b/scripts/legacy_xrd/test_convert_legacy_xrd.py @@ -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)] @@ -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: @@ -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.