fix: atom_to_site U_cart->U_cif conversion for non-orthogonal cells - #430
Merged
keitaroyam merged 1 commit intoMay 29, 2026
Merged
Conversation
The shortcut "U_cif == U_cart" only holds for fully orthogonal cells (alpha = beta = gamma = 90 degrees). The previous angle check used OR instead of AND, so any cell with at least one 90-degree angle skipped the basis change. This silently corrupted the aniso conversion for hexagonal / trigonal / monoclinic cells, where the fractionalization matrix has off-diagonal entries. Round-trip mx_to_sx_structure -> calculate_sf_from_small_structure disagreed with calculate_sf_from_model on the same model by tens of percent at moderate (h, k, l) for any hexagonal or monoclinic input. The fix is one character (OR -> AND); a clarifying comment is added. Two regression tests cover the hexagonal (90, 90, 120) and monoclinic (90, beta, 90) cases; the reference U_cif values match cctbx's adptbx.u_cart_as_u_cif.
Collaborator
|
good catch, thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixing bug in
gemmi::atom_to_site(interop.hpp)Tested with gemmi 0.7.3 on macOS, Python 3.13.
TLDR:
When converting U from cartesian to cif the condition was wrong and didn't work in hexagonal and monoclinic system. Patch prepared with Claude so pretty verbous, the important fix is only one line. I personally checked the fix, the test is created by LLM and not checked.
Long description
Summary
gemmi::atom_to_site(and thereforemx_to_sx_structure) skips theU_cart → U_cif basis change whenever any one cell angle equals 90°.
That branch produces a
SmallStructurewhosesite.anisofield doesnot satisfy the IUCr convention that the rest of gemmi (e.g.
StructureFactorCalculatorX::calculate_sf_from_small_structureandthe CIF reader) uses.
Net effect:
mx_to_sx_structure(st)followed bycalculate_sf_from_small_structure(...)returns structure factors thatdo not agree with
calculate_sf_from_model(...)on the samestructure for hexagonal / trigonal / monoclinic cells. The disagreement
grows quickly with
|U|and|hkl|and is order-of-tens-of-percent forrealistic ADP magnitudes.
The code
gemmi/include/gemmi/interop.hpp, lines 26–39:The first branch is taken whenever any of α, β, γ equals 90°. That
includes hexagonal/trigonal (α=β=90, γ=120) and monoclinic
(α=γ=90, β≠90). Mathematically,
U_cart == U_cifonly when allthree angles are 90° (fully orthogonal). The condition should be
&&, not||.What gemmi does elsewhere with
site.anisoThe rest of gemmi treats
site.anisoas the standard IUCr CIFU_aniso(the "fractional" basis), i.e. the Debye–Waller factor isThis was verified by:
_atom_site_aniso_U_*block.gemmi.read_small_structure— gemmi stores theCIF values verbatim in
site.aniso.calculate_sf_from_small_structureand comparing with thevalue computed by hand using the IUCr DW formula above.
tested.
So
calculate_sf_from_small_structureandread_small_structureagree with the IUCr convention; only
atom_to_site/mx_to_sx_structuredisagree.
Reproducer 1 — atom_to_site copies U_cart verbatim instead of converting
Output:
U_11is off by 17%,U_12by a factor of ~4. (The disagreement isexactly on the components affected by the in-plane γ ≠ 90.)
Reproducer 2 — observable as F(hkl) disagreement
Picking up the same
stfrom Reproducer 1 but with larger U(0.12, 0.13, 0.20, 0.04, 0.02, 0.01) to make the effect obvious:
Output:
Reflections lying along the c-axis (
0,0,l) are unaffected becauseU_33andc*aren't touched by the γ rotation. Everything in theab plane is wrong; the worst case shown is 77% above the correct
amplitude.
Suggested fix
Scope of impact
Cells unaffected:
and the identity copy is correct.
Note
atom_to_siteis also called frommx_to_sx_structure, so any userpipeline that does
Structure → SmallStructure → calculate_sfisaffected. The CIF-reading path
(
read_small_structure → calculate_sf_from_small_structure) is notaffected — gemmi stores the CIF's IUCr values verbatim and computes
with the IUCr formula correctly.