Build a Box¶
Let's learn how to create and work with Box objects! A Box defines your simulation boundaries and periodic boundary conditions - essential for any molecular simulation.
What is a Box?¶
A Box in MolPy represents your simulation cell boundaries. You've got three options:
- Free: No boundaries (infinite system)
- Orthogonal: Rectangular box (the most common one)
- Triclinic: General parallelepiped (for fancy non-orthogonal cells)
Let's dive in:
In [1]:
Copied!
import molpy as mp
import molpy as mp
In [2]:
Copied!
# Create a 10x10x10 Angstrom cubic box
box = mp.Box.cubic(10.0)
box = mp.Box.orth([10.0, 20.0, 15.0])
print(f"Box: {box}")
print(f"Lengths: {box.lengths}")
print(f"Volume: {box.volume:.2f} ų")
# Create a 10x10x10 Angstrom cubic box
box = mp.Box.cubic(10.0)
box = mp.Box.orth([10.0, 20.0, 15.0])
print(f"Box: {box}")
print(f"Lengths: {box.lengths}")
print(f"Volume: {box.volume:.2f} ų")
Box: <Orthogonal Box: [10. 20. 15.]> Lengths: [10. 20. 15.] Volume: 3000.00 ų
Periodic Boundary Conditions¶
You can control periodic boundary conditions (PBC) for each axis:
In [3]:
Copied!
# Box with PBC only in x and y directions
box = mp.Box.cubic(10.0, pbc=[True, True, False])
print(f"PBC: {box.pbc}")
# Box with no periodic boundaries
free_box = mp.Box.cubic(10.0, pbc=[False, False, False])
print(f"Free box PBC: {free_box.pbc}")
# Box with PBC only in x and y directions
box = mp.Box.cubic(10.0, pbc=[True, True, False])
print(f"PBC: {box.pbc}")
# Box with no periodic boundaries
free_box = mp.Box.cubic(10.0, pbc=[False, False, False])
print(f"Free box PBC: {free_box.pbc}")
PBC: [ True True False] Free box PBC: [False False False]
Centered Boxes¶
You can create boxes centered at the origin:
In [4]:
Copied!
# Regular box (origin at [0, 0, 0])
box1 = mp.Box.cubic(10.0)
print(f"Origin: {box1.origin}")
print(f"Bounds: x=[{box1.xlo:.1f}, {box1.xhi:.1f}]")
# Centered box (origin at [-5, -5, -5])
box2 = mp.Box.cubic(10.0, central=True)
print(f"Origin: {box2.origin}")
print(f"Bounds: x=[{box2.xlo:.1f}, {box2.xhi:.1f}]")
# Regular box (origin at [0, 0, 0])
box1 = mp.Box.cubic(10.0)
print(f"Origin: {box1.origin}")
print(f"Bounds: x=[{box1.xlo:.1f}, {box1.xhi:.1f}]")
# Centered box (origin at [-5, -5, -5])
box2 = mp.Box.cubic(10.0, central=True)
print(f"Origin: {box2.origin}")
print(f"Bounds: x=[{box2.xlo:.1f}, {box2.xhi:.1f}]")
Origin: [0. 0. 0.] Bounds: x=[0.0, 10.0] Origin: [-5. -5. -5.] Bounds: x=[-5.0, 15.0]
Working with Box Properties¶
Access various box properties:
In [5]:
Copied!
box = mp.Box.orth([10.0, 20.0, 15.0])
print(f"Lengths: {box.lengths}")
print(f"Volume: {box.volume:.2f} ų")
print(f"Matrix:\n{box.matrix}")
print(f"Style: {box.style}")
print(f"PBC: {box.pbc}")
print(f"Origin: {box.origin}")
box = mp.Box.orth([10.0, 20.0, 15.0])
print(f"Lengths: {box.lengths}")
print(f"Volume: {box.volume:.2f} ų")
print(f"Matrix:\n{box.matrix}")
print(f"Style: {box.style}")
print(f"PBC: {box.pbc}")
print(f"Origin: {box.origin}")
Lengths: [10. 20. 15.] Volume: 3000.00 ų Matrix: [[10. 0. 0.] [ 0. 20. 0.] [ 0. 0. 15.]] Style: Style.ORTHOGONAL PBC: [ True True True] Origin: [0. 0. 0.]
Box Operations¶
You can scale boxes and perform other operations:
In [6]:
Copied!
# Scale a box
box = mp.Box.cubic(10.0)
scaled = box * 2.0 # or 2.0 * box
print(f"Original length: {box.lengths[0]:.1f} Å")
print(f"Scaled length: {scaled.lengths[0]:.1f} Å")
# Scale a box
box = mp.Box.cubic(10.0)
scaled = box * 2.0 # or 2.0 * box
print(f"Original length: {box.lengths[0]:.1f} Å")
print(f"Scaled length: {scaled.lengths[0]:.1f} Å")
Original length: 10.0 Å Scaled length: 20.0 Å
Using Boxes with Frames¶
Boxes are typically used with Frame objects to define simulation boundaries:
In [7]:
Copied!
# Create a box and frame
box = mp.Box.cubic(20.0)
# Create some atoms
atoms_data = {
"x": [0.0, 1.0, 2.0],
"y": [0.0, 0.0, 0.0],
"z": [0.0, 0.0, 0.0],
"element": ["C", "C", "C"],
"type": [1, 1, 1],
}
frame = mp.Frame(data={"atoms": atoms_data}, box=box)
print(f"Frame box: {frame.metadata['box']}")
print(f"Box volume: {frame.metadata['box'].volume:.2f} ų")
# Create a box and frame
box = mp.Box.cubic(20.0)
# Create some atoms
atoms_data = {
"x": [0.0, 1.0, 2.0],
"y": [0.0, 0.0, 0.0],
"z": [0.0, 0.0, 0.0],
"element": ["C", "C", "C"],
"type": [1, 1, 1],
}
frame = mp.Frame(data={"atoms": atoms_data}, box=box)
print(f"Frame box: {frame.metadata['box']}")
print(f"Box volume: {frame.metadata['box'].volume:.2f} ų")
Frame box: <Orthogonal Box: [20. 20. 20.]> Box volume: 8000.00 ų