Trajectory Class¶
Overview¶
The Trajectory
class manages molecular dynamics trajectory data, including particles, time information, and simulation box data. It serves as the primary container for time-series molecular simulation data.
Class Definition¶
Constructor¶
Trajectory()
¶
Creates an empty trajectory.
Example:
import smolsat
# Create empty trajectory
trajectory = smolsat.Trajectory()
print(f"Particles: {trajectory.num_particles()}") # 0
print(f"Frames: {trajectory.num_frames()}") # 0
Particle Management¶
add_particle(id, type, mass=1.0, type_name="")
→ Particle¶
Adds a new particle to the trajectory.
Parameters:
- id
(int): Unique particle identifier
- type
(int): Particle type identifier
- mass
(float): Particle mass (default: 1.0)
- type_name
(str): Human-readable type name (default: "")
Returns: New Particle object
Example:
trajectory = smolsat.Trajectory()
# Add different types of particles
hydrogen = trajectory.add_particle(0, 1, 1.0, "H")
carbon = trajectory.add_particle(1, 6, 12.0, "C")
oxygen = trajectory.add_particle(2, 8, 16.0, "O")
print(f"Added {trajectory.num_particles()} particles")
particle(index)
→ Particle¶
Retrieves a particle by index.
Parameters:
- index
(int): Particle index (0-based)
Returns: Particle object
Example:
# Access particles
first_particle = trajectory.particle(0)
print(f"Particle ID: {first_particle.id()}")
print(f"Particle type: {first_particle.type_name()}")
num_particles()
→ int¶
Returns the number of particles in the trajectory.
Time Information¶
add_time(time)
¶
Adds a time point to the trajectory.
Parameters:
- time
(float): Time value
Example:
# Add time points (e.g., every 0.001 time units)
for frame in range(1000):
trajectory.add_time(frame * 0.001)
time(frame)
→ float¶
Gets the time for a specific frame.
Parameters:
- frame
(int): Frame index
Returns: Time value
num_frames()
→ int¶
Returns the number of frames in the trajectory.
Box Information¶
add_box_size(box_size)
¶
Adds box dimensions for a frame.
Parameters:
- box_size
(Coordinate): Box dimensions
Example:
# Add box information (cubic box with side length 10)
box = smolsat.Coordinate(10.0, 10.0, 10.0)
for frame in range(num_frames):
trajectory.add_box_size(box)
box_size(frame)
→ Coordinate¶
Gets box dimensions for a specific frame.
Parameters:
- frame
(int): Frame index
Returns: Coordinate representing box dimensions
Type-Based Selection¶
particles_of_type(type_id)
→ List[Particle]¶
Gets all particles of a specific type.
Parameters:
- type_id
(int): Type identifier
Returns: List of particles
Example:
# Get all hydrogen atoms (type 1)
hydrogens = trajectory.particles_of_type(1)
print(f"Found {len(hydrogens)} hydrogen atoms")
# Get all carbon atoms (type 6)
carbons = trajectory.particles_of_type(6)
particles_of_type_name(type_name)
→ List[Particle]¶
Gets all particles with a specific type name.
Parameters:
- type_name
(str): Type name
Returns: List of particles
Example:
# Get particles by name
waters = trajectory.particles_of_type_name("O") # Oxygen in water
polymers = trajectory.particles_of_type_name("C") # Carbon backbone
Molecule Management¶
add_molecule(particle_ids)
→ Molecule¶
Creates a molecule from a list of particle IDs.
Parameters:
- particle_ids
(List[int]): List of particle IDs
Returns: New Molecule object
Example:
# Create water molecule (H-O-H)
water_ids = [0, 1, 2] # H, O, H particle IDs
water_molecule = trajectory.add_molecule(water_ids)
# Create polymer chain
polymer_ids = list(range(10, 50)) # Particles 10-49
polymer_chain = trajectory.add_molecule(polymer_ids)
molecule(index)
→ Molecule¶
Gets a molecule by index.
Parameters:
- index
(int): Molecule index
Returns: Molecule object
num_molecules()
→ int¶
Returns the number of molecules in the trajectory.
Utility Methods¶
clear()
¶
Removes all data from the trajectory.
Example:
Usage Examples¶
Creating a Simple Trajectory¶
import smolsat
import numpy as np
# Create trajectory
trajectory = smolsat.Trajectory()
# Add particles
num_particles = 100
for i in range(num_particles):
trajectory.add_particle(i, 1, 1.0, "A")
# Add time and box information
num_frames = 1000
dt = 0.001
box_size = smolsat.Coordinate(10.0, 10.0, 10.0)
for frame in range(num_frames):
trajectory.add_time(frame * dt)
trajectory.add_box_size(box_size)
# Add position data to particles
np.random.seed(42)
for i in range(num_particles):
particle = trajectory.particle(i)
# Random walk trajectory
pos = np.random.uniform(0, 10, 3)
for frame in range(num_frames):
# Add some random motion
pos += np.random.normal(0, 0.1, 3)
position = smolsat.Coordinate(pos[0], pos[1], pos[2])
particle.add_position(position)
print(f"Created trajectory: {trajectory.num_particles()} particles, {trajectory.num_frames()} frames")
Loading and Processing Trajectory Data¶
# Load trajectory from file
trajectory = smolsat.load_trajectory("simulation.xyz")
# Get trajectory information
print(f"Trajectory contains:")
print(f" Particles: {trajectory.num_particles()}")
print(f" Frames: {trajectory.num_frames()}")
print(f" Time range: {trajectory.time(0):.3f} - {trajectory.time(trajectory.num_frames()-1):.3f}")
# Analyze particle types
for type_id in range(1, 10): # Check types 1-9
particles = trajectory.particles_of_type(type_id)
if particles:
print(f" Type {type_id}: {len(particles)} particles")
# Create molecules (example: water molecules)
# Assuming particles 0,1,2 = first water, 3,4,5 = second water, etc.
num_waters = trajectory.num_particles() // 3
for i in range(num_waters):
water_ids = [i*3, i*3+1, i*3+2]
trajectory.add_molecule(water_ids)
print(f"Created {trajectory.num_molecules()} water molecules")
Trajectory Analysis Preparation¶
# Get specific particles for analysis
solvent_particles = trajectory.particles_of_type_name("SOL")
polymer_particles = trajectory.particles_of_type_name("POL")
# Create system for analysis
system = smolsat.System(trajectory, periodic_boundaries=True)
# Perform analysis on specific particle groups
if len(solvent_particles) > 0:
msd_analysis = smolsat.MeanSquareDisplacement(system, solvent_particles)
msd_analysis.compute()
print("Solvent MSD analysis completed")
if len(polymer_particles) > 0:
rg_analysis = smolsat.RadiusOfGyration(system, polymer_particles)
rg_analysis.compute()
print("Polymer radius of gyration analysis completed")
Working with Molecules¶
# Create complex molecular system
trajectory = smolsat.Trajectory()
# Add atoms for a polymer chain
chain_length = 20
for i in range(chain_length):
trajectory.add_particle(i, 1, 12.0, "C") # Carbon backbone
# Create the polymer molecule
polymer_ids = list(range(chain_length))
polymer = trajectory.add_molecule(polymer_ids)
# Add solvent molecules
solvent_start = chain_length
num_solvents = 100
for i in range(num_solvents):
solvent_id = solvent_start + i
trajectory.add_particle(solvent_id, 2, 18.0, "SOL")
# Each solvent is its own molecule
trajectory.add_molecule([solvent_id])
print(f"System contains:")
print(f" Total particles: {trajectory.num_particles()}")
print(f" Molecules: {trajectory.num_molecules()}")
print(f" Polymer size: {polymer.num_particles()} particles")
Integration with Analysis¶
The Trajectory class integrates seamlessly with SMolSAT analysis methods:
# Create trajectory
trajectory = smolsat.create_example_trajectory(num_particles=200, num_frames=5000)
# Quick analysis using high-level functions
lag_times, msd_values = smolsat.quick_msd(trajectory)
times, rg_values = smolsat.quick_rg(trajectory)
# Advanced analysis with specific particle selection
system = smolsat.System(trajectory, periodic_boundaries=True)
selected_particles = trajectory.particles_of_type(1)[:50] # First 50 type-1 particles
msd_analysis = smolsat.MeanSquareDisplacement(system, selected_particles)
msd_analysis.compute()
See Also¶
- Particle - Individual particle data management
- Molecule - Multi-particle molecular entities
- System - System-level analysis capabilities
- Data Loading Utilities - Loading trajectory data from files