OpenMC Guide
Python API Basics
Getting Started with the API
The API is object-oriented: you create materials, surfaces, and cells as Python objects, then combine them into a complete model.
import openmc
import numpy as np
import matplotlib.pyplot as plt
# Basic workflow: create objects, combine them, run simulation
fuel = openmc.Material(name='UO2')
fuel.set_density('g/cm3', 10.4)
fuel.add_nuclide('U235', 0.04)
fuel.add_nuclide('U238', 0.96)
fuel.add_element('O', 2.0)
# OpenMC objects are Pythonic - they have useful methods
print(f"Fuel density: {fuel.density} g/cm³")
print(f"Fuel contains {len(fuel.nuclides)} nuclides")Tutorial snippet — no separate file in examples repo
Essential Patterns
1. Creating and Organizing Objects
# Use descriptive names for clarity
fuel = openmc.Material(name='UO2 Fuel 4.5%')
clad = openmc.Material(name='Zircaloy-4')
water = openmc.Material(name='Light Water')
# Group related objects into collections
materials = openmc.Materials([fuel, clad, water])Tutorial snippet — no separate file in examples repo
2. Working with Geometry
# Surfaces define boundaries
fuel_outer = openmc.ZCylinder(r=0.4096, name='fuel outer')
clad_outer = openmc.ZCylinder(r=0.4750, name='clad outer')
# Regions use boolean operations (& = and, | = or, ~ = not)
fuel_region = -fuel_outer
clad_region = +fuel_outer & -clad_outer
water_region = +clad_outer
# Cells fill regions with materials
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)Tutorial snippet — no separate file in examples repo
3. Building Complete Models
# Combine everything into a model
universe = openmc.Universe(cells=[fuel_cell, clad_cell, water_cell])
geometry = openmc.Geometry(universe)
settings = openmc.Settings()
settings.particles = 10000
settings.batches = 100
# The Model class ties everything together
model = openmc.Model(geometry, materials, settings)
# Run and get results (model.run() returns statepoint path)
sp = openmc.StatePoint(model.run())
keff = sp.keff
print(f"k-effective: {keff.nominal_value:.5f} ± {keff.std_dev:.5f}")Tutorial snippet — no separate file in examples repo
Common Mistakes to Avoid
Missing Material Properties
# Wrong - density is missing, so export_to_xml() will fail
fuel = openmc.Material()
fuel.add_nuclide('U235', 0.04)
fuel.add_nuclide('U238', 0.96)
# fuel.export_to_xml() # Error: density not set
# Correct - density must be set before exporting the model
fuel = openmc.Material()
fuel.add_nuclide('U235', 0.04)
fuel.add_nuclide('U238', 0.96)
fuel.set_density('g/cm3', 10.4) # Order of Python calls doesn't matter
# fuel.export_to_xml() # Now this worksTutorial snippet — no separate file in examples repo
Ambiguous Geometry
# Wrong - this is a Python syntax error, not a valid region
cell_region = +surf1 +surf2 # Python cannot combine half-spaces this way
# Correct - use explicit boolean operators
cell_region = +surf1 & +surf2 # Intersection (inside both)
# or
cell_region = +surf1 | +surf2 # Union (inside either)
# or
cell_region = +surf1 & ~surf2 # Inside surf1 but outside surf2Tutorial snippet — no separate file in examples repo
Forgetting Collections
# Wrong - individual exports are error-prone
materials.export_to_xml()
geometry.export_to_xml()
settings.export_to_xml()
tallies.export_to_xml()
# Better - use Model to handle everything
model = openmc.Model(geometry, materials, settings, tallies)
model.export_to_xml()Tutorial snippet — no separate file in examples repo
Practical Example: Parameter Study
This example studies the effect of fuel enrichment on reactivity by parameterizing a pin cell model:
import openmc
import numpy as np
import matplotlib.pyplot as plt
def create_pin_model(enrichment):
"""Create a pin cell model with specified enrichment."""
# Materials
fuel = openmc.Material()
fuel.set_density('g/cm3', 10.4)
fuel.add_nuclide('U235', enrichment)
fuel.add_nuclide('U238', 1.0 - enrichment)
fuel.add_element('O', 2.0)
water = openmc.Material()
water.set_density('g/cm3', 1.0)
water.add_nuclide('H1', 2.0)
water.add_element('O', 1.0)
water.add_s_alpha_beta('c_H_in_H2O')
# Simple infinite lattice geometry
fuel_boundary = openmc.ZCylinder(r=0.4)
pin_cell = openmc.Cell(fill=fuel, region=-fuel_boundary)
water_cell = openmc.Cell(fill=water, region=+fuel_boundary)
# Settings for k-eigenvalue calculation
settings = openmc.Settings()
settings.particles = 5000
settings.batches = 50
settings.inactive = 10
universe = openmc.Universe(cells=[pin_cell, water_cell])
return openmc.Model(
geometry=openmc.Geometry(universe),
materials=openmc.Materials([fuel, water]),
settings=settings
)
# Run parameter study
enrichments = np.linspace(0.02, 0.06, 5)
k_values = []
for enr in enrichments:
model = create_pin_model(enr)
sp = openmc.StatePoint(model.run())
keff = sp.keff
k_values.append(keff.nominal_value)
print(f"Enrichment {enr:.1%}: k = {k_values[-1]:.4f}")
# Plot results
plt.figure(figsize=(8, 6))
plt.plot(enrichments * 100, k_values, 'o-', linewidth=2, markersize=8)
plt.xlabel('Enrichment (%)')
plt.ylabel('k-effective')
plt.title('Reactivity vs. Fuel Enrichment')
plt.grid(True, alpha=0.3)
plt.show()Tutorial snippet — no separate file in examples repo
Why this works: With traditional input files, this would require dozens of separate files and manual result extraction. The Python API handles parameterization, execution, and post-processing in a single script.
Integration with Scientific Python
OpenMC integrates directly with NumPy, Matplotlib, Pandas, SciPy, scikit-learn, and other scientific Python libraries. This makes sophisticated analysis workflows — optimization, machine learning, uncertainty quantification — straightforward to build.