Skip to content

System Building

FBTK automates the creation of initial structures (unit cells), which is often the first bottleneck in molecular simulation.

Built-in 3D Structure Generation (SMILES to 3D)

Section titled “Built-in 3D Structure Generation (SMILES to 3D)”

FBTK features a native Rust engine to generate 3D coordinates directly from SMILES strings. It produces chemically reasonable initial structures in two steps without requiring RDKit:

  1. VSEPR Theory: Determines initial bond angles and stereochemistry based on Valence Shell Electron Pair Repulsion theory.
  2. UFF Optimization: Rapidly relaxes bond lengths and strain using the Universal Force Field (UFF).

This allows you to create 3D templates ready for MD simulation from just a single line of text.


The standard workflow for building a unit cell with a target density using SMILES strings.

import fbtk
# 1. Initialize the builder
builder = fbtk.Builder(density=0.8)
# 2. Create a molecule template from SMILES and add it with a count
# (3D generation via VSEPR + UFF is executed automatically)
water = fbtk.Molecule.from_smiles("O", name="WAT")
builder.add_molecule(water, count=500)
# 3. Build the system
system = builder.build()
# 4. Global relaxation to resolve overlaps (verbose=True by default)
system.relax()
# 5. Save the result
system.to_file("system.mol2")

When importing molecules from files (.mol or .mol2), the coordinates may not be ideal. You can refine the geometry of a single molecule before adding it to the system.

# Load from a file (which may have unoptimized coordinates)
mol = fbtk.Molecule.from_file("raw_structure.mol")
# Refine the structure standalone to ensure chemical correctness
mol.relax()
# Add the refined molecule to the builder
builder.add_molecule(mol, count=100)

You can easily build systems containing multiple types of molecules, such as solvents and solutes.

import fbtk
builder = fbtk.Builder(box_size=[40, 40, 40])
# Add multiple types of small molecules
water = fbtk.Molecule.from_smiles("O", name="WAT")
ethanol = fbtk.Molecule.from_smiles("CCO", name="EtOH")
builder.add_molecule(water, count=800)
builder.add_molecule(ethanol, count=200)
system = builder.build()

FBTK provides high-speed generation of polymer chains from monomer SMILES strings.

Include * (asterisk) in the SMILES string to automatically specify connection sites.

# '*' are connection sites. Adjacent hydrogens are automatically removed.
builder.add_polymer(
name="PS",
smiles="*C(C*)c1ccccc1",
count=10,
degree=20
)

Specify the indices of the heavy atoms involved in polymerization (0-indexed).

# Use the 0th Carbon (Head) and 1st Carbon (Tail) as connection sites
builder.add_polymer(
name="PS",
smiles="CCc1ccccc1",
count=10,
degree=20,
head=0,
tail=1
)

You can control the stereochemical arrangement (tacticity) of the polymer chain using the tacticity parameter. FBTK automatically determines the side-chain orientation using a center-of-mass analysis and applies mirroring to repeating units.

Supported values:

  • "isotactic" (Default): All units have the same orientation.
  • "syndiotactic": Orientations alternate between adjacent units.
  • "atactic": Orientations are assigned randomly.
# Generate Syndiotactic Polystyrene
builder.add_polymer(
name="PS-syn",
smiles="*C(C*)c1ccccc1",
count=10,
degree=50,
tacticity="syndiotactic"
)

If you want to create a single polymer chain as a Molecule object (e.g., for saving to a .mol file), use Molecule.from_polymer().

monomer = fbtk.Molecule.from_smiles("*C(C*)c1ccccc1", name="PS")
# Create a 20-mer Atactic chain
chain = fbtk.Molecule.from_polymer(monomer, degree=20, tacticity="atactic")
# Save to a file without unit cell information
chain.to_file("ps_chain.mol")

Placement Mechanism (Collision-aware Placement)

Section titled “Placement Mechanism (Collision-aware Placement)”

FBTK uses a robust grid-based algorithm to place molecules in the unit cell while minimizing initial overlaps. This is critical for preventing “interlocked” ring structures (e.g., benzene rings threading through each other) and ensuring a stable start for structural relaxation.

  1. Grid Generation: FBTK calculates an optimal 3D grid based on the number of molecules and the box size.
  2. Spatial Search: For each molecule, FBTK identifies a candidate grid point. If a collision is detected, it tries up to 15 different grid locations.
  3. Rotation Search: At each candidate location, the molecule is assigned a random 3D orientation. If a collision is detected, it retries with up to 8 different random rotations.
  4. Collision Detection: Collisions are checked between heavy atoms (non-hydrogen) using a 2.5 Å threshold, accounting for Periodic Boundary Conditions (PBC).
  5. Fallback: If no collision-free spot is found after 120 attempts (15 locations × 8 rotations), the molecule is placed at the first available grid point, and a warning is issued.

If you see a message like Warning: Possible overlap detected for molecule X (Name), it means the system is very dense, and FBTK could not find a completely collision-free spot for that molecule.

While the subsequent system.relax() (UFF optimization) is highly effective at resolving these overlaps, extremely high-density systems may remain unstable. If relaxation fails or the final energy is excessively high, consider:

  • Lowering the target density
  • Increasing the box size
  • Performing more relaxation steps (system.relax(steps=2000))