Skip to content

Repository files navigation

CrIStMa

Crystallographic Infrastructure for Structures and Materials.

A compact, physics-first Python library for crystallography, crystal chemistry, and periodic structure analysis.

Python Platform License Status

Overview

CrIStMa provides a common scientific foundation for programs that work with crystal and molecular structures. It reads widely used structural formats, maps them into one canonical model, and offers independent tools for symmetry, geometry, crystal chemistry, and periodic topology.

The project exists because scientific logic is often coupled to a particular file parser, graphical application, or large external framework. That makes calculations difficult to reuse, compare, and audit. CrIStMa keeps these layers separate: formats end at the I/O boundary, scientific operations receive explicit inputs, and results retain diagnostics and provenance.

CrIStMa is not an end-user application and does not prescribe a workflow. It is a reusable scientific library for scripts, notebooks, research software, desktop applications, and automated data-processing systems.

What it can do

  • read CIF, SHELX RES/INS, VASP, PDB, XYZ, and extXYZ structures through one content-aware API;
  • preserve source documents where supported or write a normalized structure;
  • represent periodic crystals and non-periodic molecules as distinct physical models;
  • expand crystallographic sites using exact symmetry operations;
  • use a bundled catalog of all 530 Hall settings and their Wyckoff positions;
  • build symmetry orbits and assign Wyckoff positions;
  • generate reciprocal reflections down to a physical d_min, including exact systematic absences, crystallographic multiplicity, and Friedel relations;
  • calculate neutral-atom X-ray structure factors F, |F|, and |F|² from independent crystallographic sites and an explicit Hall setting;
  • calculate intrinsic powder-line angles and multiplicity-weighted strengths for explicit single- or multi-component radiation, including selectable Cr, Fe, Co, Cu, Mo, and Ag Kα1/Kα2 sources and monochromatic synchrotron X-rays;
  • apply explicit Bragg–Brentano Lorentz and X-ray polarization corrections;
  • calculate finite and periodic neighbour graphs and coordination environments;
  • analyze composition, oxidation-state evidence, coordination shells, and coordination polyhedra;
  • return an explicit crystal-chemistry resolution status and stable symmetry-equivalent contact orbits for downstream applications;
  • assemble structural units and classify periodic blocks as finite units, chains, layers, or frameworks;
  • find translation-aware finite rings in periodic structural representations;
  • resolve intramolecular bond orbits and classify connected components as discrete molecules, chains, layers, or frameworks by exact periodic rank;
  • report recoverable problems as structured diagnostics instead of hiding assumptions or silently changing the input.

Scientific model

All supported formats converge on the same native structures:

CIF / RES / INS / POSCAR / XDATCAR / OUTCAR / vasprun.xml / PDB / XYZ / extXYZ
                                |
                                v
             CrystalStructure | MolecularStructure
                                |
                                v
 symmetry / geometry / chemistry / periodic topology / reciprocal reflections

The canonical structure is the source of truth for calculations. Parsed documents remain available for source preservation and provenance, but file-specific details do not control downstream scientific semantics.

Calculated objects are immutable results rather than hidden application state. The caller decides calculation order, caching, storage, presentation, and user interaction.

Installation

CrIStMa requires Python 3.11 or newer.

Install the public beta from PyPI:

python -m pip install --pre cristma

To install the current source checkout:

git clone https://github.com/ABKuznetsov/CrIStMa.git
cd CrIStMa
python -m pip install -e .

NumPy is the only runtime dependency. Optional development and reference-data dependencies are kept outside the scientific runtime.

Quick start

import cristma
from cristma.geometry import CoordinationAnalyzer, NeighborFinder
from cristma.symmetry import expand_structure

result = cristma.read("sample.cif")

for diagnostic in result.diagnostics:
    print(diagnostic.severity.value, diagnostic.code, diagnostic.message)

if not result.ok or not result.structures:
    raise RuntimeError("The structure could not be read")

crystal = result.structures.primary or result.structures[0]
view = expand_structure(crystal)
neighbors = NeighborFinder(cutoff=3.0).find(view)
coordination = CoordinationAnalyzer().analyze(view, neighbors)

print(crystal.cell.volume)
print(len(view.atoms), len(neighbors.edges))
print(len(coordination.environments))

The same entry point reads other supported formats:

structure = cristma.read("POSCAR").structures[0]
trajectory = cristma.read("XDATCAR").structures
model = cristma.read("molecule.pdb").structures[0]

Native structure I/O

Format Reading Writing Notes
CIF 1.1 Yes Preserve and canonical Source order, comments, unknown tags, and numeric text can be retained
SHELX RES/INS Yes Preserve and canonical Canonical output requires an explicit wavelength
VASP POSCAR/CONTCAR Yes — Selective Dynamics and reported velocities are retained
VASP XDATCAR Yes — Frames are indexed and loaded lazily
VASP OUTCAR Structural frames — Per-atom forces and units are retained
vasprun.xml Structural frames — Trajectory-oriented structural parsing
PDB Yes — Crystal and molecular coordinate models
XYZ/extXYZ Yes — Typed properties and lazy trajectories

CrIStMa implements these readers natively. Gemmi, pymatgen, PyXtal, CrysPy, GSAS-II, SHELX, and graphical frameworks are not required at runtime.

Recoverable source-property problems do not discard otherwise usable coordinates. CIF occupancies outside their physical [0, 1] interval are retained in their reported raw form, normalized to the nearest bound for calculation, and reported by a warning diagnostic. Overfilled coincident mixed positions are normalized proportionally. Fractional coordinates are periodic and are therefore not clamped to [0, 1]; reported ADP values likewise keep their own physical convention and are not treated as occupancies. Atom-site loops are mapped by tag name rather than column position. A non-standard trailing t attached to a fractional symmetry translation (for example z+1/2t) is removed only after strict parsing fails, and every repaired operation produces a warning with the exact recovered expression.

Cell-metric compatibility and special-position matching respect the precision reported by each CIF number; exact symmetry operations themselves remain exact. If an atom loop redundantly lists symmetry-generated copies of the same site, CrIStMa conservatively collapses only chemically and structurally compatible rows and records every source alias in provenance. Conflicting species, occupancies, disorder, displacement parameters, or site metadata are kept separate and reported diagnostically. Unusable polyhedron hull geometry similarly produces an INCOMPLETE calculated polyhedron with its valid vertices retained instead of aborting the structure analysis.

Reflection generation

The first diffraction layer generates complete reciprocal-space reflection orbits without requiring an atomic structure. It accepts an explicit unit cell, one unambiguous catalog SpaceGroupSetting, and a resolution limit:

from cristma.crystallography import SpaceGroupCatalog
from cristma.diffraction import ReflectionGenerator

setting = SpaceGroupCatalog.default().by_setting(523)
reflection_set = ReflectionGenerator().generate(
    cell=crystal.cell,
    space_group=setting,
    d_min=0.8,
)

allowed = reflection_set.allowed
absent = reflection_set.systematically_absent

Systematic absences are derived from exact symmetry-operation phases, not from group-name heuristics or expected-reflection tables.

Orbit-first crystal chemistry

Direct-space crystal chemistry starts from independent sites and an explicit, validated symmetry context. Symmetry orbits are the scientific results; expanded contact instances are created only for a consumer-requested region.

from cristma.chemistry import ChemistryAnalyzer, Composition
from cristma.crystallography import SymmetryContext
from cristma.crystal_chemistry import (
    ContactAnalyzer,
    PolyhedronOrbitBuilder,
    ReferenceCell,
    ShellResolutionPolicy,
)

context = SymmetryContext.from_definition(crystal.space_group, crystal.cell)
chemistry = ChemistryAnalyzer().analyze(Composition.from_structure(crystal))
result = ContactAnalyzer(
    ShellResolutionPolicy(1.60, 0.01, 0.08, 0.01, 2.0)
).analyze(crystal, context, chemistry.grammar)
polyhedra = PolyhedronOrbitBuilder().build(result)

# Outward-only compatibility/materialization boundary:
reference_cell_contacts = result.materialize_contacts(ReferenceCell())
assert result.contacts == reference_cell_contacts

Molecular connectivity is a separate calculation over the same resolved contact orbits. Its bond boundary is explicit and phase-independent:

from cristma.crystal_chemistry import (
    MolecularAnalysisPolicy,
    MolecularAnalyzer,
    MolecularRingSearchPolicy,
)

molecular = MolecularAnalyzer(
    MolecularAnalysisPolicy(maximum_bond_rho=1.25),
    MolecularRingSearchPolicy(maximum_ring_size=12),
).analyze(result)

The result contains immutable molecular bond and component orbits. Component periodicity is derived from exact affine-labelled graph closures: rank zero is a discrete molecule, ranks one and two are a chain and layer, and rank three is a framework. Packing contacts are not promoted to molecular bonds merely because they occurred inside the broader contact-search buffer.

For proven discrete molecular components, ring_orbits reports bounded, symmetry-unique chordless shortest-return graph cycles. Ring atoms retain exact periodic relations, while centroid, normal and planarity RMS are derived geometric descriptors. A reached search bound marks the result incomplete without discarding rings already proved; degenerate geometry likewise keeps the graph ring and reports the unavailable descriptor diagnostically. This layer makes no aromaticity, pi-system or smallest-ring-set claim.

Pi-system screening is a separate optional calculation, so molecular connectivity and ring identity never depend on this interpretation:

from cristma.crystal_chemistry import PiSystemAnalyzer, PiSystemPolicy

pi_systems = PiSystemAnalyzer(
    PiSystemPolicy(maximum_planarity_rms_angstrom=0.12)
).analyze(result, molecular)

Each retained candidate preserves the complete component and occupancy evidence at every ring position. Mixed qualifying and non-qualifying components remain explicit and make the candidate ambiguous. The result means only that a molecular ring passes the declared planarity and composition screen; it does not assign aromaticity, bond order, electron delocalization, or interaction energy.

Pairs of retained pi-system candidates can be screened independently for stacking geometry:

from cristma.crystal_chemistry import PiStackingAnalyzer, PiStackingPolicy

pi_stacking = PiStackingAnalyzer(
    PiStackingPolicy(
        minimum_centroid_distance_angstrom=3.2,
        maximum_centroid_distance_angstrom=4.2,
        maximum_plane_angle_deg=20.0,
        maximum_lateral_offset_angstrom=2.0,
    )
).analyze(result, molecular, pi_systems)

This search operates directly on symmetry orbits with an exact periodic relation and a cutoff-complete lattice buffer. It reports geometry-qualified pi-stacking candidates, not interaction energies or a packing hierarchy.

Explicit C-H and C-D molecular-bond orbits can be screened independently against those same pi-system candidates:

from cristma.crystal_chemistry import CHPiAnalyzer, CHPiPolicy

ch_pi = CHPiAnalyzer(
    CHPiPolicy(
        maximum_hydrogen_centroid_distance_angstrom=3.0,
        minimum_carbon_hydrogen_centroid_angle_deg=120.0,
    )
).analyze(result, molecular, pi_systems)

The reported angle is C-H-centroid at hydrogen. The directed periodic relation and source bond orbit remain explicit; missing hydrogens are never generated, and a molecule's own pi system is excluded by exact molecular-orbit identity rather than a coordinate heuristic.

The completed interaction results can then be assembled into one molecular packing quotient graph:

from cristma.crystal_chemistry import PackingAnalyzer

packing = PackingAnalyzer().analyze(
    intermolecular,
    pi_stacking,
    ch_pi,
)

Graph nodes reference discrete molecule orbits. Exact relation-labelled edges merge van der Waals, hydrogen-bond, pi-stacking, and C-H...pi evidence that describes the same molecular pair relation. Connected-component rank is an exact periodic-connectivity result only; CrIStMa does not assign interaction energies, motif names, a preferred packing hierarchy, or presentation state.

Explicit instances are created only at the outward materialization boundary:

from cristma.crystal_chemistry import (
    PackingInteractionKind,
    PackingMaterializer,
    ReferenceCell,
)

packing_view = PackingMaterializer().materialize(
    packing,
    ReferenceCell(),
    # Optional scientific-evidence filter:
    interaction_kinds=(PackingInteractionKind.PI_STACKING,),
)

The result contains materialized molecules and connections with stable source orbit IDs, exact periodic relations, reference-cell atom IDs, and cell translations. Connections across a cell boundary retain their neighbouring molecule endpoint, while canonical ownership prevents duplicate edges.

Intermolecular contacts reuse that same bounded pair table; they never launch a second neighbour search:

from cristma.crystal_chemistry import (
    IntermolecularContactAnalyzer,
    IntermolecularContactPolicy,
)

intermolecular_policy = IntermolecularContactPolicy()
result = ContactAnalyzer(
    ShellResolutionPolicy(1.60, 0.01, 0.08, 0.01, 2.0),
    minimum_pair_cutoff=intermolecular_policy.maximum_distance_angstrom,
).analyze(crystal, context, chemistry.grammar)
molecular = MolecularAnalyzer(
    MolecularAnalysisPolicy(maximum_bond_rho=1.25)
).analyze(result)
intermolecular = IntermolecularContactAnalyzer(
    intermolecular_policy
).analyze(result, molecular)

This first slice reports symmetry-unique geometric contact orbits, exact molecule-to-molecule periodic relations, van der Waals distance evidence, and geometry-qualified hydrogen-bond candidates for explicit H or D atoms. It does not infer missing hydrogens. Named packing assemblies, voids, interaction energies, Hirshfeld surfaces, and reticular topology are deferred. Metal-organic fragments are not presented as ordinary molecular packing.

ContactAnalysisResult exposes pair orbits, chemically resolved contact orbits, oriented incidence orbits, coordination-shell alternatives, explicit status, diagnostics, configuration and provenance. Polyhedron orbits retain oriented periodic atom references, coordination number, occupancy-weighted ligand composition, convex-hull faces, bond-length statistics, the Baur distortion index, edge-angle population dispersion, volume, geometric centroid and centre offset.

The canonical face signature represents the complete vertex-edge-face incidence graph. Shape descriptors are not guessed for open or degenerate shells: unavailable values remain None and the reason is diagnostic. CrIStMa does not triangulate display meshes or define colours, visibility, selection, tables or motif-comparison policy; those are responsibilities of consuming applications.

Structural hierarchy

The hierarchy remains on the same finite symmetry quotient graph. No stage below consumes materialized contacts or an expanded atomic view:

units = StructuralUnitBuilder().build(result, polyhedra)
graph = StructuralGraphBuilder().build(result, polyhedra)
representation = StructuralRepresentationBuilder(selection_policy).build(graph)
connectivity = PeriodicConnectivityAnalyzer().analyze(representation)
blocks = StructuralBlockFinder().find(representation, connectivity)
rings = RingFinder().find(representation, blocks)

The results expose stable unit, connection, block and ring orbit identities. Periodic rank comes from exact affine cycle translations, not geometric heuristics. StructuralUnitGeometry records only calculated points, linear groups, planar polygons, or closed polyhedra. Rendering meshes, colours, visibility, tree grouping, matching and interactive comparison remain outside CrIStMa.

X-ray structure factors

The first scattering layer calculates forward neutral-atom X-ray amplitudes from a CrystalStructure and its generated ReflectionSet:

from cristma.crystallography import (
    SpaceGroupCatalog,
    SpaceGroupSettingResolutionStatus,
    resolve_space_group_setting,
)
from cristma.diffraction import StructureFactorCalculator, XRayScatteringContext

resolution = resolve_space_group_setting(
    crystal.space_group,
    SpaceGroupCatalog.default(),
)
if resolution.status is not SpaceGroupSettingResolutionStatus.RESOLVED:
    raise ValueError("the structure has no unique catalog setting")
setting = resolution.setting

factors = StructureFactorCalculator().calculate(
    structure=crystal,
    space_group=setting,
    reflections=reflection_set,
    context=XRayScatteringContext.default(),
)

Setting resolution compares the complete exact operation set in the reported fractional basis. It returns AMBIGUOUS or UNRESOLVED instead of selecting a setting from a Hermann–Mauguin symbol or space-group number alone. The diffraction calculators themselves still accept only a uniquely resolved SpaceGroupSetting.

The calculator expands independent sites with the supplied exact symmetry, deduplicates special positions, applies occupancies and isotropic displacement parameters, and returns F, |F|, and |F|² without multiplying by reflection multiplicity. The bundled f0(s) table covers neutral atoms H through Cf and does not require xraylib at runtime. Anisotropic displacement parameters and anomalous scattering are not evaluated directly in v1. When a source reports U_aniso together with U_iso_or_equiv, the calculator uses the reported equivalent isotropic value and returns an explicit warning. Without that value, the position is calculated with T=1 and the result carries an error diagnostic plus the affected site IDs instead of aborting the complete calculation.

This is forward crystallographic physics only. Experimental peak matching, similarity measures, R-factors, powder corrections, and phase identification belong to consuming applications or later independent layers.

Powder diffraction lines

The next layer groups Friedel mates and calculates a separate Bragg angle for every component of an explicit radiation spectrum:

from cristma.diffraction import (
    BraggBrentanoGeometry,
    PowderCorrectionCalculator,
    PowderLineCalculator,
    RadiationSpectrum,
)

powder_lines = PowderLineCalculator().calculate(
    structure_factors=factors,
    spectrum=RadiationSpectrum.lab_k_alpha("Cu"),
)

corrected = PowderCorrectionCalculator().calculate(
    powder_lines,
    BraggBrentanoGeometry(),
)

for line in corrected.lines_by_angle:
    print(line.two_theta_deg, line.corrected_line_intensity)

Packaged laboratory sources are selectable for Cr, Fe, Co, Cu, Mo, and Ag. Every preset retains Kα1 and Kα2 as separate lines, so their angular separation remains visible at high angles. A synchrotron wavelength is supplied explicitly:

spectrum = RadiationSpectrum.synchrotron(
    wavelength_angstrom=0.41328,
    source_id="beamline:my-experiment",
)
geometry = BraggBrentanoGeometry(
    perpendicular_polarization_fraction=0.98,
)

intrinsic_line_intensity contains only normalized radiation weight, crystallographic multiplicity, Friedel grouping, and |F|². The separate correction layer returns the Lorentz factor, polarization factor, and corrected_line_intensity for symmetric Bragg–Brentano reflection geometry. The default polarization fraction is 0.5, corresponding to unpolarized laboratory X-rays; synchrotron polarization must be provided explicitly. These are relative calculated intensities, not an absolute detector signal.

Preferred orientation, absorption, and comparison with experiment are not part of this line result. RadiationProbe already distinguishes X-rays from neutrons, but neutron powder intensities will only be enabled together with a separate nuclear scattering-length context; CrIStMa never substitutes X-ray atomic form factors for neutrons.

Calculated powder profile

A minimal final forward layer can place intrinsic or corrected powder lines on an explicit uniform grid. If no instrument calibration is available, the caller supplies one constant Gaussian FWHM:

from cristma.diffraction import (
    ConstantWidthProfile,
    PowderProfileCalculator,
    UniformTwoThetaGrid,
)

profile = PowderProfileCalculator(max_points=1_000_000).calculate(
    corrected,
    UniformTwoThetaGrid(5.0, 120.0, 0.01),
    ConstantWidthProfile(fwhm_deg=0.10),
)

An instrument profile stored by a consuming application can instead provide explicit GSAS-style continuous-wave U, V, W, X, and Y values:

from cristma.diffraction import TchProfile

instrument = TchProfile(u=U, v=V, w=W, x=X, y=Y)
profile = PowderProfileCalculator().calculate(
    corrected,
    grid,
    instrument,
    zero_shift_deg=zero_shift,
    d_spacing_scale=estimated_d_scale,
)

d_spacing_scale is an optional fast peak-position transform for search and screening workflows. Each radiation component is moved independently using Bragg's law with d_scaled = d * d_spacing_scale; instrument and phase-local widths are then evaluated at the moved angle, and zero_shift_deg is applied last. The transform deliberately retains the supplied line intensities and does not claim to recompute the structure, structure factors, multiplicities, or angle-dependent corrections. Its exact value is recorded in profile provenance.

CrIStMa has no built-in instrument preset and does not read refinement project files. Every peak kernel is area-normalized and evaluated only in a local window. The configurable max_points limit is checked before allocating the output array; an oversized request raises PowderProfileLimitError rather than returning a truncated scientific result.

An optional isotropic sample model adds phase-local coherent-domain size and microstrain broadening:

from cristma.diffraction import IsotropicSampleBroadening

sample = IsotropicSampleBroadening(
    crystallite_size_nm=80.0,
    microstrain=8.0e-4,
    scherrer_constant=0.9,
)
profile = PowderProfileCalculator().calculate(
    phase_lines,
    grid,
    instrument,
    sample_broadening=sample,
)

Each call describes one phase. Size is an isotropic Lorentzian Scherrer contribution, while microstrain is an isotropic Gaussian 4 * microstrain * tan(theta) contribution. They are combined with the explicit instrument components before the TCH pseudo-Voigt approximation.

The same forward calculation is available through one small facade when the intermediate results are still required for inspection:

from cristma.diffraction import (
    BraggBrentanoGeometry,
    ConstantWidthProfile,
    IsotropicSampleBroadening,
    PowderPatternCalculator,
    RadiationSpectrum,
    UniformTwoThetaGrid,
)

pattern = PowderPatternCalculator().calculate(
    crystal,
    setting,
    RadiationSpectrum.lab_k_alpha("Cu"),
    UniformTwoThetaGrid(5.0, 90.0, 0.02),
    ConstantWidthProfile(0.10),
    geometry=BraggBrentanoGeometry(),
    sample_broadening=IsotropicSampleBroadening(
        crystallite_size_nm=80.0,
        microstrain=8.0e-4,
    ),
)

The facade derives reciprocal coverage from the upper grid boundary and the shortest selected wavelength, then retains its ReflectionSet, StructureFactorSet, intrinsic lines, optional corrected lines, sampled profile, status, and provenance. Instrument broadening remains mandatory and explicit; sample broadening belongs only to the phase calculated by that call. The facade does not read experimental patterns, compare phases, or refine any parameter. Every radiation component uses its own wavelength, including K-alpha doublets. If the consuming application has no instrument calibration, the same sample model can be combined with ConstantWidthProfile; CrIStMa never invents an instrument setting. Anisotropic size/strain, preferred orientation, absorption, background, asymmetry, experimental matching, and refinement remain outside this minimal forward calculation.

Design principles

  • Physics before interface. Scientific meaning is not determined by a GUI or storage format.
  • One canonical model. Every reader produces the same structure types for downstream calculations.
  • Explicit assumptions. Policies, tolerances, limits, and incomplete searches are visible in inputs and results.
  • Traceable results. Symmetry images, reference data, transformations, and diagnostics retain provenance.
  • Composable tools. Calculators are independent and do not rely on a hidden current structure or global workflow.
  • Small runtime. The core depends only on Python and NumPy.

Beta status

0.1.0b1 was the first public beta. 0.1.0b2 added the first diffraction milestone, explicit crystal-chemistry result statuses, and stable symmetry-equivalent contact orbits. 0.1.0b3 keeps coordinate structures available when a reported anisotropic displacement tensor conflicts with site symmetry, and extends composition grammar to hydrogen-omitted organic and metal-organic structures. The local beta3 development line also adds neutral-atom X-ray structure factors with explicit scattering provenance. The 0.1.0b4 keeps a usable coordinate structure when an anisotropic ADP fails the final orbit-consistency check: it retains a reported U_iso_or_equiv when available, otherwise omits only that ADP, and returns a warning instead of rejecting the complete CIF. The published 0.1.0b5 release introduces orbit-first direct-space crystal chemistry: validated symmetry contexts, asymmetric-unit pair orbits, chemical contact orbits, oriented incidences, and multiplicity-weighted coordination-shell orbits without expanded contacts in the scientific pipeline. The published 0.1.0b6 unifies reference-cell atom-image identities across atomic_view(), contact materialization, polyhedra, and structural units. It also accepts symmetry-constrained cells within their componentwise reported precision, collapses redundant symmetry-expanded CIF atom rows conservatively, and preserves incomplete polyhedra when hull geometry is unusable. The local 0.1.0b7 development line adds orbit-first molecular bond and component analysis with explicit normalized-distance policy and exact periodic-rank classification. The current 0.1.0b9 development line adds the one-call powder-pattern facade while retaining every intermediate reciprocal result and keeping instrument and phase-local sample broadening explicit, plus bounded molecular rings, pi-system, pi-stacking, and explicit C-H/C-D...pi geometry. It also assembles these independently calculated interactions into an exact molecular packing quotient graph. The implemented scientific core is covered by automated tests and is ready for evaluation and integration. Until the first stable release, public APIs may still change when required to correct or clarify scientific contracts.

The current development version adds reciprocal metrics, bounded reflection generation, exact systematic absences, reciprocal symmetry orbits, crystallographic multiplicity, Friedel relations, neutral-atom structure factors, intrinsic multi-component powder lines, selectable X-ray sources, and Bragg–Brentano Lorentz–polarization corrections, plus minimal calculated profiles on explicit grids and optional phase-local isotropic size/microstrain broadening, to the published beta's structural I/O, symmetry, geometry, crystal chemistry, and topology layers. It does not calculate anisotropic sample broadening or corrections, neutron structure factors, experimental matching, or structure refinement.

Roadmap

Planned scientific layers are developed as independent milestones:

  1. energy-dependent and additional scattering contexts;
  2. additional powder geometries, sample corrections, and explicit instrument models;
  3. anisotropic sample broadening and neutron scattering;
  4. additional structural transforms, hierarchy and topology tools, and refinement built over the same forward calculations.

The roadmap describes direction, not a compatibility or release-date promise. CrIStMa will remain independent of any particular consuming application.

License and reference data

Original CrIStMa code is distributed under the permissive BSD-3-Clause license. It may be used in open-source, commercial, and closed-source software subject to the license notice requirements.

Bundled reference resources retain their own attribution and provenance:

  • space-group and Wyckoff data normalized from pinned spglib 2.7.0 resources under BSD-3-Clause;
  • Cordero covalent radii compiled from QCElemental resources under BSD-3-Clause;
  • Shannon radii compiled from a pinned pymatgen artifact under MIT;
  • neutral-atom X-ray form factors normalized from pinned xraylib 4.3.0 data under its BSD-style license, with EPDL97 recorded as the scientific source;
  • selected Crystallography Open Database fixtures under CC0/public-domain terms;
  • curated chemical-reference rules with their scientific literature recorded in the versioned resources.

Versions, commits, hashes, known provenance limitations, and redistribution requirements are listed in THIRD_PARTY_NOTICES.md.

Author

Artem B. Kuznetsov
GitHub

About

CrIStMa — Crystallographic Infrastructure for Structures and Materials. Beta · Python 3.11+ · NumPy-only scientific library.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages