OpenMC Guide
Geometry Basics
The Building Block Approach
OpenMC uses constructive solid geometry (CSG) where you build complex shapes by combining simple surfaces with boolean operations. Think of it like building with digital blocks - surfaces divide space into regions, and you select which regions to fill with materials.
Every surface splits 3D space into two regions: positive (outside) and negative (inside). The key insight is learning to combine these regions logically to create the shapes you need.
import openmc
# Surface divides space into two regions
cylinder = openmc.ZCylinder(r=0.5)
# Boolean operators combine regions
inside_cylinder = -cylinder # Negative side (inside)
outside_cylinder = +cylinder # Positive side (outside)
# Note: + is often omitted, so 'cylinder' means +cylinderEssential Surface Types
Start with these fundamental surfaces that cover most nuclear engineering applications:
# Cylinders (for pins, rods, pipes)
fuel_surface = openmc.ZCylinder(r=0.4096) # Cylinder along z-axis
pipe = openmc.XCylinder(r=2.5) # Cylinder along x-axis
# Planes (for boundaries, flat surfaces)
centerline = openmc.XPlane(0.0) # Plane at x=0
top = openmc.ZPlane(365.76) # Plane at z=365.76 cm
# Spheres (for particles, pellets)
pellet = openmc.Sphere(r=0.1) # Sphere at origin
# Rectangular regions (for assemblies, lattices)
box = openmc.rectangular_prism(2.0, 2.0) # 2×2 cm square (helper function)Creating Cells with Boolean Logic
Cells are regions of space filled with material or left void. You define them by combining surface regions with logical operators.
# Example: Fuel pin with cladding
fuel_outer = openmc.ZCylinder(r=0.4096)
clad_outer = openmc.ZCylinder(r=0.4750)
# Define regions using boolean operations
fuel_region = -fuel_outer # Inside fuel cylinder
clad_region = +fuel_outer & -clad_outer # Between fuel and clad
water_region = +clad_outer # Outside clad
# Create cells by filling regions
fuel_cell = openmc.Cell(fill=fuel_material, region=fuel_region)
clad_cell = openmc.Cell(fill=clad_material, region=clad_region)
water_cell = openmc.Cell(fill=water_material, region=water_region)The logical operators work intuitively: & means "and" (intersection), | means "or" (union), and ~ means "not" (complement).
Boundary Conditions
Surface boundary conditions control what happens when particles reach model edges:
# Common boundary types
vacuum_boundary = openmc.ZPlane(100, boundary_type='vacuum') # Particles escape
reflect_boundary = openmc.ZPlane(-100, boundary_type='reflective') # Particles reflect
periodic_left = openmc.XPlane(-10, boundary_type='periodic') # Particles wrap around
periodic_right = openmc.XPlane(10, boundary_type='periodic')
# For infinite lattice problems, use reflective boundaries
# For shielding problems, use vacuum boundaries
# For reactor cores, mix reflective (sides) and vacuum (top/bottom)Working Example: Pin Cell
Here's a complete pin cell geometry that demonstrates these concepts:
import openmc
# Define surfaces
fuel_radius = 0.4096
clad_radius = 0.4750
pitch = 1.26
fuel_outer = openmc.ZCylinder(r=fuel_radius)
clad_outer = openmc.ZCylinder(r=clad_radius)
# Square boundary with reflective conditions
left = openmc.XPlane(-pitch/2, boundary_type='reflective')
right = openmc.XPlane(pitch/2, boundary_type='reflective')
bottom = openmc.YPlane(-pitch/2, boundary_type='reflective')
top = openmc.YPlane(pitch/2, boundary_type='reflective')
# Define regions
fuel_region = -fuel_outer
clad_region = +fuel_outer & -clad_outer
water_region = +clad_outer & +left & -right & +bottom & -top
# Create cells (materials defined elsewhere)
fuel_cell = openmc.Cell(fill=fuel, region=fuel_region)
clad_cell = openmc.Cell(fill=clad, region=clad_region)
water_cell = openmc.Cell(fill=water, region=water_region)
# Combine into universe and geometry
universe = openmc.Universe(cells=[fuel_cell, clad_cell, water_cell])
geometry = openmc.Geometry(universe)Common Mistakes
Avoid these frequent geometry errors:
# Wrong: Missing boolean operators
region = surf1 surf2 # This doesn't work
# Correct: Explicit operators
region = +surf1 & +surf2 # Intersection
region = +surf1 | +surf2 # Union
# Wrong: Forgetting boundary conditions for finite geometry
boundary = openmc.ZPlane(100) # Particles will be lost
# Correct: Specify boundary behavior
boundary = openmc.ZPlane(100, boundary_type='vacuum')
# Wrong: Overlapping regions (OpenMC will detect this)
cell1_region = -cylinder
cell2_region = -cylinder # Same region used twice!
# Correct: Non-overlapping regions
cell1_region = -inner_cylinder
cell2_region = +inner_cylinder & -outer_cylinderNext Steps
With these geometry fundamentals, you can model most nuclear systems. For repeated structures like fuel assemblies, you'll want to learn about lattices and universes. For complex shapes, explore additional surface types and advanced boolean operations.
The key is starting simple and building complexity gradually. Master these basics first, then tackle more sophisticated geometries as your needs require.