CoordinationShellTarget

First-shell coordination targets extracted from a reference crystal via Gaussian-mixture decomposition of each species-pair g(r) and of each rooted-angle distribution. The result drives the bond-length, angle, and repulsion springs in tricor.Supercell.generate() / tricor.Supercell.shell_relax().

class tricor.CoordinationShellTarget(atoms, label, species, species_labels, phi_num_bins, phi_edges, phi, phi_deg, angle_index, angle_lookup, pair_hard_min, pair_inner, pair_peak, pair_sigma, pair_outer, pair_mask, coordination_target, coordination_std, angle_target, angle_pair_mass_target, angle_mode_deg, angle_enabled_mask, motif_center_species, motif_neighbor_species, motif_neighbor_vectors, max_pair_outer, max_pair_outer_by_center, summary)[source]

Bases: object

Species-aware first-shell coordination targets extracted from a crystal.

Construction

Parameters:
classmethod from_atoms(atoms, *, phi_num_bins=72, shell_hist_step=0.05, shell_smooth_sigma_bins=1.2, extract_cutoff=None, auto_filter_lattice_artifacts=True, label=None)[source]

Extract first-shell coordination, distance, and angle targets from a reference crystal.

For every species pair in atoms the method fits the first peak of the radial pair distribution g(r) — its inner edge, peak position, Gaussian width, and outer edge — and counts the average number of neighbours each centre atom has within that window. For every triplet (centre, neighbour-A, neighbour-B) species combination it builds a histogram of bond angles ranged 0–180° using phi_num_bins bins, identifying the dominant angle mode. All quantities are stored as 2-D / 3-D numpy arrays indexed by species index in species.

Parameters:
  • atoms (ase.Atoms) – Reference crystal whose g(r) and bond-angle distributions define the target geometry. Must be a periodic cell with at least one neighbour pair within extract_cutoff (auto if None).

  • phi_num_bins (int, optional) – Number of bins used to discretise the [0, 180°] bond-angle axis. Default 72 (2.5° per bin). Higher values sharpen the angle target but slow down the angle measurement loop in Supercell.measure_g3().

  • shell_hist_step (float, optional) – Bin width (Å) of the per-pair radial histogram used to locate the first peak. Default 0.05 Å.

  • shell_smooth_sigma_bins (float, optional) – Gaussian smoothing width (in bins) applied to the radial histogram before peak detection. Default 1.2 bins.

  • extract_cutoff (float, optional) – Maximum centre-neighbour distance (Å) considered when building the neighbour list. If None the routine picks min(default, max(3.8 × NN, NN + 2)) based on the inferred nearest-neighbour distance.

  • auto_filter_lattice_artifacts (bool, optional) – If True (default), zero out coordination_target for species pairs that represent lattice artefacts rather than real chemical bonds. A pair (i, j) is kept only when pair_peak[i, j] is the smallest enabled peak in either row i or column j. This automatically silences the second-shell Si-Si / O-O springs in SiO2, the Sr-Sr / Ti-Ti / O-O / Sr-Ti springs in SrTiO3, etc. Set to False to keep every extracted pair (pre-2026 behaviour); callers can also override the filter by chaining with_bonded_species_pairs() after extraction.

  • label (str, optional) – Free-text identifier carried along on the returned target (used in plot legends and HTML viewer titles). Default uses the chemical formula of atoms.

Returns:

Frozen dataclass populated with every per-species and per-triplet field listed in the class header (coordination_target, pair_peak, pair_inner, angle_target, angle_mode_deg, etc.). All ndarray fields are pre-symmetrised over species pairs and the angle-enabled mask is initialised to True everywhere.

Return type:

CoordinationShellTarget

Notes

Single-element references (Si, Cu, …) produce a 1×1 coordination matrix and one self-self angle channel. Multi-element references (SiO₂, SrTiO₃, …) populate every cross-pair entry — see with_cross_species_bonds_only() and with_bonded_species_pairs() for masking helpers when only a subset of pairs represents real chemical bonds.

Examples

>>> from ase.build import bulk
>>> import tricor as tc
>>> atoms = bulk("Si", "diamond", a=5.431)
>>> shell = tc.CoordinationShellTarget.from_atoms(atoms,
...                                                phi_num_bins=90)
>>> shell.coordination_target  # 4 NN per Si
array([[4.]])
>>> float(shell.pair_peak[0, 0])
2.352
classmethod from_targets(targets, *, cross_pair_peak=None, cross_pair_outer_scale=1.15, label=None)[source]

Stack multiple shell targets into one with a widened species axis.

Used for blended materials where atoms share an atomic number but want different local coordination (e.g. graphite sp² + diamond sp³ carbon). Each input target contributes a virtual species slot per element of its species array; the composite target’s species is the concatenation of all inputs, with species_labels rewritten as f"{key}_{element}".

Cross-target pairs default to:

  • coordination_target = 0 (no bonds form across virtual species boundaries; the repulsion term still keeps them apart),

  • pair_peak = mean(peak_a, peak_b) unless overridden by cross_pair_peak,

  • pair_outer = max(outer_a, outer_b) * cross_pair_outer_scale,

  • pair_hard_min / pair_inner pro-rated from the two source values.

Cross-target triplets (any of the three species drawn from a different source than the other two) get coordination_target = 0 and zero angle_mode_deg - the relaxer will never enumerate these triplets because no such bonds form.

Parameters:
  • targets (dict[str, CoordinationShellTarget]) – Mapping {key: CoordinationShellTarget}. Insertion order defines the virtual-species order.

  • cross_pair_peak (dict[tuple[str, str], float] | None) – Optional overrides for pair_peak between elements drawn from different source targets. Keys are (key_a, key_b) with symbol lookup done via atomic_numbers when pair contains non-tuple element labels.

  • cross_pair_outer_scale (float) – Multiplier applied to the larger of the two source pair_outer values when populating cross-target entries.

  • label (str | None) – Optional label; defaults to "composite(" + keys + ")".

Return type:

CoordinationShellTarget

Modifiers

with_cross_species_bonds_only()[source]

Return a copy where same-species coordination_target entries are zeroed.

Useful for network-former compounds such as SiO₂ where only cross-species pairs (Si-O) are real chemical bonds; the same-species “shell” peaks (Si-Si, O-O) come from the second coordination shell through the bridging atom and should not be treated as bonds by Supercell.shell_relax() (which would otherwise install spurious angle springs on triplets like Si-Si-Si or O-O-O whose angle_mode_deg is just a geometric artefact of the reference sampling, not a physical target).

Returns:

New target whose coordination_target diagonal is zeroed (off-diagonal cross-species entries preserved). The original target is unmodified.

Return type:

CoordinationShellTarget

with_bonded_species_pairs(pairs)[source]

Return a copy whose coordination_target is zero everywhere except for the listed species pairs.

Useful for materials with spectator ions: perovskites like SrTiO₃ want only Ti-O bonds considered by Supercell.shell_relax(), since Sr-O, Sr-Ti, O-O, Ti-Ti, etc. would either install spurious angle springs (angle_mode_deg is a geometric artefact for non-bond triplets) or pin atoms via bond springs to distances that are really second-shell separations, not chemical bonds.

Parameters:

pairs (list of tuple of str) – Each (symbol_a, symbol_b) pair is treated symmetrically — both directions in the coordination_target matrix are preserved. Pairs whose symbols don’t appear in self.species_labels are silently skipped.

Returns:

A new CoordinationShellTarget (the original is left unmodified) whose coordination_target keeps only the listed species-pair entries; every other slot is zeroed so Supercell.shell_relax() won’t try to enforce bonds there.

Return type:

CoordinationShellTarget

Examples

# SrTiO3: preserve only TiO6 octahedra
st.with_bonded_species_pairs([('Ti', 'O')])

# SiO2: equivalent to ``with_cross_species_bonds_only`` for a
# binary, but explicit about what a bond is
st.with_bonded_species_pairs([('Si', 'O')])
with_angle_triplets(triplets)[source]

Return a copy whose angle-spring mask is enabled only for the listed triplet types; all other angle springs are disabled.

Each triplet is (centre_symbol, neighbour_1_symbol, neighbour_2_symbol); both (n1, n2) and (n2, n1) are enabled automatically. Bond-distance springs are untouched - only the angle springs installed during shell_relax are filtered.

Useful for multi-modal shells where the extracted angle_mode_deg picks one peak of a bimodal / quadrimodal distribution; enforcing it would strain the other modes. SrTiO₃’s SrO₁₂ cuboctahedron (O-Sr-O angles at 60°/90°/120°/180°) is the canonical example.

Parameters:

triplets (list of tuple of str) – Each (centre, n1, n2) triplet enables the angle-spring term for that combination of species. Ordering of n1 and n2 is symmetrised internally.

Returns:

New target whose angle_enabled_mask is True only for the listed triplets; every other triplet’s angle spring is silenced.

Return type:

CoordinationShellTarget

Examples

# Keep Ti-centered 90° and linear O-Ti-Ti 180° angle
# springs; silence every Sr-centered or Sr-in-triplet
# angle spring.
st.with_angle_triplets([
    ('Ti', 'O', 'O'),
    ('O',  'Ti', 'Ti'),
])
without_angle_triplets(triplets)[source]

Return a copy with the angle mask disabled for the listed triplets.

Inverse of with_angle_triplets(): starts from the current angle_enabled_mask and turns OFF the listed triplets, leaving every other triplet’s angle spring intact.

Parameters:

triplets (list of tuple of str) – Each (centre, n1, n2) triplet disables the angle spring for that species combination.

Returns:

New target whose angle_enabled_mask matches the original except the listed triplets are now False.

Return type:

CoordinationShellTarget

Helpers

property pair_labels: list[str]

Human-readable species-pair labels for every present pair.

Returns:

One "<centre>-<neighbour>" string per (centre, neighbour) slot in self.pair_mask that is True. Order matches the row-major flatten of the species table (centre, neighbour) — useful for legend labels in multi-pair g(r) plots.

Return type:

list of str

property angle_labels: list[str]

Human-readable rooted-angle labels for every triplet channel.

Returns:

One "<n1>-<centre>-<n2>" string per row of self.angle_index. Useful for labelling angle-channel histograms or filtering the per-triplet output of Supercell.measure_g3().

Return type:

list of str

Restricting the bond graph

In multi-element compounds only a subset of species pairs represent actual chemical bonds (e.g. Si-O in silica; Ti-O and Sr-O in perovskites) — the other pairs’ first-shell peaks are lattice separations through a bridging atom, and relaxing against them can destroy the coordination geometry. from_atoms zeroes those lattice-artefact pairs automatically (auto_filter_lattice_artifacts=True): any pair whose pair_peak is not the smallest in either its row or column is excluded. Two helpers set the bond graph explicitly when the automatic rule is not what you want:

# SiO2: only Si-O is a real bond (equivalent to the two-species helper)
st = tc.CoordinationShellTarget.from_atoms(atoms, phi_num_bins=90)
st = st.with_cross_species_bonds_only()

# SrTiO3: both Ti-O and Sr-O are real bonds.  The SrO12 cuboctahedron
# is multi-modal (60°/90°/120°/180°) so Sr-centered angle springs
# would strain the other modes; mask them out but keep the Ti-O
# distance springs intact.
st = (
    tc.CoordinationShellTarget.from_atoms(atoms, phi_num_bins=90)
    .with_bonded_species_pairs([('Ti', 'O'), ('Sr', 'O')])
    .with_angle_triplets([('Ti', 'O', 'O'), ('O', 'Ti', 'Ti')])
)

Masking angle springs (multi-modal shells)

Some coordination shells are multi-modal: the single angle_mode_deg peak that from_atoms extracts is just the tallest bar of a distribution with several physically valid modes. The canonical example is the 12-coordinated cuboctahedron (Cu FCC, SrO₁₂ in SrTiO₃) whose angle distribution sits at 60° / 90° / 120° / 180° simultaneously, so enforcing any one mode distorts the others.

Two helpers operate on the angle_enabled_mask field:

  • with_angle_triplets(triplets): whitelist; enable angle springs only for the listed triplet types.

  • without_angle_triplets(triplets): blacklist; disable angle springs for the listed triplets, keep the rest.

Bond-distance springs are unaffected; masking only controls the angle force term. For copper, the whole thing is replaced with angle_weight=0.0 in the regime presets, but for mixed compounds like SrTiO₃ you want 90° preserved on the TiO₆ octahedron while silencing the Sr-centered cuboctahedron:

st.with_angle_triplets([
    ('Ti', 'O', 'O'),    # O-Ti-O at 90° (octahedral)
    ('O',  'Ti', 'Ti'),  # Ti-O-Ti at 180° (linear backbone)
])

Blending two reference crystals

For materials with a controllable phase mix (sp²/sp³ carbon; SiO₂ / Si₃N₄ nitride-silica blends; etc.) extract one shell target per chemistry and combine them with from_targets:

shell_sp2 = tc.CoordinationShellTarget.from_atoms(atoms_graphite, phi_num_bins=90)
shell_sp3 = tc.CoordinationShellTarget.from_atoms(atoms_diamond,  phi_num_bins=90)
shell_target = tc.CoordinationShellTarget.from_targets(
    {"sp2": shell_sp2, "sp3": shell_sp3},
)

The composite target holds virtual species (e.g. sp2_C at index 0, sp3_C at index 1): both atomic number 6, but with distinct coordination_target rows (3 vs 4), pair_peak (1.42 vs 1.54 Å), and angle_mode_deg (120° vs 109.5°). Each atom’s virtual species is assigned at grain-build time via Supercell.generate(..., grain_sources=[...]) (see Carbon example); the relaxer then pulls each atom toward the geometry of its source crystal.