Reading and writing CIF files¶
The full description of exact numeric handling, repair policy, atom-type symbols, disorder, magnetic expansion, and spatial mCIF projection is in CIF and mCIF reading in detail.
httk-atomistic ships the CIF/mCIF parser, reader and writer stack under
httk.atomistic.io.cif, and registers its readers with httk-core through
httk.registry.io.atomistic. Importing httk.core therefore discovers the
.cif loader, so httk.core.load can dispatch a CIF file. .cif, .mcif and
their compressed forms (.cif.gz, .cif.bz2) all dispatch here.
Plain load(path) returns the native ASUStructure — a structure held as its
asymmetric unit, expanding to a full cell on demand (see Structures and
Asymmetric units). Pass raw=True to get the neutral parsed CIF payload instead, when
you want the file’s contents without interpreting them as a structure:
import httk.core # discovery registers the ".cif" loader
payload = httk.core.load("structure.cif", raw=True)
block = payload["blocks"][0] # one neutral asymmetric-unit mapping per structural block
print(payload["header"]) # the file's leading comment lines
print(block["symbols"]) # e.g. ["Na", "Cl"]
print(block["cell_parameters_exact"]) # ("a", "b", "c", "alpha", "beta", "gamma") as verbatim tokens
The neutral CIF payload¶
The neutral payload is a mapping with format "cif" ("mcif" for magnetic
CIFs), a blocks list holding one asymmetric-unit mapping per structural block,
unparsed reasons for blocks that have atom sites but cannot be interpreted, and
the verbatim header. Numeric values are kept as strings; where the file carries
_httk_*_exact companion tags those exact tokens are preferred, so no precision
is lost at the I/O layer.
Two conveniences smooth over real-world files:
Inferred element symbols.
_atom_site_type_symbolis optional in the CIF core dictionary. When it is absent, each site’s element is inferred from the leading element run of its_atom_site_label("MgM1"→Mg), with a warning on the report channel, because inferring chemistry from a label is a guess. A label whose prefix names no element is not guessed at in strict mode: its block cannot be interpreted, soloadomits it fromblocksand records the reason inunparsed(the underlying parser raises aValueErrorthat the loader catches per block). Withrepair=Truesuch a label is instead mapped to the non-chemical"X"with a warning.Repair. Passing
repair=Trueenables a bounded set of warning-emitting repairs and stampsrepair=Trueon neutral payloads. The low-level reader drops malformed auxiliary loops whose column counts do not line up and retries legacy non-UTF-8 path inputs as Latin-1. Duringload, the structure adapter additionally ignores invalid declared Wyckoff metadata in favor of the coordinates and clamps an individual refined occupancy no more than0.1outside[0, 1]to the nearest boundary. Larger violations remain errors. Strict loading rejects each of those cases.
Partial occupancy and disorder¶
Site occupancy is represented without discarding chemistry. When several atom-site rows
generate exactly the same symmetry orbit, the reader combines their elements, occupancies,
charges, and source labels into one mixed Species. When a site’s total occupancy is below
one, the remaining fraction is represented by an explicit "vacancy" constituent. A
co-located total above one that lies outside its stated-precision interval is normalized
without repair when the excess is no larger than 1/1000 and every constituent has a stated
precision, with a DEBUG diagnostic (a total within its stated precision is kept unchanged, as
before). An excess no larger
than 1/10 is rescaled with a warning under repair=True, or rejected with a repair=True
remedy hint otherwise; larger excesses are rejected. For the moment-free spatial report of an
mCIF, the same 1/10 cap applies under repair, and a partial mass channel may also be omitted.
These projections emit warnings where repair changes or omits source data and leave the native
magnetic structure unchanged.
Orbits that only partly overlap remain invalid, because they do not describe one shared crystallographic site and cannot be combined as a species composition.
The CIF writer emits one atom-site row per non-vacancy constituent, preserving occupancies, source labels, integral charge spellings, isotope/pseudo-site labels, and declared masses. Read→write→read is covered over the disorder fixture corpus. State without an exact CIF channel—fractional charges, spins, non-hydrogen attachments, assemblies, a net structure charge, or an independently declared composition—is rejected rather than projected away.
Atom-type symbols and isotopes¶
The CIF core dictionary’s standard _atom_type_symbol values are interpreted as their
elements and optional oxidation states. Both magnitude-before-sign (Fe3+) and the common
sign-before-magnitude spelling (Fe+3) are accepted when the remaining token is an element.
The widespread isotope symbols D and T become
hydrogen constituents with species labels D and T. No default mass is invented for them:
the label already records the isotope, so a mass is set only when an _atom_type_mass or
_atom_type.atomic_mass table states one, and a write does not emit that loop when the source
had none. X maps to OPTIMADE’s non-chemical "X"; Vac, Va, and vacancy map to
"vacancy" with zero mass.
Any other CIF-valid type symbol remains readable in strict mode. The reader emits one
warning per distinct unrecognized symbol, represents its chemistry as "X", and preserves
the symbol without a charge suffix in the aligned species label. This covers conventional
pseudo-sites such as M, R, LP, and Lp, as well as arbitrary values such as dummy
or FeNi, without pretending that they name chemical elements.
Declared Wyckoff data¶
The modern CIF atom-site declarations _atom_site_site_symmetry_multiplicity
(International Tables multiplicity) and _atom_site_site_symmetry_order (the
site-symmetry order) are honored when identifying Wyckoff positions. The deprecated
_atom_site_symmetry_multiplicity tag is never parsed: if it is the only
multiplicity-like tag in a block, httk ignores it and emits one debug-level note for
that block because legacy values are ambiguous between the two conventions. If a
modern declaration is present as well, the deprecated tag is ignored silently.
Lower-level API¶
The runnable Reading, inspecting and writing CIF files walks the lower-level read_cif,
parse_cif_float / parse_cif_int and write_cif API in full. read_cif
parses a CIF into a (data_blocks, header) tuple of raw named blocks without
interpreting any tag’s meaning; read_cif_asus interprets the blocks into
asymmetric-unit mappings; and write_cif reconstructs a CIF, including its
loop_ sections, from that neutral form. read_cif and read_cif_asus are
importable from httk.atomistic.io.cif; write_cif lives in
httk.atomistic.io.cif.cif_writer and the parse helpers in
httk.atomistic.io.cif.cif_parser.