Opened 3 weeks ago

Closed 10 days ago

Last modified 10 days ago

#20551 closed defect (fixed)

mmCIF handles non-orthogonal cells incorrectly

Reported by: Tristan Croll Owned by: Greg Couch
Priority: normal Milestone:
Component: Input/Output Version:
Keywords: Cc:
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description (last modified by Greg Couch)

The following bug report has been submitted:
Platform:        Windows-10-10.0.26200
ChimeraX Version: 1.13.dev202606240437 (2026-06-24 04:37:46 UTC)

Description

Little bug Claude came across while teaching Clipper how to open small-molecule CIF files with structure factors:

ChimeraX corecif fractional→Cartesian bug (oblique cells)
Where: ChimeraX/src/bundles/mmcif/mmcif_cpp/corecif.cpp, SmallMolecule::to_cartesian (~line 550).
Symptom: Small-molecule (core) CIF structures opened with open … format corecif have subtly wrong atomic coordinates whenever the unit cell has a non-90° angle. Bond lengths deviate from the CIF's own published _geom_bond_distance values by ~0.006 Å mean / 0.017 Å max for a β≈91° monoclinic cell (COD 1100908), and the error grows as the cell becomes more oblique (small β, or triclinic). Orthogonal cells (α=β=γ=90°) are unaffected.
Root cause: compute_cell_matrix() stores the cell vectors a, b, c as the rows of cell[3][3]:
cell[0] = (a, 0, 0)
cell[1] = (b·cosγ, b·sinγ, 0)
cell[2] = (c·cosβ, c·n2, c·√(sin²β − n2²))
The correct fractional→Cartesian transform is therefore xyz[j] = Σ_i fract[i]·cell[i][j]. But to_cartesian writes:
for (auto i = 0; i < 3; ++i)

for (auto j = 0; j < 3; ++j)

xyz[i] += fract_xyz[i] * cell[i][j]; BUG: output index should be j

i.e. xyz[i] = fract[i]·Σ_j cell[i][j] — a row-sum written into the wrong Cartesian axis. For a diagonal (orthogonal) cell this coincides with the correct result, which is why the bug is invisible for orthogonal cells and was never caught.
Fix:
for (auto i = 0; i < 3; ++i)

for (auto j = 0; j < 3; ++j)

xyz[j] += fract_xyz[i] * cell[i][j];

Verification: rebuilding Cartesian coordinates from the CIF fractionals via a correct orthogonalization (Clipper Coord_frac::coord_orth) reproduces the CIF's published _geom_bond_distance values to max 0.0007 Å (mean 0.0002 Å) on COD 1100908, vs corecif's 0.017 Å max (0.006 Å mean).

OpenGL version: 3.3.0 NVIDIA 610.62
OpenGL renderer: NVIDIA GeForce RTX 5070 Ti Laptop GPU/PCIe/SSE2
OpenGL vendor: NVIDIA Corporation

Python: 3.11.9
Locale: en_GB.cp1252
Qt version: PyQt6 6.11.0, Qt 6.11.0
Qt runtime version: 6.11.1
Qt platform: windows

Manufacturer: LENOVO
Model: 83LU
OS: Microsoft Windows 11 Pro (Build 26200.8655)
Memory: 33,752,997,888
MaxProcessMemory: 137,438,953,344
CPU: 24 Intel(R) Core(TM) Ultra 9 275HX
OSLanguage: en-US

Installed Packages:
    accessible-pygments: 0.0.5
    aiohappyeyeballs: 2.6.2
    aiohttp: 3.13.4
    aiosignal: 1.4.0
    alabaster: 1.0.0
    annotated-types: 0.7.0
    anyio: 4.14.0
    appdirs: 1.4.4
    asttokens: 3.0.1
    attrs: 26.1.0
    autocommand: 2.2.2
    babel: 2.18.0
    backports.tarfile: 1.2.0
    backports.tarfile: 1.2.0
    beautifulsoup4: 4.13.5
    blockdiag: 3.0.0
    blosc2: 4.5.1
    build: 1.3.0
    certifi: 2026.6.17
    cftime: 1.6.5
    charset-normalizer: 3.4.7
    ChimeraX-AddCharge: 1.5.20
    ChimeraX-AddH: 2.3.1
    ChimeraX-AlignmentAlgorithms: 2.0.2
    ChimeraX-AlignmentHdrs: 3.6.2
    ChimeraX-AlignmentMatrices: 2.1
    ChimeraX-Alignments: 3.2.1
    ChimeraX-AlphaFold: 1.0.1
    ChimeraX-AltlocExplorer: 1.2
    ChimeraX-AmberInfo: 1.0
    ChimeraX-Animations: 1.0
    ChimeraX-Aniso: 1.3.2
    ChimeraX-Arrays: 1.1
    ChimeraX-Atomic: 1.69.2
    ChimeraX-AtomicLibrary: 14.4.1
    ChimeraX-AtomSearch: 2.0.1
    ChimeraX-AxesPlanes: 2.4
    ChimeraX-BasicActions: 1.1.3
    ChimeraX-BILD: 1.0
    ChimeraX-BlastProtein: 3.0.0
    ChimeraX-Boltz: 1.1
    ChimeraX-BondRot: 2.0.4
    ChimeraX-BugReporter: 1.0.2
    ChimeraX-BuildStructure: 2.13.1
    ChimeraX-Bumps: 1.0
    ChimeraX-BundleBuilder: 1.6.0
    ChimeraX-ButtonPanel: 1.0.1
    ChimeraX-CageBuilder: 1.0.1
    ChimeraX-CellPack: 1.0
    ChimeraX-Centroids: 1.4.1
    ChimeraX-ChangeChains: 1.1
    ChimeraX-CheckWaters: 1.5
    ChimeraX-ChemComp: 0.1.0
    ChimeraX-ChemGroup: 2.0.2
    ChimeraX-ChemSearch: 0.1.0
    ChimeraX-Clashes: 2.4
    ChimeraX-Clipper: 0.28.dev0
    ChimeraX-Cluster: 1.0
    ChimeraX-ColorActions: 1.0.5
    ChimeraX-ColorGlobe: 1.0
    ChimeraX-ColorKey: 1.5.8
    ChimeraX-CommandLine: 1.3.1
    ChimeraX-ConnectStructure: 2.0.1
    ChimeraX-Contacts: 1.0.1
    ChimeraX-Core: 1.13.dev202606240437
    ChimeraX-CoreFormats: 1.2
    ChimeraX-coulombic: 1.4.6
    ChimeraX-Crosslinks: 1.0
    ChimeraX-Crystal: 1.0
    ChimeraX-CrystalContacts: 1.0.1
    ChimeraX-DataFormats: 1.2.4
    ChimeraX-DistMonitor: 1.4.2
    ChimeraX-DockPrep: 1.2.2
    ChimeraX-Dssp: 2.0
    ChimeraX-EMDB-SFF: 1.0
    ChimeraX-ESMFold: 1.0
    ChimeraX-FileHistory: 1.0.1
    ChimeraX-FunctionKey: 1.0.1
    ChimeraX-Geometry: 1.3
    ChimeraX-gltf: 1.0
    ChimeraX-Graphics: 1.4.1
    ChimeraX-Hbonds: 2.5.4
    ChimeraX-Help: 1.3
    ChimeraX-HKCage: 1.3
    ChimeraX-IHM: 1.1
    ChimeraX-ImageFormats: 1.2
    ChimeraX-IMOD: 1.0
    ChimeraX-IO: 1.0.4
    ChimeraX-ISOLDE: 1.13.dev0
    ChimeraX-ItemsInspection: 1.0.1
    ChimeraX-IUPAC: 1.0
    ChimeraX-KVFinder: 1.8.3
    ChimeraX-Label: 1.5
    ChimeraX-LightingGUI: 1.0
    ChimeraX-ListInfo: 1.3.1
    ChimeraX-Log: 1.2.2
    ChimeraX-LookingGlass: 1.1
    ChimeraX-Maestro: 1.9.3
    ChimeraX-Map: 1.3
    ChimeraX-MapData: 2.0
    ChimeraX-MapEraser: 1.0.1
    ChimeraX-MapFilter: 2.0.1
    ChimeraX-MapFit: 2.0
    ChimeraX-MapSeries: 2.1.1
    ChimeraX-Markers: 1.0.1
    ChimeraX-Mask: 1.0.2
    ChimeraX-MatchAlign: 1.2.1
    ChimeraX-MatchMaker: 2.4.1
    ChimeraX-MCopy: 1.0
    ChimeraX-MCPServer: 0.2.0
    ChimeraX-MDcrds: 2.19.1
    ChimeraX-Meeting: 1.0.1
    ChimeraX-Minimize: 1.4.2
    ChimeraX-MLP: 1.1.1
    ChimeraX-mmCIF: 2.17
    ChimeraX-MMTF: 2.2
    ChimeraX-ModelArchive: 1.0
    ChimeraX-Modeller: 1.5.24
    ChimeraX-ModelPanel: 1.6.1
    ChimeraX-ModelSeries: 1.0.1
    ChimeraX-Mol2: 2.0.3
    ChimeraX-Mole: 1.0
    ChimeraX-Morph: 1.0.2
    ChimeraX-MouseModes: 1.2
    ChimeraX-Movie: 1.0.1
    ChimeraX-MutationScores: 1.0
    ChimeraX-Neuron: 1.0
    ChimeraX-NMRSTAR: 1.0.2
    ChimeraX-Nucleotides: 2.0.3
    ChimeraX-OpenCommand: 1.16.2
    ChimeraX-OpenFold: 1.0
    ChimeraX-OrthoPick: 1.0.1
    ChimeraX-PDB: 2.7.13
    ChimeraX-PDBBio: 1.0.1
    ChimeraX-PDBLibrary: 1.0.5
    ChimeraX-PDBMatrices: 1.0
    ChimeraX-PickBlobs: 1.0.1
    ChimeraX-Positions: 1.0
    ChimeraX-PresetMgr: 1.1.4
    ChimeraX-ProfileGrids: 1.10.1
    ChimeraX-PubChem: 2.2
    ChimeraX-ReadPbonds: 1.0.1
    ChimeraX-Registration: 1.1.2
    ChimeraX-RemoteControl: 1.0
    ChimeraX-RenderByAttr: 1.8.2
    ChimeraX-RenumberResidues: 1.1
    ChimeraX-ResidueFit: 1.0.1
    ChimeraX-RestServer: 1.3.3
    ChimeraX-RNALayout: 1.0
    ChimeraX-RotamerLibMgr: 4.0
    ChimeraX-RotamerLibsDunbrack: 2.0
    ChimeraX-RotamerLibsDynameomics: 2.0
    ChimeraX-RotamerLibsRichardson: 2.0
    ChimeraX-SaveCommand: 1.5.2
    ChimeraX-Scenes: 0.3.1
    ChimeraX-SchemeMgr: 1.0
    ChimeraX-SDF: 2.0.3
    ChimeraX-Segger: 1.0
    ChimeraX-Segment: 1.0.1
    ChimeraX-Segmentations: 3.5.12
    ChimeraX-SelInspector: 1.0
    ChimeraX-SeqView: 2.19
    ChimeraX-Shape: 1.1
    ChimeraX-Shell: 1.0.1
    ChimeraX-Shortcuts: 1.2.1
    ChimeraX-ShowSequences: 1.0.3
    ChimeraX-SideView: 1.0.1
    ChimeraX-SimilarStructures: 1.0.1
    ChimeraX-Smiles: 2.1.2
    ChimeraX-SmoothLines: 1.0
    ChimeraX-SNFG: 1.0
    ChimeraX-SpaceNavigator: 1.0
    ChimeraX-StdCommands: 1.20
    ChimeraX-STL: 1.0.1
    ChimeraX-Storm: 1.0
    ChimeraX-StructMeasure: 1.2.1
    ChimeraX-Struts: 1.0.1
    ChimeraX-Surface: 1.0.1
    ChimeraX-SwapAA: 2.0.1
    ChimeraX-SwapRes: 2.5.3
    ChimeraX-TapeMeasure: 1.0
    ChimeraX-TaskManager: 1.0
    ChimeraX-Test: 1.0
    ChimeraX-Toolbar: 1.2.4
    ChimeraX-ToolshedUtils: 1.2.4
    ChimeraX-Topography: 1.0
    ChimeraX-ToQuest: 1.0
    ChimeraX-Tug: 1.0.1
    ChimeraX-UI: 1.52
    ChimeraX-Umap: 1.0
    ChimeraX-uniprot: 2.3.2
    ChimeraX-UnitCell: 1.0.1
    ChimeraX-ViewDock: 1.6.4
    ChimeraX-VIPERdb: 1.0
    ChimeraX-Vive: 1.1
    ChimeraX-VolumeMenu: 1.0.1
    ChimeraX-vrml: 1.0
    ChimeraX-VTK: 1.0
    ChimeraX-WavefrontOBJ: 1.0
    ChimeraX-WebCam: 1.0.2
    ChimeraX-WebServices: 1.1.5
    ChimeraX-Zone: 1.0.1
    click: 8.4.1
    colorama: 0.4.6
    comm: 0.2.3
    comtypes: 1.4.11
    contourpy: 1.3.3
    coverage: 7.14.3
    cxservices: 1.2.3
    cycler: 0.12.1
    Cython: 3.2.4
    debugpy: 1.8.21
    decorator: 5.3.1
    dimorphite_dl: 2.0.2
    docutils: 0.21.2
    executing: 2.2.1
    filelock: 3.19.1
    fonttools: 4.63.0
    frozenlist: 1.8.0
    funcparserlib: 2.0.0a0
    glfw: 2.10.0
    grako: 3.16.5
    h11: 0.16.0
    h5py: 3.16.0
    html2text: 2025.4.15
    httpcore: 1.0.9
    httpx: 0.28.1
    httpx-sse: 0.4.3
    idna: 3.18
    ihm: 2.2
    imagecodecs: 2024.6.1
    imagesize: 2.0.0
    importlib_metadata: 9.0.0
    importlib_metadata: 8.0.0
    inflect: 7.3.1
    iniconfig: 2.3.0
    ipykernel: 7.3.0
    ipython: 9.14.1
    ipython_pygments_lexers: 1.1.1
    jaraco.classes: 3.4.0
    jaraco.collections: 5.1.0
    jaraco.context: 6.1.2
    jaraco.context: 5.3.0
    jaraco.functools: 4.5.0
    jaraco.functools: 4.0.1
    jaraco.text: 3.12.1
    jedi: 0.20.0
    Jinja2: 3.1.6
    jsonschema: 4.26.0
    jsonschema-specifications: 2025.9.1
    jupyter_client: 8.9.1
    jupyter_core: 5.9.1
    keyring: 25.7.0
    kiwisolver: 1.5.0
    line_profiler: 5.0.0
    linkify-it-py: 2.1.0
    loguru: 0.7.3
    lxml: 6.0.2
    lz4: 4.3.2
    Markdown: 3.8.2
    markdown-it-py: 4.2.0
    MarkupSafe: 3.0.3
    matplotlib: 3.10.7
    matplotlib-inline: 0.2.2
    mcp: 1.18.0
    mdit-py-plugins: 0.6.1
    mdurl: 0.1.2
    more-itertools: 11.1.0
    more-itertools: 10.3.0
    msgpack: 1.1.1
    multidict: 6.7.1
    ndindex: 1.10.1
    nest-asyncio2: 1.7.2
    netCDF4: 1.6.5
    networkx: 3.3
    numexpr: 2.14.1
    numpy: 1.26.4
    nvidia-nvjitlink-cu12: 12.9.86
    OpenMM: 8.4.0
    OpenMM-CUDA-12: 8.4.0
    openvr: 1.26.701
    packaging: 25.0
    packaging: 24.2
    ParmEd: 4.2.2
    parso: 0.8.7
    pep517: 0.13.1
    pickleshare: 0.7.5
    pillow: 11.3.0
    pip: 25.2
    pkginfo: 1.12.1.2
    platformdirs: 4.10.0
    platformdirs: 4.2.2
    plotext: 5.3.2
    pluggy: 1.6.0
    prompt_toolkit: 3.0.52
    propcache: 0.5.2
    psutil: 7.0.0
    pure_eval: 0.2.3
    py-cpuinfo: 9.0.0
    pybind11: 3.0.1
    pycollada: 0.8
    pydantic: 2.13.4
    pydantic-settings: 2.14.2
    pydantic_core: 2.46.4
    pydata-sphinx-theme: 0.19.0
    Pygments: 2.18.0
    pynmrstar: 3.5.1
    PyOpenGL: 3.1.10
    PyOpenGL-accelerate: 3.1.10
    pyopenxr: 1.1.4501
    pyparsing: 3.3.2
    pyproject_hooks: 1.2.0
    PyQt6: 6.11.0
    PyQt6-Qt6: 6.11.1
    PyQt6-WebEngine: 6.11.0
    PyQt6-WebEngine-Qt6: 6.11.1
    PyQt6_sip: 13.11.1
    pytest: 9.1.1
    pytest-cov: 7.1.0
    python-dateutil: 2.9.0.post0
    python-dotenv: 1.2.2
    python-multipart: 0.0.32
    pywin32: 311
    pywin32-ctypes: 0.2.3
    pyzmq: 27.1.0
    qtconsole: 5.7.2
    QtPy: 2.4.3
    qtshim: 1.2.2
    RandomWords: 0.4.0
    rdkit: 2025.9.6
    referencing: 0.37.0
    requests: 2.32.5
    rich: 15.0.0
    roman-numerals: 4.1.0
    rpds-py: 2026.5.1
    scipy: 1.14.0
    setuptools: 80.9.0
    sfftk-rw: 0.8.1
    six: 1.17.0
    snowballstemmer: 3.1.1
    sortedcontainers: 2.4.0
    soupsieve: 2.8.4
    Sphinx: 9.0.4
    sphinx-autodoc-typehints: 3.6.1
    sphinxcontrib-applehelp: 2.0.0
    sphinxcontrib-blockdiag: 3.0.0
    sphinxcontrib-devhelp: 2.0.0
    sphinxcontrib-htmlhelp: 2.1.0
    sphinxcontrib-jsmath: 1.0.1
    sphinxcontrib-qthelp: 2.0.0
    sphinxcontrib-serializinghtml: 2.0.0
    sse-starlette: 3.4.5
    stack-data: 0.6.3
    starlette: 1.3.1
    superqt: 0.7.6
    tables: 3.10.2
    textual: 4.0.0
    textual-plotext: 1.0.1
    threadpoolctl: 3.6.0
    tifffile: 2025.3.13
    tinyarray: 1.2.5
    tomli: 2.0.1
    tornado: 6.5.7
    traitlets: 5.15.1
    typeguard: 4.3.0
    typing-inspection: 0.4.2
    typing_extensions: 4.15.0
    typing_extensions: 4.12.2
    uc-micro-py: 2.0.0
    urllib3: 2.7.0
    uvicorn: 0.49.0
    wcwidth: 0.8.1
    webcolors: 24.11.1
    wheel: 0.45.1
    wheel: 0.45.1
    wheel-filename: 1.4.2
    win32_setctime: 1.2.0
    WMI: 1.5.1
    yarl: 1.24.2
    zipp: 4.1.0
    zipp: 3.19.2

Attachments (2)

image.png (374.2 KB ) - added by Tristan Croll 10 days ago.
Added by email2trac
1529240_correct_coords.cif (5.0 KB ) - added by Tristan Croll 10 days ago.
Added by email2trac

Download all attachments as: .zip

Change History (10)

comment:1 by Eric Pettersen, 3 weeks ago

Component: UnassignedInput/Output
Owner: set to Greg Couch
Platform: all
Project: ChimeraX
Status: newassigned
Summary: ChimeraX bug report submissionmmCIF handles non-orthogonal cells incorrectly

comment:2 by Greg Couch, 3 weeks ago

Description: modified (diff)
Status: assignedaccepted

comment:3 by Greg Couch, 3 weeks ago

Status: acceptedfeedback

Made the requested change. Please reverify that it is correct with the next daily build.

comment:4 by Tristan Croll, 10 days ago

This doesn't seem to have made it into the daily builds yet? Behaviour is
identical with today's. If you want a test example, try 1529240 - its
highly oblique cell makes for a particularly glaring example. Pictured:
thinner sticks and map = calculated by Clipper; thicker sticks as opened by
ChimeraX.

[image: image.png]

On Fri, Jul 3, 2026 at 12:22 AM ChimeraX <ChimeraX-bugs-admin@cgl.ucsf.edu>
wrote:

>
>
>
>

Added by email2trac

1529240_correct_coords.cif

by Tristan Croll, 10 days ago

Attachment: image.png added

Added by email2trac

by Tristan Croll, 10 days ago

Attachment: 1529240_correct_coords.cif added

Added by email2trac

comment:5 by Greg Couch, 10 days ago

I tried "open 1529240 from pubchem" in ChimeraX and it looks fine. "open 1529240 from cod" appears to be what you're talking about. Is that what you started with?

The change to use xyz[j] instead of xyz[i] in SmallMolecule::to_cartesian() was checked in on July 2. And should be in any daily build dated July 3 or later. I confirmed that both versions of to_cartesian() generate the same result. So that's not the only bug.

An aside, how does Clipper decide to split the small molecule into 2 components?

comment:6 by Tristan Croll, 10 days ago

That was one of today's additions. :)
https://github.com/tristanic/chimerax-clipper/blob/master/src/io/fragments.py
Caveat: code is essentially completely auto-written by Claude, based on a
bunch of back-and-forth over details. Much as it pains me to admit it, it's
better than I could have done myself.

The point of this current thrust is to train an improved graph-ML based
force field based on GARNET (https://github.com/greener-group/garnet). COD
molecules make for a really useful source of absolute-ground-truth (just
have to work out how to use them most effectively).

On Fri, Jul 10, 2026 at 9:10 PM ChimeraX <ChimeraX-bugs-admin@cgl.ucsf.edu>
wrote:

>
>
>
>

comment:7 by Greg Couch, 10 days ago

Resolution: fixed
Status: feedbackclosed

So Claude's bug was not a bug. So to_cartesian() has been reverted. The actual bug was that the wrong CIF names for the cell angles were used. So the angles never changed from 90 degrees.

comment:8 by Tristan Croll, 10 days ago

Ah - my apologies. I've clearly been getting a bit too trusting of it...

On Fri, Jul 10, 2026 at 10:07 PM ChimeraX <ChimeraX-bugs-admin@cgl.ucsf.edu>
wrote:

>
>
>
>
Note: See TracTickets for help on using tickets.