Python API

Quick API

import autofragment as af

tree = af.partition_xyz("water64.xyz", n_fragments=4)
tree.to_json("partitioned.json")

for frag in tree.fragments:
    print(f"Fragment: {frag.id}, atoms: {len(frag.symbols)}")

Partitioner objects

import autofragment as af

partitioner = af.MolecularPartitioner(
    n_fragments=4,
    method="kmeans",  # or "kmeans_constrained" with pip install autofragment[balanced]
)

system = af.io.read_xyz("water64.xyz")
tree = partitioner.partition(system)

# If you need isolated molecules:
molecules = af.io.read_xyz_molecules("water64.xyz")

Tiered (Hierarchical) Partitioning

For large systems, tiered partitioning groups molecules into primary fragments, then sub-partitions each into secondary (and optionally tertiary) fragments:

import autofragment as af

# 2-tier: 4 primary fragments, each with 4 sub-fragments
partitioner = af.MolecularPartitioner(
    tiers=2, n_primary=4, n_secondary=4, method="kmeans"
)
system = af.io.read_xyz("water64.xyz")
tree = partitioner.partition(system)

print(f"Primary fragments: {tree.n_primary}")
print(f"Total fragments: {tree.n_fragments}")  # 4 + 16 = 20
print(f"Hierarchical: {tree._is_hierarchical}")

for pf in tree.fragments:
    print(f"  {pf.id}: {len(pf.fragments)} sub-fragments")
    for sf in pf.fragments:
        print(f"    {sf.id}: {sf.n_atoms} atoms")

3-Tier Partitioning

partitioner = af.MolecularPartitioner(
    tiers=3, n_primary=2, n_secondary=2, n_tertiary=2, method="kmeans"
)
tree = partitioner.partition(system)
# Hierarchy: PF1 -> PF1_SF1 -> PF1_SF1_TF1

Seeding Strategies

Control k-means initialization with seeding strategies:

# Global seeding strategy
partitioner = af.MolecularPartitioner(
    tiers=2, n_primary=4, n_secondary=4,
    method="kmeans", init_strategy="pca"
)

# Per-tier overrides
partitioner = af.MolecularPartitioner(
    tiers=2, n_primary=4, n_secondary=4,
    method="kmeans",
    init_strategy="pca",             # default for all tiers
    init_strategy_secondary="radial" # override for secondary tier
)

Available strategies: "halfplane", "pca", "axis", "radial".

Quick API (Tiered)

tree = af.partition_xyz(
    "water64.xyz", tiers=2, n_primary=4, n_secondary=4
)
tree.to_json("tiered.json")

Topology-Aware Selection

Use reusable neighborhood growth around seed atoms for QM/MM or broader partitioning workflows.

from autofragment.partitioners import (
    QMMMPartitioner,
    TopologySelection,
)

system = af.io.read_pdb("protein.pdb")

qm_selection = TopologySelection(
    seed_atoms={10, 11, 12},
    mode="graph",        # or "euclidean"
    hops=2,
    layers=2,
    k_per_layer=8,
    expand_residues=True,
    bond_policy="infer", # or "strict"
)

partitioner = QMMMPartitioner(qm_selection=qm_selection, buffer_radius=5.0)
result = partitioner.partition(system)

print(len(result.qm_atoms), len(result.buffer_atoms), len(result.mm_atoms))

Molecular Topology Refinement

MolecularPartitioner can optionally refine cluster assignments using topology overlap around representative molecules.

from autofragment.partitioners import MolecularPartitioner

partitioner = MolecularPartitioner(
    n_fragments=8,
    method="kmeans_constrained",  # requires pip install autofragment[balanced]
    topology_refine=True,
    topology_mode="graph",
    topology_hops=1,
    topology_bond_policy="infer",
)

tree = partitioner.partition(af.io.read_xyz("water64.xyz"))

Rules Engine

Use the rules engine to control which bonds can be broken:

import autofragment as af
from autofragment.rules import (
    RuleEngine,
    RuleAction,
    AromaticRingRule,
    DoubleBondRule,
    PeptideBondRule,
)
from autofragment.core.types import ChemicalSystem

# Isolated molecules for rules evaluation
molecules = af.io.read_xyz_molecules("water64.xyz")

# Create an engine with common rules
engine = RuleEngine([
    AromaticRingRule(),      # Never break aromatic rings (CRITICAL priority)
    DoubleBondRule(),        # Never break double/triple bonds (CRITICAL)
    PeptideBondRule(),       # Prefer keeping peptide bonds (HIGH)
])

# Create a chemical system from isolated molecules (explicit boundary)
system = ChemicalSystem.from_molecules(molecules)

# Evaluate a specific bond
action = engine.evaluate_bond((0, 1), system)
print(f"Bond (0,1) action: {action}")

# Get all breakable bonds (action != MUST_NOT_BREAK)
breakable = engine.get_breakable_bonds(system)
print(f"Breakable bonds: {len(breakable)}")

# Get preferred break points (action == PREFER_BREAK)
preferred = engine.get_preferred_breaks(system)

Configurable Biological Rules

Biological rules accept custom actions:

from autofragment.rules import PeptideBondRule, DisulfideBondRule, RuleAction

# Traditional FMO: keep peptide bonds, break at alpha carbon
engine = RuleEngine([
    PeptideBondRule(rule_action=RuleAction.PREFER_KEEP),
])

# Residue-based: break at peptide bonds
engine = RuleEngine([
    PeptideBondRule(rule_action=RuleAction.PREFER_BREAK),
])

# Allow breaking of disulfide bridges
engine = RuleEngine([
    DisulfideBondRule(rule_action=RuleAction.ALLOW),
])

See the Rules Documentation for complete details.