QuantumBFS / QuantumBFS/quantum.harness

[challenge]: Solving crystal structures from powder XRD with a generative prior

Open
#68 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accepted challenge
Dominant language
Python
Stars
66
Forks
93
PR merge metrics
No merged PRs in 30d

Description

Released by

Lei Wang (王磊), Institute of Physics, Chinese Academy of Sciences

Contact email

wangleiphy@gmail.com

Method

Generative modeling / inverse problems

Challenge issue

Track: AI-agents-for-research · generative materials / inverse problems
Difficulty: advanced (comfortable reading ML papers and modifying JAX)
Compute: one GPU per team is enough for the week

Overview

Point an X-ray source at an unknown powder and, in minutes, you get a diffraction pattern — a 1-D barcode of the 3-D atomic arrangement inside. Turning that barcode back into the actual crystal structure is one of the oldest and most useful inverse problems in science: it is how we find out what we just made. When a sample happens to yield a good single crystal, the structure falls out almost for free — but often it doesn't, and then the powder pattern is all you have. Reading a structure out of it has, for a century, demanded expert intuition and painstaking trial-and-error.

It is hard for a real reason. Single-crystal structure solution has been essentially routine since direct methods (Nobel Prize, 1985); powder is harder still — collapsing 3-D diffraction into a 1-D pattern overlaps the reflections, and it remains unsolved for complex structures. Very different structures can produce nearly identical patterns, so naively optimizing "make the simulated pattern match the data" wanders into a maze of look-alike wrong answers (Segal et al., Digital Discovery 2026).

Here is the bet of this challenge. A generative model that has already seen a million crystals knows what real structures look like. Give that knowledge to the solver as a prior, and the maze collapses — you search only over structures that are both consistent with the measured pattern and chemically plausible. Your job this week is to build that solver, and watch it read a structure straight out of an experiment.

The idea

Three ingredients, one loop:

  1. a generative prior — CrystalFormer, a pretrained transformer that samples plausible crystals. It emits the space group first, then Wyckoff sites, atom types, coordinates, and lattice.
  2. a forward simulator — compute the powder pattern of any candidate structure and score how well it matches your target.
  3. reinforcement learning — reward structures that fit, keep them close to the prior, repeat.

Formally, you minimize a variational free energy:

$$F ;=; \underbrace{\mathbb{E}{X\sim q(X)}\big[-r(X)\big]}{\text{goodness of fit — "energy"}} ;+; \tau,\underbrace{\mathrm{KL}\big(q(X),|,p(X)\big)}_{\text{stay realistic — "entropy"}}$$

  • $r(X)$ — how well the pattern simulated from structure $X$ matches the measured pattern.
  • $p(X)$ — the pretrained CrystalFormer prior; the KL term is a leash keeping proposals on the manifold of real crystals.
  • $q(X)$ — your solver, tuned to one target pattern at a time.

This is the maximum-entropy principle with a learned prior: fit the measurement, but stay as close as you can to what real crystals look like. It buys you two things that make the "impossible" problem tractable:

  • No gradients through the simulator. The reward is just a number, so a fast, standard, non-differentiable simulator is fine — and the rough loss landscape that traps gradient descent is simply not in your path.
  • The symmetry is discovered, not assumed. Because CrystalFormer samples the space group as its first token, you do not need to know it in advance — the solver proposes a space group and the pattern fit selects it.

It is a modern remake of a classic idea: Harris et al. (1994) solved structures from powder data by random-move Monte Carlo — propose a structure, score it against the pattern, accept or reject. We swap the random moves for a pretrained generative model that already knows chemistry, and the accept/reject for the variational free energy above.

The reward $r(X)$

You know the composition — it is your sample. Condition CrystalFormer on that formula and let it sample structures (space group and all). For each candidate:

  • Simulate its powder pattern with pymatgen's XRDCalculator (kinematic, fast), then convolve the discrete peaks with a profile (Gaussian / pseudo-Voigt) into a continuous curve.
  • Score it with the cosine similarity to the target pattern — one clean number in $[0,1]$, and that is the reward.

Matching the broadening and $2\theta$ window to the target is where much of the real craft lives — a faithful fit metric matters more than the RL details.

Do you need a database of patterns? No.

To solve a structure from a given pattern, all you need is a structure→pattern simulator for the fit; the prior is trained on structures (CIFs), not on paired pattern↔structure labels. So databases are only for scoring yourself:

  • Self-supervised recovery — start here. Take a known crystal, simulate its pattern (add realistic broadening and noise), and see whether your solver recovers it. Unlimited targets from Materials Project / COD CIFs, ground truth included.
  • Benchmark on held-out cases from SimXRD-4M (4M simulated patterns; arXiv:2406.15469); report structure-match rate.
  • Stretch to real data with experimental patterns from opXRD (arXiv:2503.05577), where background, texture, and broadening break simulator-clean assumptions — exactly where the prior earns its keep.

Getting started

Repo: deepmodeling/CrystalFormer (JAX). You are reusing a working system — you write one new reward function, not a new algorithm. (It is the very same RL loop as the sibling challenge #65; only the reward is new.)

  • Add a reward: make_xrd_reward_fn in crystalformer/reinforce/reward.py, next to make_prop_reward_fn. It wraps pymatgen (structure→pattern) plus cosine similarity to the fixed target. The sim is NumPy and the loop is JAX, so wrap the reward as a host callback / plain black-box scalar — RL never needs it differentiable.
  • Drive it: crystalformer/cli/train_ppo.py, conditioned on the known composition. Knobs: --beta (the $\tau$ KL leash to the prior), --sg_temperature, --sg_epsilon, --exploration_weight, --diversity_weight.
  • Evaluate: the fit is your live metric; for the benchmark, structure-match the top candidate to ground truth with pymatgen's StructureMatcher.

Milestones (week-sized)

  1. Wire the pymatgen XRD reward; confirm it peaks at the true structure for a simple known case.
  2. Recover a handful of known structures from simulated patterns; report recovery rate against a no-prior (random-search) baseline.
  3. Show the prior matters: sweep the KL strength $\tau$ from no-prior to strong-prior and demonstrate it cures the look-alike-local-minima failure.
  4. Stretch: harder chemistries, or experimental opXRD patterns.

Deliverables

A short study: recovery rate, the $\tau$ ablation, and a comparison against a gradient-descent baseline and/or a random-move Monte Carlo baseline — with a gallery of solved structures next to their patterns. Bounded for a week, with a tail that can become a paper.

References

  • CrystalFormer (the prior $p$) — Cao, Luo, Lv, Wang, Space Group Informed Transformer for Crystalline Materials Generation, arXiv:2403.15734; Science Bulletin 2025. Code: deepmodeling/CrystalFormer.
  • CrystalFormer-RL (the RL loop, shared with #65) — Cao & Wang, Reinforcement Fine-Tuning for Materials Design, arXiv:2504.02367; Phys. Rev. B 113, 024106 (2026).
  • Why the naive fit is hard — Segal, Subramanian, Li, Miller, Gómez-Bombarelli, The loss landscape of powder X-ray diffraction-based structure optimization is too rough for gradient descent, arXiv:2512.04036; Digital Discovery 2026, DOI 10.1039/D6DD00017G.
  • The classical Monte Carlo ancestor — Harris, Tremayne, Lightfoot, Bruce, Crystal Structure Determination from Powder Diffraction Data by Monte Carlo Methods, J. Am. Chem. Soc. 116, 3543 (1994).
  • Related ML baseline — Parackal, Goodall, Faber, Armiento, Identifying crystal structures beyond known prototypes from x-ray powder diffraction spectra, Phys. Rev. Materials 8, 103801 (2024).
  • Tooling — forward model: pymatgen XRDCalculator. Benchmarks: SimXRD-4M (arXiv:2406.15469), opXRD (arXiv:2503.05577).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading crystalformer/reinforce/reward.py, especially make_prop_reward_fn, then inspect crystalformer/cli/train_ppo.py and the existing RL loop. Add the XRD reward around pymatgen XRDCalculator and cosine similarity for a fixed target, then validate recovery on known simulated structures and report the recovery rate and KL-strength ablation.

Written by the indexing model from the issue text.

Assessment

Tech stack
numpy, python
Domain
data, machine-learning
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.